Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2469