Chameleon

Chameleon Svn Source Tree

Root/branches/mozodojo/i386/boot2/picopng.c

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

Archive Download this file

Revision: 755