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