Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2537