Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 881