1 /*
2 LodePNG Utils
3
4 Copyright (c) 2005-2012 Lode Vandevenne
5
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
13
14 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product documentation would be
17 appreciated but is not required.
18
19 2. Altered source versions must be plainly marked as such, and must not be
20 misrepresented as being the original software.
21
22 3. This notice may not be removed or altered from any source
23 distribution.
24 */
25
26 #include "lodepng_util.h"
27 #include <iostream>
28
29 namespace lodepng
30 {
31
getPNGHeaderInfo(const std::vector<unsigned char> & png)32 LodePNGInfo getPNGHeaderInfo(const std::vector<unsigned char>& png)
33 {
34 unsigned w, h;
35 lodepng::State state;
36 lodepng_inspect(&w, &h, &state, &png[0], png.size());
37 return state.info_png;
38 }
39
getChunkInfo(std::vector<std::string> & names,std::vector<size_t> & sizes,const std::vector<unsigned char> & png)40 unsigned getChunkInfo(std::vector<std::string>& names, std::vector<size_t>& sizes,
41 const std::vector<unsigned char>& png)
42 {
43 // Listing chunks is based on the original file, not the decoded png info.
44 const unsigned char *chunk, *begin, *end;
45 end = &png.back() + 1;
46 begin = chunk = &png.front() + 8;
47
48 while(chunk + 8 < end && chunk >= begin)
49 {
50 char type[5];
51 lodepng_chunk_type(type, chunk);
52 if(std::string(type).size() != 4) return 1;
53
54 names.push_back(type);
55 sizes.push_back(lodepng_chunk_length(chunk));
56
57 chunk = lodepng_chunk_next_const(chunk);
58 }
59 return 0;
60 }
61
getChunks(std::vector<std::string> names[3],std::vector<std::vector<unsigned char>> chunks[3],const std::vector<unsigned char> & png)62 unsigned getChunks(std::vector<std::string> names[3],
63 std::vector<std::vector<unsigned char> > chunks[3],
64 const std::vector<unsigned char>& png)
65 {
66 const unsigned char *chunk, *next, *begin, *end;
67 end = &png.back() + 1;
68 begin = chunk = &png.front() + 8;
69
70 int location = 0;
71
72 while(chunk + 8 < end && chunk >= begin)
73 {
74 char type[5];
75 lodepng_chunk_type(type, chunk);
76 std::string name(type);
77 if(name.size() != 4) return 1;
78
79 next = lodepng_chunk_next_const(chunk);
80
81 if(name == "IHDR")
82 {
83 location = 0;
84 }
85 else if(name == "PLTE")
86 {
87 location = 1;
88 }
89 else if(name == "IDAT")
90 {
91 location = 2;
92 }
93 else if(name != "IEND")
94 {
95 names[location].push_back(name);
96 chunks[location].push_back(std::vector<unsigned char>(chunk, next));
97 }
98
99 chunk = next;
100 }
101 return 0;
102 }
103
104
insertChunks(std::vector<unsigned char> & png,const std::vector<std::vector<unsigned char>> chunks[3])105 unsigned insertChunks(std::vector<unsigned char>& png,
106 const std::vector<std::vector<unsigned char> > chunks[3])
107 {
108 const unsigned char *chunk, *next, *begin, *end;
109 end = &png.back() + 1;
110 begin = chunk = &png.front() + 8;
111
112 size_t l0 = 0; //location 0: IHDR-l0-PLTE (or IHDR-l0-l1-IDAT)
113 size_t l1 = 0; //location 1: PLTE-l1-IDAT (or IHDR-l0-l1-IDAT)
114 size_t l2 = 0; //location 2: IDAT-l2-IEND
115
116 while(chunk + 8 < end && chunk >= begin)
117 {
118 char type[5];
119 lodepng_chunk_type(type, chunk);
120 std::string name(type);
121 if(name.size() != 4) return 1;
122
123 next = lodepng_chunk_next_const(chunk);
124
125 if(name == "PLTE")
126 {
127 if(l0 == 0) l0 = chunk - begin + 8;
128 }
129 else if(name == "IDAT")
130 {
131 if(l0 == 0) l0 = chunk - begin + 8;
132 if(l1 == 0) l1 = chunk - begin + 8;
133 }
134 else if(name == "IEND")
135 {
136 if(l2 == 0) l2 = chunk - begin + 8;
137 }
138
139 chunk = next;
140 }
141
142 std::vector<unsigned char> result;
143 result.insert(result.end(), png.begin(), png.begin() + l0);
144 for(size_t i = 0; i < chunks[0].size(); i++) result.insert(result.end(), chunks[0][i].begin(), chunks[0][i].end());
145 result.insert(result.end(), png.begin() + l0, png.begin() + l1);
146 for(size_t i = 0; i < chunks[1].size(); i++) result.insert(result.end(), chunks[1][i].begin(), chunks[1][i].end());
147 result.insert(result.end(), png.begin() + l1, png.begin() + l2);
148 for(size_t i = 0; i < chunks[2].size(); i++) result.insert(result.end(), chunks[2][i].begin(), chunks[2][i].end());
149 result.insert(result.end(), png.begin() + l2, png.end());
150
151 png = result;
152 return 0;
153 }
154
getFilterTypesInterlaced(std::vector<std::vector<unsigned char>> & filterTypes,const std::vector<unsigned char> & png)155 unsigned getFilterTypesInterlaced(std::vector<std::vector<unsigned char> >& filterTypes,
156 const std::vector<unsigned char>& png)
157 {
158 //Get color type and interlace type
159 lodepng::State state;
160 unsigned w, h;
161 unsigned error;
162 error = lodepng_inspect(&w, &h, &state, &png[0], png.size());
163
164 if(error) return 1;
165
166 //Read literal data from all IDAT chunks
167 const unsigned char *chunk, *begin, *end;
168 end = &png.back() + 1;
169 begin = chunk = &png.front() + 8;
170
171 std::vector<unsigned char> zdata;
172
173 while(chunk + 8 < end && chunk >= begin)
174 {
175 char type[5];
176 lodepng_chunk_type(type, chunk);
177 if(std::string(type).size() != 4) return 1; //Probably not a PNG file
178
179 if(std::string(type) == "IDAT")
180 {
181 const unsigned char* cdata = lodepng_chunk_data_const(chunk);
182 unsigned clength = lodepng_chunk_length(chunk);
183
184 for(unsigned i = 0; i < clength; i++)
185 {
186 zdata.push_back(cdata[i]);
187 }
188 }
189
190 chunk = lodepng_chunk_next_const(chunk);
191 }
192
193 //Decompress all IDAT data
194 std::vector<unsigned char> data;
195 error = lodepng::decompress(data, &zdata[0], zdata.size());
196
197 if(error) return 1;
198
199 if(state.info_png.interlace_method == 0)
200 {
201 filterTypes.resize(1);
202
203 //A line is 1 filter byte + all pixels
204 size_t linebytes = 1 + lodepng_get_raw_size(w, 1, &state.info_png.color);
205
206 for(size_t i = 0; i < data.size(); i += linebytes)
207 {
208 filterTypes[0].push_back(data[i]);
209 }
210 }
211 else
212 {
213 //Interlaced
214 filterTypes.resize(7);
215 static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
216 static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
217 static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
218 static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
219 size_t pos = 0;
220 for(int j = 0; j < 7; j++)
221 {
222 unsigned w2 = (w - ADAM7_IX[j] + ADAM7_DX[j] - 1) / ADAM7_DX[j];
223 unsigned h2 = (h - ADAM7_IY[j] + ADAM7_DY[j] - 1) / ADAM7_DY[j];
224 if(ADAM7_IX[j] >= w || ADAM7_IY[j] >= h) w2 = h2 = 0;
225 size_t linebytes = 1 + lodepng_get_raw_size(w2, 1, &state.info_png.color);
226 for(size_t i = 0; i < h2; i++)
227 {
228 filterTypes[j].push_back(data[pos]);
229 pos += linebytes;
230 }
231 }
232 }
233 return 0; /* OK */
234 }
235
236
getFilterTypes(std::vector<unsigned char> & filterTypes,const std::vector<unsigned char> & png)237 unsigned getFilterTypes(std::vector<unsigned char>& filterTypes, const std::vector<unsigned char>& png)
238 {
239 std::vector<std::vector<unsigned char> > passes;
240 unsigned error = getFilterTypesInterlaced(passes, png);
241 if(error) return error;
242
243 if(passes.size() == 1)
244 {
245 filterTypes.swap(passes[0]);
246 }
247 else
248 {
249 lodepng::State state;
250 unsigned w, h;
251 lodepng_inspect(&w, &h, &state, &png[0], png.size());
252 /*
253 Interlaced. Simplify it: put pass 6 and 7 alternating in the one vector so
254 that one filter per scanline of the uninterlaced image is given, with that
255 filter corresponding the closest to what it would be for non-interlaced
256 image.
257 */
258 for(size_t i = 0; i < h; i++)
259 {
260 filterTypes.push_back(i % 2 == 0 ? passes[5][i / 2] : passes[6][i / 2]);
261 }
262 }
263 return 0; /* OK */
264 }
265
getPaletteValue(const unsigned char * data,size_t i,int bits)266 int getPaletteValue(const unsigned char* data, size_t i, int bits)
267 {
268 if(bits == 8) return data[i];
269 else if(bits == 4) return (data[i / 2] >> ((i % 2) * 4)) & 15;
270 else if(bits == 2) return (data[i / 4] >> ((i % 4) * 2)) & 3;
271 else if(bits == 1) return (data[i / 8] >> (i % 8)) & 1;
272 else return 0;
273 }
274
275 //This uses a stripped down version of picoPNG to extract detailed zlib information while decompressing.
276 static const unsigned long LENBASE[29] =
277 {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258};
278 static const unsigned long LENEXTRA[29] =
279 {0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
280 static const unsigned long DISTBASE[30] =
281 {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
282 static const unsigned long DISTEXTRA[30] =
283 {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
284 static const unsigned long CLCL[19] =
285 {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; //code length code lengths
286
287 struct ExtractZlib // Zlib decompression and information extraction
288 {
289 std::vector<ZlibBlockInfo>* zlibinfo;
290 int error;
291
ExtractZliblodepng::ExtractZlib292 ExtractZlib(std::vector<ZlibBlockInfo>* output) : zlibinfo(output) {};
293
readBitFromStreamlodepng::ExtractZlib294 unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits)
295 {
296 unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1;
297 bitp++;
298 return result;
299 }
300
readBitsFromStreamlodepng::ExtractZlib301 unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits)
302 {
303 unsigned long result = 0;
304 for(size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i;
305 return result;
306 }
307
308 struct HuffmanTree
309 {
makeFromLengthslodepng::ExtractZlib::HuffmanTree310 int makeFromLengths(const std::vector<unsigned long>& bitlen, unsigned long maxbitlen)
311 { //make tree given the lengths
312 unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0;
313 std::vector<unsigned long> tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0);
314 //count number of instances of each code length
315 for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++;
316 for(unsigned long bits = 1; bits <= maxbitlen; bits++)
317 {
318 nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1;
319 }
320 //generate all the codes
321 for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++;
322 tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet
323 for(unsigned long n = 0; n < numcodes; n++) //the codes
324 for(unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code
325 {
326 unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1;
327 if(treepos > numcodes - 2) return 55;
328 if(tree2d[2 * treepos + bit] == 32767) //not yet filled in
329 {
330 if(i + 1 == bitlen[n])
331 {
332 //last bit
333 tree2d[2 * treepos + bit] = n;
334 treepos = 0;
335 }
336 else
337 {
338 //addresses are encoded as values > numcodes
339 tree2d[2 * treepos + bit] = ++nodefilled + numcodes;
340 treepos = nodefilled;
341 }
342 }
343 else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value
344 }
345 return 0;
346 }
decodelodepng::ExtractZlib::HuffmanTree347 int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const
348 { //Decodes a symbol from the tree
349 unsigned long numcodes = (unsigned long)tree2d.size() / 2;
350 if(treepos >= numcodes) return 11; //error: you appeared outside the codetree
351 result = tree2d[2 * treepos + bit];
352 decoded = (result < numcodes);
353 treepos = decoded ? 0 : result - numcodes;
354 return 0;
355 }
356 //2D representation of a huffman tree: one dimension is "0" or "1", the other contains all nodes and leaves.
357 std::vector<unsigned long> tree2d;
358 };
359
inflatelodepng::ExtractZlib360 void inflate(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, size_t inpos = 0)
361 {
362 size_t bp = 0, pos = 0; //bit pointer and byte pointer
363 error = 0;
364 unsigned long BFINAL = 0;
365 while(!BFINAL && !error)
366 {
367 size_t uncomprblockstart = pos;
368 size_t bpstart = bp;
369 if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory
370 BFINAL = readBitFromStream(bp, &in[inpos]);
371 unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]);
372 zlibinfo->resize(zlibinfo->size() + 1);
373 zlibinfo->back().btype = BTYPE;
374 if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE
375 else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size());
376 else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE);
377 size_t uncomprblocksize = pos - uncomprblockstart;
378 zlibinfo->back().compressedbits = bp - bpstart;
379 zlibinfo->back().uncompressedbytes = uncomprblocksize;
380 }
381 }
382
generateFixedTreeslodepng::ExtractZlib383 void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) //get the tree of a deflated block with fixed tree
384 {
385 std::vector<unsigned long> bitlen(288, 8), bitlenD(32, 5);;
386 for(size_t i = 144; i <= 255; i++) bitlen[i] = 9;
387 for(size_t i = 256; i <= 279; i++) bitlen[i] = 7;
388 tree.makeFromLengths(bitlen, 15);
389 treeD.makeFromLengths(bitlenD, 15);
390 }
391
392 //the code tree for Huffman codes, dist codes, and code length codes
393 HuffmanTree codetree, codetreeD, codelengthcodetree;
huffmanDecodeSymbollodepng::ExtractZlib394 unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength)
395 {
396 //decode a single symbol from given list of bits with given code tree. return value is the symbol
397 bool decoded; unsigned long ct;
398 for(size_t treepos = 0;;)
399 {
400 if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode
401 error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in));
402 if(error) return 0; //stop, an error happened
403 if(decoded) return ct;
404 }
405 }
406
getTreeInflateDynamiclodepng::ExtractZlib407 void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD,
408 const unsigned char* in, size_t& bp, size_t inlength)
409 {
410 size_t bpstart = bp;
411 //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree
412 std::vector<unsigned long> bitlen(288, 0), bitlenD(32, 0);
413 if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory
414 size_t HLIT = readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257
415 size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1
416 size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4
417 zlibinfo->back().hlit = HLIT - 257;
418 zlibinfo->back().hdist = HDIST - 1;
419 zlibinfo->back().hclen = HCLEN - 4;
420 std::vector<unsigned long> codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree
421 for(size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0;
422 //code length code lengths
423 for(size_t i = 0; i < codelengthcode.size(); i++) zlibinfo->back().clcl.push_back(codelengthcode[i]);
424 error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return;
425 size_t i = 0, replength;
426 while(i < HLIT + HDIST)
427 {
428 unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return;
429 zlibinfo->back().treecodes.push_back(code); //tree symbol code
430 if(code <= 15) { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code
431 else if(code == 16) //repeat previous
432 {
433 if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
434 replength = 3 + readBitsFromStream(bp, in, 2);
435 unsigned long value; //set value to the previous code
436 if((i - 1) < HLIT) value = bitlen[i - 1];
437 else value = bitlenD[i - HLIT - 1];
438 for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
439 {
440 if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes
441 if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value;
442 }
443 }
444 else if(code == 17) //repeat "0" 3-10 times
445 {
446 if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
447 replength = 3 + readBitsFromStream(bp, in, 3);
448 zlibinfo->back().treecodes.push_back(replength); //tree symbol code repetitions
449 for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
450 {
451 if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes
452 if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
453 }
454 }
455 else if(code == 18) //repeat "0" 11-138 times
456 {
457 if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
458 replength = 11 + readBitsFromStream(bp, in, 7);
459 zlibinfo->back().treecodes.push_back(replength); //tree symbol code repetitions
460 for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
461 {
462 if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes
463 if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
464 }
465 }
466 else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen.
467 }
468 if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0
469 error = tree.makeFromLengths(bitlen, 15);
470 if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
471 error = treeD.makeFromLengths(bitlenD, 15);
472 if(error) return;
473 zlibinfo->back().treebits = bp - bpstart;
474 //lit/len/end symbol lengths
475 for(size_t i = 0; i < bitlen.size(); i++) zlibinfo->back().litlenlengths.push_back(bitlen[i]);
476 //dist lengths
477 for(size_t i = 0; i < bitlenD.size(); i++) zlibinfo->back().distlengths.push_back(bitlenD[i]);
478 }
479
inflateHuffmanBlocklodepng::ExtractZlib480 void inflateHuffmanBlock(std::vector<unsigned char>& out,
481 const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype)
482 {
483 size_t numcodes = 0, numlit = 0, numlen = 0; //for logging
484 if(btype == 1) { generateFixedTrees(codetree, codetreeD); }
485 else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; }
486 for(;;)
487 {
488 unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return;
489 numcodes++;
490 zlibinfo->back().lz77_lcode.push_back(code); //output code
491 zlibinfo->back().lz77_dcode.push_back(0);
492 zlibinfo->back().lz77_lbits.push_back(0);
493 zlibinfo->back().lz77_dbits.push_back(0);
494 zlibinfo->back().lz77_lvalue.push_back(0);
495 zlibinfo->back().lz77_dvalue.push_back(0);
496
497 if(code == 256) break; //end code
498 else if(code <= 255) //literal symbol
499 {
500 out.push_back((unsigned char)(code));
501 pos++;
502 numlit++;
503 }
504 else if(code >= 257 && code <= 285) //length code
505 {
506 size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
507 if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
508 length += readBitsFromStream(bp, in, numextrabits);
509 unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return;
510 if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used)
511 unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
512 if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
513 dist += readBitsFromStream(bp, in, numextrabitsD);
514 size_t start = pos, back = start - dist; //backwards
515 for(size_t i = 0; i < length; i++)
516 {
517 out.push_back(out[back++]);
518 pos++;
519 if(back >= start) back = start - dist;
520 }
521 numlen++;
522 zlibinfo->back().lz77_dcode.back() = codeD; //output distance code
523 zlibinfo->back().lz77_lbits.back() = numextrabits; //output length extra bits
524 zlibinfo->back().lz77_dbits.back() = numextrabitsD; //output dist extra bits
525 zlibinfo->back().lz77_lvalue.back() = length; //output length
526 zlibinfo->back().lz77_dvalue.back() = dist; //output dist
527 }
528 }
529 zlibinfo->back().numlit = numlit; //output number of literal symbols
530 zlibinfo->back().numlen = numlen; //output number of length symbols
531 }
532
inflateNoCompressionlodepng::ExtractZlib533 void inflateNoCompression(std::vector<unsigned char>& out,
534 const unsigned char* in, size_t& bp, size_t& pos, size_t inlength)
535 {
536 while((bp & 0x7) != 0) bp++; //go to first boundary of byte
537 size_t p = bp / 8;
538 if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory
539 unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4;
540 if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN
541 if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer
542 for(unsigned long n = 0; n < LEN; n++)
543 {
544 out.push_back(in[p++]); //read LEN bytes of literal data
545 pos++;
546 }
547 bp = p * 8;
548 }
549
decompresslodepng::ExtractZlib550 int decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in) //returns error value
551 {
552 if(in.size() < 2) { return 53; } //error, size of zlib data too small
553 //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
554 if((in[0] * 256 + in[1]) % 31 != 0) { return 24; }
555 unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
556 //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
557 if(CM != 8 || CINFO > 7) { return 25; }
558 //error: the PNG spec says about the zlib stream: "The additional flags shall not specify a preset dictionary."
559 if(FDICT != 0) { return 26; }
560 inflate(out, in, 2);
561 return error; //note: adler32 checksum was skipped and ignored
562 }
563 };
564
565 struct ExtractPNG //PNG decoding and information extraction
566 {
567 std::vector<ZlibBlockInfo>* zlibinfo;
568 int error;
569
ExtractPNGlodepng::ExtractPNG570 ExtractPNG(std::vector<ZlibBlockInfo>* output) : zlibinfo(output) {};
571
decodelodepng::ExtractPNG572 void decode(const unsigned char* in, size_t size)
573 {
574 error = 0;
575 if(size == 0 || in == 0) { error = 48; return; } //the given data is empty
576 readPngHeader(&in[0], size); if(error) return;
577 size_t pos = 33; //first byte of the first chunk after the header
578 std::vector<unsigned char> idat; //the data from idat chunks
579 bool IEND = false;
580 //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
581 //IDAT data is put at the start of the in buffer
582 while(!IEND)
583 {
584 //error: size of the in buffer too small to contain next chunk
585 if(pos + 8 >= size) { error = 30; return; }
586 size_t chunkLength = read32bitInt(&in[pos]); pos += 4;
587 if(chunkLength > 2147483647) { error = 63; return; }
588 //error: size of the in buffer too small to contain next chunk
589 if(pos + chunkLength >= size) { error = 35; return; }
590 //IDAT chunk, containing compressed image data
591 if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T')
592 {
593 idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
594 pos += (4 + chunkLength);
595 }
596 else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D')
597 {
598 pos += 4;
599 IEND = true;
600 }
601 else //it's not an implemented chunk type, so ignore it: skip over the data
602 {
603 pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
604 }
605 pos += 4; //step over CRC (which is ignored)
606 }
607 std::vector<unsigned char> out; //now the out buffer will be filled
608 ExtractZlib zlib(zlibinfo); //decompress with the Zlib decompressor
609 error = zlib.decompress(out, idat);
610 if(error) return; //stop if the zlib decompressor returned an error
611 }
612
613 //read the information from the header and store it in the Info
readPngHeaderlodepng::ExtractPNG614 void readPngHeader(const unsigned char* in, size_t inlength)
615 {
616 if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header
617 if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71
618 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature
619 //error: it doesn't start with a IHDR chunk!
620 if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; }
621 }
622
readBitFromReversedStreamlodepng::ExtractPNG623 unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits)
624 {
625 unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1;
626 bitp++;
627 return result;
628 }
629
readBitsFromReversedStreamlodepng::ExtractPNG630 unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits)
631 {
632 unsigned long result = 0;
633 for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i);
634 return result;
635 }
636
setBitOfReversedStreamlodepng::ExtractPNG637 void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit)
638 {
639 bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); bitp++;
640 }
641
read32bitIntlodepng::ExtractPNG642 unsigned long read32bitInt(const unsigned char* buffer)
643 {
644 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
645 }
646 };
647
extractZlibInfo(std::vector<ZlibBlockInfo> & zlibinfo,const std::vector<unsigned char> & in)648 void extractZlibInfo(std::vector<ZlibBlockInfo>& zlibinfo, const std::vector<unsigned char>& in)
649 {
650 ExtractPNG decoder(&zlibinfo);
651 decoder.decode(&in[0], in.size());
652
653 if(decoder.error) std::cout << "extract error: " << decoder.error << std::endl;
654 }
655
656 } // namespace lodepng
657