Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/boot2/picopng.c

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

Archive Download this file

Revision: 2385