Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2111