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