Chameleon

Chameleon Svn Source Tree

Root/tags/2.0/i386/boot2/picopng.c

Source at commit 1808 created 12 years 3 months ago.
By blackosx, Revise layout of package installer 'Welcome' file so it looks cleaner. Change the copyright notice to begin from 2009 as seen in the Chameleon 2.0 r431 installer. Should this date be set earlier?
1// picoPNG version 20080503 (cleaned up and ported to c by kaitek)
2// Copyright (c) 2005-2008 Lode Vandevenne
3//
4// This software is provided 'as-is', without any express or implied
5// warranty. In no event will the authors be held liable for any damages
6// arising from the use of this software.
7//
8// Permission is granted to anyone to use this software for any purpose,
9// including commercial applications, and to alter it and redistribute it
10// freely, subject to the following restrictions:
11//
12// 1. The origin of this software must not be misrepresented; you must not
13// claim that you wrote the original software. If you use this software
14// in a product, an acknowledgment in the product documentation would be
15// appreciated but is not required.
16// 2. Altered source versions must be plainly marked as such, and must not be
17// misrepresented as being the original software.
18// 3. This notice may not be removed or altered from any source distribution.
19
20#include <sys/types.h>
21#include "libsa.h"
22#include "picopng.h"
23
24/*************************************************************************************************/
25
26typedef struct png_alloc_node {
27struct png_alloc_node *prev, *next;
28void *addr;
29size_t size;
30} png_alloc_node_t;
31
32png_alloc_node_t *png_alloc_head = NULL;
33png_alloc_node_t *png_alloc_tail = NULL;
34
35png_alloc_node_t *png_alloc_find_node(void *addr)
36{
37png_alloc_node_t *node;
38for (node = png_alloc_head; node; node = node->next)
39if (node->addr == addr)
40break;
41return node;
42}
43
44void png_alloc_add_node(void *addr, size_t size)
45{
46png_alloc_node_t *node;
47if (png_alloc_find_node(addr))
48return;
49node = malloc(sizeof (png_alloc_node_t));
50node->addr = addr;
51node->size = size;
52node->prev = png_alloc_tail;
53node->next = NULL;
54png_alloc_tail = node;
55if (node->prev)
56node->prev->next = node;
57if (!png_alloc_head)
58png_alloc_head = node;
59}
60
61void png_alloc_remove_node(png_alloc_node_t *node)
62{
63if (node->prev)
64node->prev->next = node->next;
65if (node->next)
66node->next->prev = node->prev;
67if (node == png_alloc_head)
68png_alloc_head = node->next;
69if (node == png_alloc_tail)
70png_alloc_tail = node->prev;
71node->prev = node->next = node->addr = NULL;
72free(node);
73}
74
75void *png_alloc_malloc(size_t size)
76{
77void *addr = malloc(size);
78png_alloc_add_node(addr, size);
79return addr;
80}
81
82void *png_alloc_realloc(void *addr, size_t size)
83{
84void *new_addr;
85if (!addr)
86return png_alloc_malloc(size);
87new_addr = realloc(addr, size);
88if (new_addr != addr) {
89png_alloc_node_t *old_node;
90old_node = png_alloc_find_node(addr);
91png_alloc_remove_node(old_node);
92png_alloc_add_node(new_addr, size);
93}
94return new_addr;
95}
96
97void png_alloc_free(void *addr)
98{
99png_alloc_node_t *node = png_alloc_find_node(addr);
100if (!node)
101return;
102png_alloc_remove_node(node);
103free(addr);
104}
105
106void png_alloc_free_all()
107{
108while (png_alloc_tail) {
109void *addr = png_alloc_tail->addr;
110png_alloc_remove_node(png_alloc_tail);
111free(addr);
112}
113}
114
115/*************************************************************************************************/
116
117__unused void vector32_cleanup(vector32_t *p)
118{
119p->size = p->allocsize = 0;
120if (p->data)
121png_alloc_free(p->data);
122p->data = NULL;
123}
124
125uint32_t vector32_resize(vector32_t *p, size_t size)
126{// returns 1 if success, 0 if failure ==> nothing done
127if (size * sizeof (uint32_t) > p->allocsize) {
128size_t newsize = size * sizeof (uint32_t) * 2;
129void *data = png_alloc_realloc(p->data, newsize);
130if (data) {
131p->allocsize = newsize;
132p->data = (uint32_t *) data;
133p->size = size;
134} else
135return 0;
136} else
137p->size = size;
138return 1;
139}
140
141uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
142{// resize and give all new elements the value
143size_t oldsize = p->size, i;
144if (!vector32_resize(p, size))
145return 0;
146for (i = oldsize; i < size; i++)
147p->data[i] = value;
148return 1;
149}
150
151void vector32_init(vector32_t *p)
152{
153p->data = NULL;
154p->size = p->allocsize = 0;
155}
156
157vector32_t *vector32_new(size_t size, uint32_t value)
158{
159vector32_t *p = png_alloc_malloc(sizeof (vector32_t));
160vector32_init(p);
161if (size && !vector32_resizev(p, size, value))
162return NULL;
163return p;
164}
165
166/*************************************************************************************************/
167
168__unused void vector8_cleanup(vector8_t *p)
169{
170p->size = p->allocsize = 0;
171if (p->data)
172png_alloc_free(p->data);
173p->data = NULL;
174}
175
176uint32_t vector8_resize(vector8_t *p, size_t size)
177{// returns 1 if success, 0 if failure ==> nothing done
178// xxx: the use of sizeof uint32_t here seems like a bug (this descends from the lodepng vector
179// compatibility functions which do the same). without this there is corruption in certain cases,
180// so this was probably done to cover up allocation bug(s) in the original picopng code!
181if (size * sizeof (uint32_t) > p->allocsize) {
182size_t newsize = size * sizeof (uint32_t) * 2;
183void *data = png_alloc_realloc(p->data, newsize);
184if (data) {
185p->allocsize = newsize;
186p->data = (uint8_t *) data;
187p->size = size;
188} else
189return 0; // error: not enough memory
190} else
191p->size = size;
192return 1;
193}
194
195uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
196{// resize and give all new elements the value
197size_t oldsize = p->size, i;
198if (!vector8_resize(p, size))
199return 0;
200for (i = oldsize; i < size; i++)
201p->data[i] = value;
202return 1;
203}
204
205void vector8_init(vector8_t *p)
206{
207p->data = NULL;
208p->size = p->allocsize = 0;
209}
210
211vector8_t *vector8_new(size_t size, uint8_t value)
212{
213vector8_t *p = png_alloc_malloc(sizeof (vector8_t));
214vector8_init(p);
215if (size && !vector8_resizev(p, size, value))
216return NULL;
217return p;
218}
219
220vector8_t *vector8_copy(vector8_t *p)
221{
222vector8_t *q = vector8_new(p->size, 0);
223uint32_t n;
224for (n = 0; n < q->size; n++)
225q->data[n] = p->data[n];
226return q;
227}
228
229/*************************************************************************************************/
230
231const uint32_t LENBASE[29] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
23259, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
233const uint32_t LENEXTRA[29] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
2344, 5, 5, 5, 5, 0 };
235const uint32_t DISTBASE[30] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
236513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
237const uint32_t DISTEXTRA[30] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
23810, 10, 11, 11, 12, 12, 13, 13 };
239// code length code lengths
240const uint32_t CLCL[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
241
242/*************************************************************************************************/
243
244typedef struct {
245// 2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all
246// nodes and leaves of the tree.
247vector32_t *tree2d;
248} HuffmanTree;
249
250HuffmanTree *HuffmanTree_new()
251{
252HuffmanTree *tree = png_alloc_malloc(sizeof (HuffmanTree));
253tree->tree2d = NULL;
254return tree;
255}
256
257int HuffmanTree_makeFromLengths(HuffmanTree *tree, const vector32_t *bitlen, uint32_t maxbitlen)
258{// make tree given the lengths
259uint32_t bits, n, i;
260uint32_t numcodes = (uint32_t) bitlen->size, treepos = 0, nodefilled = 0;
261vector32_t *tree1d, *blcount, *nextcode;
262tree1d = vector32_new(numcodes, 0);
263blcount = vector32_new(maxbitlen + 1, 0);
264nextcode = vector32_new(maxbitlen + 1, 0);
265for (bits = 0; bits < numcodes; bits++)
266blcount->data[bitlen->data[bits]]++; // count number of instances of each code length
267for (bits = 1; bits <= maxbitlen; bits++)
268nextcode->data[bits] = (nextcode->data[bits - 1] + blcount->data[bits - 1]) << 1;
269for (n = 0; n < numcodes; n++)
270if (bitlen->data[n] != 0)
271tree1d->data[n] = nextcode->data[bitlen->data[n]]++; // generate all the codes
272// 0x7fff here means the tree2d isn't filled there yet
273vector32_t *tree2d = vector32_new(numcodes * 2, 0x7fff);
274tree->tree2d = tree2d;
275for (n = 0; n < numcodes; n++) // the codes
276for (i = 0; i < bitlen->data[n]; i++) { // the bits for this code
277uint32_t bit = (tree1d->data[n] >> (bitlen->data[n] - i - 1)) & 1;
278if (treepos > numcodes - 2)
279return 55;
280if (tree2d->data[2 * treepos + bit] == 0x7fff) { // not yet filled in
281if (i + 1 == bitlen->data[n]) { // last bit
282tree2d->data[2 * treepos + bit] = n;
283treepos = 0;
284} else { // addresses are encoded as values > numcodes
285tree2d->data[2 * treepos + bit] = ++nodefilled + numcodes;
286treepos = nodefilled;
287}
288} else // subtract numcodes from address to get address value
289treepos = tree2d->data[2 * treepos + bit] - numcodes;
290}
291return 0;
292}
293
294int HuffmanTree_decode(const HuffmanTree *tree, bool *decoded, uint32_t *result, size_t *treepos,
295uint32_t bit)
296{// Decodes a symbol from the tree
297const vector32_t *tree2d = tree->tree2d;
298uint32_t numcodes = (uint32_t) tree2d->size / 2;
299if (*treepos >= numcodes)
300return 11; // error: you appeared outside the codetree
301*result = tree2d->data[2 * (*treepos) + bit];
302*decoded = (*result < numcodes);
303*treepos = *decoded ? 0 : *result - numcodes;
304return 0;
305}
306
307/*************************************************************************************************/
308
309int Inflator_error;
310
311uint32_t Zlib_readBitFromStream(size_t *bitp, const uint8_t *bits)
312{
313uint32_t result = (bits[*bitp >> 3] >> (*bitp & 0x7)) & 1;
314(*bitp)++;
315return result;
316}
317
318uint32_t Zlib_readBitsFromStream(size_t *bitp, const uint8_t *bits, size_t nbits)
319{
320uint32_t i, result = 0;
321for (i = 0; i < nbits; i++)
322result += (Zlib_readBitFromStream(bitp, bits)) << i;
323return result;
324}
325
326void Inflator_generateFixedTrees(HuffmanTree *tree, HuffmanTree *treeD)
327{// get the tree of a deflated block with fixed tree
328size_t i;
329vector32_t *bitlen, *bitlenD;
330bitlen = vector32_new(288, 8);
331bitlenD = vector32_new(32, 5);
332for (i = 144; i <= 255; i++)
333bitlen->data[i] = 9;
334for (i = 256; i <= 279; i++)
335bitlen->data[i] = 7;
336HuffmanTree_makeFromLengths(tree, bitlen, 15);
337HuffmanTree_makeFromLengths(treeD, bitlenD, 15);
338}
339
340uint32_t Inflator_huffmanDecodeSymbol(const uint8_t *in, size_t *bp, const HuffmanTree *codetree,
341size_t inlength)
342{// decode a single symbol from given list of bits with given code tree. returns the symbol
343bool decoded = false;
344uint32_t ct = 0;
345size_t treepos = 0;
346for (;;) {
347if ((*bp & 0x07) == 0 && (*bp >> 3) > inlength) {
348Inflator_error = 10; // error: end reached without endcode
349return 0;
350}
351Inflator_error = HuffmanTree_decode(codetree, &decoded, &ct, &treepos,
352Zlib_readBitFromStream(bp, in));
353if (Inflator_error)
354return 0; // stop, an error happened
355if (decoded)
356return ct;
357}
358}
359
360void Inflator_getTreeInflateDynamic(HuffmanTree *tree, HuffmanTree *treeD, const uint8_t *in,
361size_t *bp, size_t inlength)
362{// get the tree of a deflated block with dynamic tree, the tree itself is also Huffman
363// compressed with a known tree
364size_t i, n;
365HuffmanTree *codelengthcodetree = HuffmanTree_new(); // the code tree for code length codes
366vector32_t *bitlen, *bitlenD;
367bitlen = vector32_new(288, 0);
368bitlenD = vector32_new(32, 0);
369if (*bp >> 3 >= inlength - 2) {
370Inflator_error = 49; // the bit pointer is or will go past the memory
371return;
372}
373size_t HLIT = Zlib_readBitsFromStream(bp, in, 5) + 257;// number of literal/length codes + 257
374size_t HDIST = Zlib_readBitsFromStream(bp, in, 5) + 1;// number of dist codes + 1
375size_t HCLEN = Zlib_readBitsFromStream(bp, in, 4) + 4;// number of code length codes + 4
376vector32_t *codelengthcode; // lengths of tree to decode the lengths of the dynamic tree
377codelengthcode = vector32_new(19, 0);
378for (i = 0; i < 19; i++)
379codelengthcode->data[CLCL[i]] = (i < HCLEN) ? Zlib_readBitsFromStream(bp, in, 3) : 0;
380Inflator_error = HuffmanTree_makeFromLengths(codelengthcodetree, codelengthcode, 7);
381if (Inflator_error)
382return;
383size_t replength;
384for (i = 0; i < HLIT + HDIST; ) {
385uint32_t code = Inflator_huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength);
386if (Inflator_error)
387return;
388if (code <= 15) { // a length code
389if (i < HLIT)
390bitlen->data[i++] = code;
391else
392bitlenD->data[i++ - HLIT] = code;
393} else if (code == 16) { // repeat previous
394if (*bp >> 3 >= inlength) {
395Inflator_error = 50; // error, bit pointer jumps past memory
396return;
397}
398replength = 3 + Zlib_readBitsFromStream(bp, in, 2);
399uint32_t value; // set value to the previous code
400if ((i - 1) < HLIT)
401value = bitlen->data[i - 1];
402else
403value = bitlenD->data[i - HLIT - 1];
404for (n = 0; n < replength; n++) { // repeat this value in the next lengths
405if (i >= HLIT + HDIST) {
406Inflator_error = 13; // error: i is larger than the amount of codes
407return;
408}
409if (i < HLIT)
410bitlen->data[i++] = value;
411else
412bitlenD->data[i++ - HLIT] = value;
413}
414} else if (code == 17) { // repeat "0" 3-10 times
415if (*bp >> 3 >= inlength) {
416Inflator_error = 50; // error, bit pointer jumps past memory
417return;
418}
419replength = 3 + Zlib_readBitsFromStream(bp, in, 3);
420for (n = 0; n < replength; n++) { // repeat this value in the next lengths
421if (i >= HLIT + HDIST) {
422Inflator_error = 14; // error: i is larger than the amount of codes
423return;
424}
425if (i < HLIT)
426bitlen->data[i++] = 0;
427else
428bitlenD->data[i++ - HLIT] = 0;
429}
430} else if (code == 18) { // repeat "0" 11-138 times
431if (*bp >> 3 >= inlength) {
432Inflator_error = 50; // error, bit pointer jumps past memory
433return;
434}
435replength = 11 + Zlib_readBitsFromStream(bp, in, 7);
436for (n = 0; n < replength; n++) { // repeat this value in the next lengths
437if (i >= HLIT + HDIST) {
438Inflator_error = 15; // error: i is larger than the amount of codes
439return;
440}
441if (i < HLIT)
442bitlen->data[i++] = 0;
443else
444bitlenD->data[i++ - HLIT] = 0;
445}
446} else {
447Inflator_error = 16; // error: an nonexitent code appeared. This can never happen.
448return;
449}
450}
451if (bitlen->data[256] == 0) {
452Inflator_error = 64; // the length of the end code 256 must be larger than 0
453return;
454}
455// now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
456Inflator_error = HuffmanTree_makeFromLengths(tree, bitlen, 15);
457if (Inflator_error)
458return;
459Inflator_error = HuffmanTree_makeFromLengths(treeD, bitlenD, 15);
460if (Inflator_error)
461return;
462}
463
464void Inflator_inflateHuffmanBlock(vector8_t *out, const uint8_t *in, size_t *bp, size_t *pos,
465size_t inlength, uint32_t btype)
466{
467HuffmanTree *codetree, *codetreeD; // the code tree for Huffman codes, dist codes
468codetree = HuffmanTree_new();
469codetreeD = HuffmanTree_new();
470if (btype == 1)
471Inflator_generateFixedTrees(codetree, codetreeD);
472else if (btype == 2) {
473Inflator_getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength);
474if (Inflator_error)
475return;
476}
477for (;;) {
478uint32_t code = Inflator_huffmanDecodeSymbol(in, bp, codetree, inlength);
479if (Inflator_error)
480return;
481if (code == 256) // end code
482return;
483else if (code <= 255) { // literal symbol
484if (*pos >= out->size)
485vector8_resize(out, (*pos + 1) * 2); // reserve more room
486out->data[(*pos)++] = (uint8_t) code;
487} else if (code >= 257 && code <= 285) { // length code
488size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
489if ((*bp >> 3) >= inlength) {
490Inflator_error = 51; // error, bit pointer will jump past memory
491return;
492}
493length += Zlib_readBitsFromStream(bp, in, numextrabits);
494uint32_t codeD = Inflator_huffmanDecodeSymbol(in, bp, codetreeD, inlength);
495if (Inflator_error)
496return;
497if (codeD > 29) {
498Inflator_error = 18; // error: invalid dist code (30-31 are never used)
499return;
500}
501uint32_t dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
502if ((*bp >> 3) >= inlength) {
503Inflator_error = 51; // error, bit pointer will jump past memory
504return;
505}
506dist += Zlib_readBitsFromStream(bp, in, numextrabitsD);
507size_t start = *pos, back = start - dist; // backwards
508if (*pos + length >= out->size)
509vector8_resize(out, (*pos + length) * 2); // reserve more room
510size_t i;
511for (i = 0; i < length; i++) {
512out->data[(*pos)++] = out->data[back++];
513if (back >= start)
514back = start - dist;
515}
516}
517}
518}
519
520void Inflator_inflateNoCompression(vector8_t *out, const uint8_t *in, size_t *bp, size_t *pos,
521size_t inlength)
522{
523while ((*bp & 0x7) != 0)
524(*bp)++; // go to first boundary of byte
525size_t p = *bp / 8;
526if (p >= inlength - 4) {
527Inflator_error = 52; // error, bit pointer will jump past memory
528return;
529}
530uint32_t LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3];
531p += 4;
532if (LEN + NLEN != 65535) {
533Inflator_error = 21; // error: NLEN is not one's complement of LEN
534return;
535}
536if (*pos + LEN >= out->size)
537vector8_resize(out, *pos + LEN);
538if (p + LEN > inlength) {
539Inflator_error = 23; // error: reading outside of in buffer
540return;
541}
542uint32_t n;
543for (n = 0; n < LEN; n++)
544out->data[(*pos)++] = in[p++]; // read LEN bytes of literal data
545*bp = p * 8;
546}
547
548void Inflator_inflate(vector8_t *out, const vector8_t *in, size_t inpos)
549{
550size_t bp = 0, pos = 0; // bit pointer and byte pointer
551Inflator_error = 0;
552uint32_t BFINAL = 0;
553while (!BFINAL && !Inflator_error) {
554if (bp >> 3 >= in->size) {
555Inflator_error = 52; // error, bit pointer will jump past memory
556return;
557}
558BFINAL = Zlib_readBitFromStream(&bp, &in->data[inpos]);
559uint32_t BTYPE = Zlib_readBitFromStream(&bp, &in->data[inpos]);
560BTYPE += 2 * Zlib_readBitFromStream(&bp, &in->data[inpos]);
561if (BTYPE == 3) {
562Inflator_error = 20; // error: invalid BTYPE
563return;
564}
565else if (BTYPE == 0)
566Inflator_inflateNoCompression(out, &in->data[inpos], &bp, &pos, in->size);
567else
568Inflator_inflateHuffmanBlock(out, &in->data[inpos], &bp, &pos, in->size, BTYPE);
569}
570if (!Inflator_error)
571vector8_resize(out, pos); // Only now we know the true size of out, resize it to that
572}
573
574/*************************************************************************************************/
575
576int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
577{
578if (in->size < 2)
579return 53; // error, size of zlib data too small
580if ((in->data[0] * 256 + in->data[1]) % 31 != 0)
581// error: 256 * in->data[0] + in->data[1] must be a multiple of 31, the FCHECK value is
582// supposed to be made that way
583return 24;
584uint32_t CM = in->data[0] & 15, CINFO = (in->data[0] >> 4) & 15, FDICT = (in->data[1] >> 5) & 1;
585if (CM != 8 || CINFO > 7)
586// error: only compression method 8: inflate with sliding window of 32k is supported by
587// the PNG spec
588return 25;
589if (FDICT != 0)
590// error: the specification of PNG says about the zlib stream: "The additional flags shall
591// not specify a preset dictionary."
592return 26;
593Inflator_inflate(out, in, 2);
594return Inflator_error; // note: adler32 checksum was skipped and ignored
595}
596
597/*************************************************************************************************/
598
599#define PNG_SIGNATURE0x0a1a0a0d474e5089ull
600
601#define CHUNK_IHDR0x52444849
602#define CHUNK_IDAT0x54414449
603#define CHUNK_IEND0x444e4549
604#define CHUNK_PLTE0x45544c50
605#define CHUNK_tRNS0x534e5274
606
607int PNG_error;
608
609uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
610{
611uint32_t result = (bits[*bitp >> 3] >> (7 - (*bitp & 0x7))) & 1;
612(*bitp)++;
613return result;
614}
615
616uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
617{
618uint32_t i, result = 0;
619for (i = nbits - 1; i < nbits; i--)
620result += ((PNG_readBitFromReversedStream(bitp, bits)) << i);
621return result;
622}
623
624void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
625{
626bits[*bitp >> 3] |= (bit << (7 - (*bitp & 0x7)));
627(*bitp)++;
628}
629
630uint32_t PNG_read32bitInt(const uint8_t *buffer)
631{
632return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
633}
634
635int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
636{
637if ((colorType == 2 || colorType == 4 || colorType == 6)) {
638if (!(bd == 8 || bd == 16))
639return 37;
640else
641return 0;
642} else if (colorType == 0) {
643if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16))
644return 37;
645else
646return 0;
647} else if (colorType == 3) {
648if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8))
649return 37;
650else
651return 0;
652} else
653return 31; // nonexistent color type
654}
655
656uint32_t PNG_getBpp(const PNG_info_t *info)
657{
658uint32_t bitDepth, colorType;
659bitDepth = info->bitDepth;
660colorType = info->colorType;
661if (colorType == 2)
662return (3 * bitDepth);
663else if (colorType >= 4)
664return (colorType - 2) * bitDepth;
665else
666return bitDepth;
667}
668
669void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
670{// read the information from the header and store it in the Info
671if (inlength < 29) {
672PNG_error = 27; // error: the data length is smaller than the length of the header
673return;
674}
675if (*(uint64_t *) in != PNG_SIGNATURE) {
676PNG_error = 28; // no PNG signature
677return;
678}
679if (*(uint32_t *) &in[12] != CHUNK_IHDR) {
680PNG_error = 29; // error: it doesn't start with a IHDR chunk!
681return;
682}
683info->width = PNG_read32bitInt(&in[16]);
684info->height = PNG_read32bitInt(&in[20]);
685info->bitDepth = in[24];
686info->colorType = in[25];
687info->compressionMethod = in[26];
688if (in[26] != 0) {
689PNG_error = 32; // error: only compression method 0 is allowed in the specification
690return;
691}
692info->filterMethod = in[27];
693if (in[27] != 0) {
694PNG_error = 33; // error: only filter method 0 is allowed in the specification
695return;
696}
697info->interlaceMethod = in[28];
698if (in[28] > 1) {
699PNG_error = 34; // error: only interlace methods 0 and 1 exist in the specification
700return;
701}
702PNG_error = PNG_checkColorValidity(info->colorType, info->bitDepth);
703}
704
705int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
706{
707int p, pa, pb, pc;
708p = a + b - c;
709pa = p > a ? (p - a) : (a - p);
710pb = p > b ? (p - b) : (b - p);
711pc = p > c ? (p - c) : (c - p);
712return (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
713}
714
715void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
716size_t bytewidth, uint32_t filterType, size_t length)
717{
718size_t i;
719switch (filterType) {
720case 0:
721for (i = 0; i < length; i++)
722recon[i] = scanline[i];
723break;
724case 1:
725for (i = 0; i < bytewidth; i++)
726recon[i] = scanline[i];
727for (i = bytewidth; i < length; i++)
728recon[i] = scanline[i] + recon[i - bytewidth];
729break;
730case 2:
731if (precon)
732for (i = 0; i < length; i++)
733recon[i] = scanline[i] + precon[i];
734else
735for (i = 0; i < length; i++)
736recon[i] = scanline[i];
737break;
738case 3:
739if (precon) {
740for (i = 0; i < bytewidth; i++)
741recon[i] = scanline[i] + precon[i] / 2;
742for (i = bytewidth; i < length; i++)
743recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
744} else {
745for (i = 0; i < bytewidth; i++)
746recon[i] = scanline[i];
747for (i = bytewidth; i < length; i++)
748recon[i] = scanline[i] + recon[i - bytewidth] / 2;
749}
750break;
751case 4:
752if (precon) {
753for (i = 0; i < bytewidth; i++)
754recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(0, precon[i], 0));
755for (i = bytewidth; i < length; i++)
756recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth],
757precon[i], precon[i - bytewidth]));
758} else {
759for (i = 0; i < bytewidth; i++)
760recon[i] = scanline[i];
761for (i = bytewidth; i < length; i++)
762recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth], 0, 0));
763}
764break;
765default:
766PNG_error = 36; // error: nonexistent filter type given
767return;
768}
769}
770
771void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
772size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh,
773uint32_t bpp)
774{// filter and reposition the pixels into the output when the image is Adam7 interlaced. This
775// function can only do it after the full image is already decoded. The out buffer must have
776// the correct allocated memory size already.
777if (passw == 0)
778return;
779size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8);
780uint32_t y;
781for (y = 0; y < passh; y++) {
782size_t i, b;
783uint8_t filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
784PNG_unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType,
785(w * bpp + 7) / 8);
786if (PNG_error)
787return;
788if (bpp >= 8)
789for (i = 0; i < passw; i++)
790for (b = 0; b < bytewidth; b++) // b = current byte of this pixel
791out[bytewidth * w * (passtop + spacey * y) + bytewidth *
792(passleft + spacex * i) + b] = linen[bytewidth * i + b];
793else
794for (i = 0; i < passw; i++) {
795size_t obp, bp;
796obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i);
797bp = i * bpp;
798for (b = 0; b < bpp; b++)
799PNG_setBitOfReversedStream(&obp, out, PNG_readBitFromReversedStream(&bp, linen));
800}
801uint8_t *temp = linen;
802linen = lineo;
803lineo = temp; // swap the two buffer pointers "line old" and "line new"
804}
805}
806
807int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
808{// converts from any color type to 32-bit. return value = LodePNG error code
809size_t i, c;
810uint32_t bitDepth, colorType;
811bitDepth = info->bitDepth;
812colorType = info->colorType;
813size_t numpixels = info->width * info->height, bp = 0;
814vector8_resize(out, numpixels * 4);
815uint8_t *out_data = out->size ? out->data : 0;
816if (bitDepth == 8 && colorType == 0) // greyscale
817for (i = 0; i < numpixels; i++) {
818out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[i];
819out_data[4 * i + 3] = (info->key_defined && (in[i] == info->key_r)) ? 0 : 255;
820}
821else if (bitDepth == 8 && colorType == 2) // RGB color
822for (i = 0; i < numpixels; i++) {
823for (c = 0; c < 3; c++)
824out_data[4 * i + c] = in[3 * i + c];
825out_data[4 * i + 3] = (info->key_defined && (in[3 * i + 0] == info->key_r) &&
826(in[3 * i + 1] == info->key_g) && (in[3 * i + 2] == info->key_b)) ? 0 : 255;
827}
828else if (bitDepth == 8 && colorType == 3) // indexed color (palette)
829for (i = 0; i < numpixels; i++) {
830if (4U * in[i] >= info->palette->size)
831return 46;
832for (c = 0; c < 4; c++) // get rgb colors from the palette
833out_data[4 * i + c] = info->palette->data[4 * in[i] + c];
834}
835else if (bitDepth == 8 && colorType == 4) // greyscale with alpha
836for (i = 0; i < numpixels; i++) {
837out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i + 0];
838out_data[4 * i + 3] = in[2 * i + 1];
839}
840else if (bitDepth == 8 && colorType == 6)
841for (i = 0; i < numpixels; i++)
842for (c = 0; c < 4; c++)
843out_data[4 * i + c] = in[4 * i + c]; // RGB with alpha
844else if (bitDepth == 16 && colorType == 0) // greyscale
845for (i = 0; i < numpixels; i++) {
846out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i];
847out_data[4 * i + 3] = (info->key_defined && (256U * in[i] + in[i + 1] == info->key_r))
848? 0 : 255;
849}
850else if (bitDepth == 16 && colorType == 2) // RGB color
851for (i = 0; i < numpixels; i++) {
852for (c = 0; c < 3; c++)
853out_data[4 * i + c] = in[6 * i + 2 * c];
854out_data[4 * i + 3] = (info->key_defined &&
855(256U * in[6 * i + 0] + in[6 * i + 1] == info->key_r) &&
856(256U * in[6 * i + 2] + in[6 * i + 3] == info->key_g) &&
857(256U * in[6 * i + 4] + in[6 * i + 5] == info->key_b)) ? 0 : 255;
858}
859else if (bitDepth == 16 && colorType == 4) // greyscale with alpha
860for (i = 0; i < numpixels; i++) {
861out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[4 * i]; // msb
862out_data[4 * i + 3] = in[4 * i + 2];
863}
864else if (bitDepth == 16 && colorType == 6)
865for (i = 0; i < numpixels; i++)
866for (c = 0; c < 4; c++)
867out_data[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha
868else if (bitDepth < 8 && colorType == 0) // greyscale
869for (i = 0; i < numpixels; i++) {
870uint32_t value = (PNG_readBitsFromReversedStream(&bp, in, bitDepth) * 255) /
871((1 << bitDepth) - 1); // scale value from 0 to 255
872out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = (uint8_t) value;
873out_data[4 * i + 3] = (info->key_defined && value &&
874(((1U << bitDepth) - 1U) == info->key_r) && ((1U << bitDepth) - 1U)) ? 0 : 255;
875}
876else if (bitDepth < 8 && colorType == 3) // palette
877for (i = 0; i < numpixels; i++) {
878uint32_t value = PNG_readBitsFromReversedStream(&bp, in, bitDepth);
879if (4 * value >= info->palette->size)
880return 47;
881for (c = 0; c < 4; c++) // get rgb colors from the palette
882out_data[4 * i + c] = info->palette->data[4 * value + c];
883}
884return 0;
885}
886
887PNG_info_t *PNG_info_new()
888{
889PNG_info_t *info = png_alloc_malloc(sizeof (PNG_info_t));
890uint32_t i;
891for (i = 0; i < sizeof (PNG_info_t); i++)
892((uint8_t *) info)[i] = 0;
893info->palette = vector8_new(0, 0);
894info->image = vector8_new(0, 0);
895return info;
896}
897
898PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size)
899{
900PNG_info_t *info;
901PNG_error = 0;
902if (size == 0 || in == 0) {
903PNG_error = 48; // the given data is empty
904return NULL;
905}
906info = PNG_info_new();
907PNG_readPngHeader(info, in, size);
908if (PNG_error)
909return NULL;
910size_t pos = 33; // first byte of the first chunk after the header
911vector8_t *idat = NULL; // the data from idat chunks
912bool IEND = false, known_type = true;
913info->key_defined = false;
914// loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is
915// put at the start of the in buffer
916while (!IEND) {
917size_t i, j;
918if (pos + 8 >= size) {
919PNG_error = 30; // error: size of the in buffer too small to contain next chunk
920return NULL;
921}
922size_t chunkLength = PNG_read32bitInt(&in[pos]);
923pos += 4;
924if (chunkLength > 0x7fffffff) {
925PNG_error = 63;
926return NULL;
927}
928if (pos + chunkLength >= size) {
929PNG_error = 35; // error: size of the in buffer too small to contain next chunk
930return NULL;
931}
932uint32_t chunkType = *(uint32_t *) &in[pos];
933if (chunkType == CHUNK_IDAT) { // IDAT: compressed image data chunk
934size_t offset = 0;
935if (idat) {
936offset = idat->size;
937vector8_resize(idat, offset + chunkLength);
938} else
939idat = vector8_new(chunkLength, 0);
940for (i = 0; i < chunkLength; i++)
941idat->data[offset + i] = in[pos + 4 + i];
942pos += (4 + chunkLength);
943} else if (chunkType == CHUNK_IEND) { // IEND
944pos += 4;
945IEND = true;
946} else if (chunkType == CHUNK_PLTE) { // PLTE: palette chunk
947pos += 4; // go after the 4 letters
948vector8_resize(info->palette, 4 * (chunkLength / 3));
949if (info->palette->size > (4 * 256)) {
950PNG_error = 38; // error: palette too big
951return NULL;
952}
953for (i = 0; i < info->palette->size; i += 4) {
954for (j = 0; j < 3; j++)
955info->palette->data[i + j] = in[pos++]; // RGB
956info->palette->data[i + 3] = 255; // alpha
957}
958} else if (chunkType == CHUNK_tRNS) { // tRNS: palette transparency chunk
959pos += 4; // go after the 4 letters
960if (info->colorType == 3) {
961if (4 * chunkLength > info->palette->size) {
962PNG_error = 39; // error: more alpha values given than there are palette entries
963return NULL;
964}
965for (i = 0; i < chunkLength; i++)
966info->palette->data[4 * i + 3] = in[pos++];
967} else if (info->colorType == 0) {
968if (chunkLength != 2) {
969PNG_error = 40; // error: this chunk must be 2 bytes for greyscale image
970return NULL;
971}
972info->key_defined = true;
973info->key_r = info->key_g = info->key_b = 256 * in[pos] + in[pos + 1];
974pos += 2;
975} else if (info->colorType == 2) {
976if (chunkLength != 6) {
977PNG_error = 41; // error: this chunk must be 6 bytes for RGB image
978return NULL;
979}
980info->key_defined = true;
981info->key_r = 256 * in[pos] + in[pos + 1];
982pos += 2;
983info->key_g = 256 * in[pos] + in[pos + 1];
984pos += 2;
985info->key_b = 256 * in[pos] + in[pos + 1];
986pos += 2;
987} else {
988PNG_error = 42; // error: tRNS chunk not allowed for other color models
989return NULL;
990}
991} else { // it's not an implemented chunk type, so ignore it: skip over the data
992if (!(in[pos + 0] & 32)) {
993// error: unknown critical chunk (5th bit of first byte of chunk type is 0)
994PNG_error = 69;
995return NULL;
996}
997pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
998known_type = false;
999}
1000pos += 4; // step over CRC (which is ignored)
1001}
1002uint32_t bpp = PNG_getBpp(info);
1003vector8_t *scanlines; // now the out buffer will be filled
1004scanlines = vector8_new(((info->width * (info->height * bpp + 7)) / 8) + info->height, 0);
1005PNG_error = Zlib_decompress(scanlines, idat);
1006if (PNG_error)
1007return NULL; // stop if the zlib decompressor returned an error
1008size_t bytewidth = (bpp + 7) / 8, outlength = (info->height * info->width * bpp + 7) / 8;
1009vector8_resize(info->image, outlength); // time to fill the out buffer
1010uint8_t *out_data = outlength ? info->image->data : 0;
1011if (info->interlaceMethod == 0) { // no interlace, just filter
1012size_t y, obp, bp;
1013size_t linestart, linelength;
1014linestart = 0;
1015// length in bytes of a scanline, excluding the filtertype byte
1016linelength = (info->width * bpp + 7) / 8;
1017if (bpp >= 8) // byte per byte
1018for (y = 0; y < info->height; y++) {
1019uint32_t filterType = scanlines->data[linestart];
1020const uint8_t *prevline;
1021prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
1022PNG_unFilterScanline(&out_data[linestart - y], &scanlines->data[linestart + 1],
1023prevline, bytewidth, filterType, linelength);
1024if (PNG_error)
1025return NULL;
1026linestart += (1 + linelength); // go to start of next scanline
1027} else { // less than 8 bits per pixel, so fill it up bit per bit
1028vector8_t *templine; // only used if bpp < 8
1029templine = vector8_new((info->width * bpp + 7) >> 3, 0);
1030for (y = 0, obp = 0; y < info->height; y++) {
1031uint32_t filterType = scanlines->data[linestart];
1032const uint8_t *prevline;
1033prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
1034PNG_unFilterScanline(templine->data, &scanlines->data[linestart + 1], prevline,
1035bytewidth, filterType, linelength);
1036if (PNG_error)
1037return NULL;
1038for (bp = 0; bp < info->width * bpp;)
1039PNG_setBitOfReversedStream(&obp, out_data, PNG_readBitFromReversedStream(&bp,
1040templine->data));
1041linestart += (1 + linelength); // go to start of next scanline
1042}
1043}
1044} else { // interlaceMethod is 1 (Adam7)
1045int i;
1046size_t passw[7] = {
1047(info->width + 7) / 8, (info->width + 3) / 8, (info->width + 3) / 4,
1048(info->width + 1) / 4, (info->width + 1) / 2, (info->width + 0) / 2,
1049(info->width + 0) / 1
1050};
1051size_t passh[7] = {
1052(info->height + 7) / 8, (info->height + 7) / 8, (info->height + 3) / 8,
1053(info->height + 3) / 4, (info->height + 1) / 4, (info->height + 1) / 2,
1054(info->height + 0) / 2
1055};
1056size_t passstart[7] = { 0 };
1057size_t pattern[28] = { 0, 4, 0, 2, 0, 1, 0, 0, 0, 4, 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, 1, 8, 8,
10588, 4, 4, 2, 2 }; // values for the adam7 passes
1059for (i = 0; i < 6; i++)
1060passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
1061vector8_t *scanlineo, *scanlinen; // "old" and "new" scanline
1062scanlineo = vector8_new((info->width * bpp + 7) / 8, 0);
1063scanlinen = vector8_new((info->width * bpp + 7) / 8, 0);
1064for (i = 0; i < 7; i++)
1065PNG_adam7Pass(out_data, scanlinen->data, scanlineo->data, &scanlines->data[passstart[i]],
1066info->width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21],
1067passw[i], passh[i], bpp);
1068}
1069if (info->colorType != 6 || info->bitDepth != 8) { // conversion needed
1070vector8_t *copy = vector8_copy(info->image); // xxx: is this copy necessary?
1071PNG_error = PNG_convert(info, info->image, copy->data);
1072}
1073return info;
1074}
1075
1076/*************************************************************************************************/
1077
1078#ifdef TEST
1079
1080#include <stdio.h>
1081#include <sys/stat.h>
1082
1083int main(int argc, char **argv)
1084{
1085char *fname = (argc > 1) ? argv[1] : "test.png";
1086PNG_info_t *info;
1087struct stat statbuf;
1088uint32_t insize, outsize;
1089FILE *infp, *outfp;
1090uint8_t *inbuf;
1091uint32_t n;
1092
1093if (stat(fname, &statbuf) != 0) {
1094perror("stat");
1095return 1;
1096} else if (!statbuf.st_size) {
1097printf("file empty\n");
1098return 1;
1099}
1100insize = (uint32_t) statbuf.st_size;
1101inbuf = malloc(insize);
1102infp = fopen(fname, "rb");
1103if (!infp) {
1104perror("fopen");
1105return 1;
1106} else if (fread(inbuf, 1, insize, infp) != insize) {
1107perror("fread");
1108return 1;
1109}
1110fclose(infp);
1111
1112printf("input file: %s (size: %d)\n", fname, insize);
1113
1114info = PNG_decode(inbuf, insize);
1115free(inbuf);
1116printf("PNG_error: %d\n", PNG_error);
1117if (PNG_error != 0)
1118return 1;
1119
1120printf("width: %d, height: %d\nfirst 16 bytes: ", info->width, info->height);
1121for (n = 0; n < 16; n++)
1122printf("%02x ", info->image->data[n]);
1123printf("\n");
1124
1125outsize = info->width * info->height * 4;
1126printf("image size: %d\n", outsize);
1127if (outsize != info->image->size) {
1128printf("error: image size doesn't match dimensions\n");
1129return 1;
1130}
1131outfp = fopen("out.bin", "wb");
1132if (!outfp) {
1133perror("fopen");
1134return 1;
1135} else if (fwrite(info->image->data, 1, outsize, outfp) != outsize) {
1136perror("fwrite");
1137return 1;
1138}
1139fclose(outfp);
1140
1141#ifdef ALLOC_DEBUG
1142png_alloc_node_t *node;
1143for (node = png_alloc_head, n = 1; node; node = node->next, n++)
1144printf("node %d (%p) addr = %p, size = %ld\n", n, node, node->addr, node->size);
1145#endif
1146png_alloc_free_all(); // also frees info and image data from PNG_decode
1147
1148return 0;
1149}
1150
1151#endif
1152

Archive Download this file

Revision: 1808