1337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne/*
2337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode VandevenneLodePNG Utils
3337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
4337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode VandevenneCopyright (c) 2005-2012 Lode Vandevenne
5337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
6337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode VandevenneThis software is provided 'as-is', without any express or implied
7337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennewarranty. In no event will the authors be held liable for any damages
8337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennearising from the use of this software.
9337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
10337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode VandevennePermission is granted to anyone to use this software for any purpose,
11337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneincluding commercial applications, and to alter it and redistribute it
12337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennefreely, subject to the following restrictions:
13337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
14337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    1. The origin of this software must not be misrepresented; you must not
15337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    claim that you wrote the original software. If you use this software
16337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    in a product, an acknowledgment in the product documentation would be
17337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    appreciated but is not required.
18337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
19337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    2. Altered source versions must be plainly marked as such, and must not be
20337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    misrepresented as being the original software.
21337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
22337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    3. This notice may not be removed or altered from any source
23337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    distribution.
24337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne*/
25337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
26337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne#include "lodepng_util.h"
27337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne#include <iostream>
28337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
29337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennenamespace lodepng
30337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
31337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
32337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode VandevenneLodePNGInfo getPNGHeaderInfo(const std::vector<unsigned char>& png)
33337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
34337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned w, h;
35337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  lodepng::State state;
36337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  lodepng_inspect(&w, &h, &state, &png[0], png.size());
37337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  return state.info_png;
38337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
39337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
40337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneunsigned getChunkInfo(std::vector<std::string>& names, std::vector<size_t>& sizes,
41337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                      const std::vector<unsigned char>& png)
42337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
43337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  // Listing chunks is based on the original file, not the decoded png info.
44337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  const unsigned char *chunk, *begin, *end;
45337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  end = &png.back() + 1;
46337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  begin = chunk = &png.front() + 8;
47337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
48337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  while(chunk + 8 < end && chunk >= begin)
49337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
50337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    char type[5];
51337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    lodepng_chunk_type(type, chunk);
52337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(std::string(type).size() != 4) return 1;
53337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
54337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    names.push_back(type);
55337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    sizes.push_back(lodepng_chunk_length(chunk));
56337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
57337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    chunk = lodepng_chunk_next_const(chunk);
58337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
59337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  return 0;
60337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
61337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
62337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneunsigned getChunks(std::vector<std::string> names[3],
63337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                   std::vector<std::vector<unsigned char> > chunks[3],
64337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                   const std::vector<unsigned char>& png)
65337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
66337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  const unsigned char *chunk, *next, *begin, *end;
67337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  end = &png.back() + 1;
68337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  begin = chunk = &png.front() + 8;
69337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
70337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  int location = 0;
71337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
72337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  while(chunk + 8 < end && chunk >= begin)
73337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
74337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    char type[5];
75337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    lodepng_chunk_type(type, chunk);
76337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::string name(type);
77337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(name.size() != 4) return 1;
78337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
79337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    next = lodepng_chunk_next_const(chunk);
80337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
81337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(name == "IHDR")
82337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
83337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      location = 0;
84337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
85337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    else if(name == "PLTE")
86337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
87337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      location = 1;
88337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
89337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    else if(name == "IDAT")
90337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
91337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      location = 2;
92337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
93337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    else if(name != "IEND")
94337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
95337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      names[location].push_back(name);
96337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      chunks[location].push_back(std::vector<unsigned char>(chunk, next));
97337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
98337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
99337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    chunk = next;
100337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
101337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  return 0;
102337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
103337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
104337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
105337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneunsigned insertChunks(std::vector<unsigned char>& png,
106337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                      const std::vector<std::vector<unsigned char> > chunks[3])
107337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
108337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  const unsigned char *chunk, *next, *begin, *end;
109337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  end = &png.back() + 1;
110337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  begin = chunk = &png.front() + 8;
111337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
112337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  size_t l0 = 0; //location 0: IHDR-l0-PLTE (or IHDR-l0-l1-IDAT)
113337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  size_t l1 = 0; //location 1: PLTE-l1-IDAT (or IHDR-l0-l1-IDAT)
114337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  size_t l2 = 0; //location 2: IDAT-l2-IEND
115337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
116337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  while(chunk + 8 < end && chunk >= begin)
117337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
118337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    char type[5];
119337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    lodepng_chunk_type(type, chunk);
120337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::string name(type);
121337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(name.size() != 4) return 1;
122337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
123337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    next = lodepng_chunk_next_const(chunk);
124337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
125337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(name == "PLTE")
126337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
127337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(l0 == 0) l0 = chunk - begin + 8;
128337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
129337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    else if(name == "IDAT")
130337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
131337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(l0 == 0) l0 = chunk - begin + 8;
132337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(l1 == 0) l1 = chunk - begin + 8;
133337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
134337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    else if(name == "IEND")
135337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
136337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(l2 == 0) l2 = chunk - begin + 8;
137337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
138337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
139337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    chunk = next;
140337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
141337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
142337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  std::vector<unsigned char> result;
143337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  result.insert(result.end(), png.begin(), png.begin() + l0);
144337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  for(size_t i = 0; i < chunks[0].size(); i++) result.insert(result.end(), chunks[0][i].begin(), chunks[0][i].end());
145337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  result.insert(result.end(), png.begin() + l0, png.begin() + l1);
146337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  for(size_t i = 0; i < chunks[1].size(); i++) result.insert(result.end(), chunks[1][i].begin(), chunks[1][i].end());
147337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  result.insert(result.end(), png.begin() + l1, png.begin() + l2);
148337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  for(size_t i = 0; i < chunks[2].size(); i++) result.insert(result.end(), chunks[2][i].begin(), chunks[2][i].end());
149337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  result.insert(result.end(), png.begin() + l2, png.end());
150337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
151337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  png = result;
152337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  return 0;
153337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
154337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
155337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneunsigned getFilterTypesInterlaced(std::vector<std::vector<unsigned char> >& filterTypes,
156337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                                  const std::vector<unsigned char>& png)
157337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
158337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  //Get color type and interlace type
159337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  lodepng::State state;
160337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned w, h;
161337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned error;
162337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  error = lodepng_inspect(&w, &h, &state, &png[0], png.size());
163337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
164337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(error) return 1;
165337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
166337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  //Read literal data from all IDAT chunks
167337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  const unsigned char *chunk, *begin, *end;
168337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  end = &png.back() + 1;
169337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  begin = chunk = &png.front() + 8;
170337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
171337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  std::vector<unsigned char> zdata;
172337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
173337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  while(chunk + 8 < end && chunk >= begin)
174337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
175337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    char type[5];
176337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    lodepng_chunk_type(type, chunk);
177337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(std::string(type).size() != 4) return 1; //Probably not a PNG file
178337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
179337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(std::string(type) == "IDAT")
180337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
181337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      const unsigned char* cdata = lodepng_chunk_data_const(chunk);
182337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned clength = lodepng_chunk_length(chunk);
183337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
184337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(unsigned i = 0; i < clength; i++)
185337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
186337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zdata.push_back(cdata[i]);
187337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
188337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
189337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
190337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    chunk = lodepng_chunk_next_const(chunk);
191337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
192337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
193337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  //Decompress all IDAT data
194337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  std::vector<unsigned char> data;
195337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  error = lodepng::decompress(data, &zdata[0], zdata.size());
196337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
197337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(error) return 1;
198337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
199337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(state.info_png.interlace_method == 0)
200337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
201337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    filterTypes.resize(1);
202337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
203337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //A line is 1 filter byte + all pixels
204337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t linebytes = 1 + lodepng_get_raw_size(w, 1, &state.info_png.color);
205337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
206337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < data.size(); i += linebytes)
207337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
208337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      filterTypes[0].push_back(data[i]);
209337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
210337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
211337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  else
212337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
213337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //Interlaced
214337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    filterTypes.resize(7);
215337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
216337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
217337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
218337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
219337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t pos = 0;
220337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(int j = 0; j < 7; j++)
221337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
222337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned w2 = (w - ADAM7_IX[j] + ADAM7_DX[j] - 1) / ADAM7_DX[j];
223337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned h2 = (h - ADAM7_IY[j] + ADAM7_DY[j] - 1) / ADAM7_DY[j];
224337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(ADAM7_IX[j] >= w || ADAM7_IY[j] >= h) w2 = h2 = 0;
225337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      size_t linebytes = 1 + lodepng_get_raw_size(w2, 1, &state.info_png.color);
226337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(size_t i = 0; i < h2; i++)
227337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
228337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        filterTypes[j].push_back(data[pos]);
229337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        pos += linebytes;
230337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
231337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
232337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
233337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  return 0; /* OK */
234337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
235337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
236337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
237337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneunsigned getFilterTypes(std::vector<unsigned char>& filterTypes, const std::vector<unsigned char>& png)
238337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
239337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  std::vector<std::vector<unsigned char> > passes;
240337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned error = getFilterTypesInterlaced(passes, png);
241337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(error) return error;
242337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
243337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(passes.size() == 1)
244337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
245337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    filterTypes.swap(passes[0]);
246337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
247337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  else
248337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
249337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    lodepng::State state;
250337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned w, h;
251337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    lodepng_inspect(&w, &h, &state, &png[0], png.size());
252337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    /*
253337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    Interlaced. Simplify it: put pass 6 and 7 alternating in the one vector so
254337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    that one filter per scanline of the uninterlaced image is given, with that
255337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    filter corresponding the closest to what it would be for non-interlaced
256337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    image.
257337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    */
258337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < h; i++)
259337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
260337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      filterTypes.push_back(i % 2 == 0 ? passes[5][i / 2] : passes[6][i / 2]);
261337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
262337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
263337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  return 0; /* OK */
264337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
265337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
266337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneint getPaletteValue(const unsigned char* data, size_t i, int bits)
267337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
268337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(bits == 8) return data[i];
269337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  else if(bits == 4) return (data[i / 2] >> ((i % 2) * 4)) & 15;
270337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  else if(bits == 2) return (data[i / 4] >> ((i % 4) * 2)) & 3;
271337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  else if(bits == 1) return (data[i / 8] >> (i % 8)) & 1;
272337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  else return 0;
273337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
274337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
275337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne//This uses a stripped down version of picoPNG to extract detailed zlib information while decompressing.
276337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestatic const unsigned long LENBASE[29] =
277337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {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};
278337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestatic const unsigned long LENEXTRA[29] =
279337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {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};
280337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestatic const unsigned long DISTBASE[30] =
281337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {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};
282337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestatic const unsigned long DISTEXTRA[30] =
283337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {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};
284337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestatic const unsigned long CLCL[19] =
285337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; //code length code lengths
286337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
287337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestruct ExtractZlib // Zlib decompression and information extraction
288337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
289337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  std::vector<ZlibBlockInfo>* zlibinfo;
290337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  int error;
291337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
292337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  ExtractZlib(std::vector<ZlibBlockInfo>* output) : zlibinfo(output) {};
293337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
294337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits)
295337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
296337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1;
297337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    bitp++;
298337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    return result;
299337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
300337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
301337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits)
302337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
303337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long result = 0;
304337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i;
305337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    return result;
306337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
307337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
308337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  struct HuffmanTree
309337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
310337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    int makeFromLengths(const std::vector<unsigned long>& bitlen, unsigned long maxbitlen)
311337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    { //make tree given the lengths
312337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0;
313337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      std::vector<unsigned long> tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0);
314337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      //count number of instances of each code length
315337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++;
316337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(unsigned long bits = 1; bits <= maxbitlen; bits++)
317337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
318337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1;
319337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
320337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      //generate all the codes
321337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++;
322337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet
323337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(unsigned long n = 0; n < numcodes; n++) //the codes
324337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      for(unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code
325337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
326337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1;
327337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if(treepos > numcodes - 2) return 55;
328337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if(tree2d[2 * treepos + bit] == 32767) //not yet filled in
329337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        {
330337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i + 1 == bitlen[n])
331337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          {
332337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne            //last bit
333337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne            tree2d[2 * treepos + bit] = n;
334337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne            treepos = 0;
335337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          }
336337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          else
337337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          {
338337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne            //addresses are encoded as values > numcodes
339337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne            tree2d[2 * treepos + bit] = ++nodefilled + numcodes;
340337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne            treepos = nodefilled;
341337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          }
342337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        }
343337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value
344337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
345337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      return 0;
346337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
347337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const
348337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    { //Decodes a symbol from the tree
349337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned long numcodes = (unsigned long)tree2d.size() / 2;
350337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(treepos >= numcodes) return 11; //error: you appeared outside the codetree
351337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      result = tree2d[2 * treepos + bit];
352337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      decoded = (result < numcodes);
353337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      treepos = decoded ? 0 : result - numcodes;
354337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      return 0;
355337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
356337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //2D representation of a huffman tree: one dimension is "0" or "1", the other contains all nodes and leaves.
357337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::vector<unsigned long> tree2d;
358337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  };
359337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
360337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void inflate(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, size_t inpos = 0)
361337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
362337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t bp = 0, pos = 0; //bit pointer and byte pointer
363337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    error = 0;
364337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long BFINAL = 0;
365337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    while(!BFINAL && !error)
366337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
367337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      size_t uncomprblockstart = pos;
368337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      size_t bpstart = bp;
369337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory
370337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      BFINAL = readBitFromStream(bp, &in[inpos]);
371337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]);
372337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->resize(zlibinfo->size() + 1);
373337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().btype = BTYPE;
374337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE
375337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size());
376337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE);
377337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      size_t uncomprblocksize = pos - uncomprblockstart;
378337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().compressedbits = bp - bpstart;
379337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().uncompressedbytes = uncomprblocksize;
380337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
381337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
382337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
383337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) //get the tree of a deflated block with fixed tree
384337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
385337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::vector<unsigned long> bitlen(288, 8), bitlenD(32, 5);;
386337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 144; i <= 255; i++) bitlen[i] = 9;
387337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 256; i <= 279; i++) bitlen[i] = 7;
388337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    tree.makeFromLengths(bitlen, 15);
389337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    treeD.makeFromLengths(bitlenD, 15);
390337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
391337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
392337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  //the code tree for Huffman codes, dist codes, and code length codes
393337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  HuffmanTree codetree, codetreeD, codelengthcodetree;
394337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength)
395337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
396337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //decode a single symbol from given list of bits with given code tree. return value is the symbol
397337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    bool decoded; unsigned long ct;
398337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t treepos = 0;;)
399337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
400337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode
401337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in));
402337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(error) return 0; //stop, an error happened
403337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(decoded) return ct;
404337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
405337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
406337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
407337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD,
408337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                             const unsigned char* in, size_t& bp, size_t inlength)
409337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
410337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t bpstart = bp;
411337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree
412337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::vector<unsigned long> bitlen(288, 0), bitlenD(32, 0);
413337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory
414337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t HLIT =  readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257
415337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1
416337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4
417337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    zlibinfo->back().hlit = HLIT - 257;
418337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    zlibinfo->back().hdist = HDIST - 1;
419337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    zlibinfo->back().hclen = HCLEN - 4;
420337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::vector<unsigned long> codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree
421337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0;
422337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //code length code lengths
423337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < codelengthcode.size(); i++) zlibinfo->back().clcl.push_back(codelengthcode[i]);
424337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return;
425337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t i = 0, replength;
426337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    while(i < HLIT + HDIST)
427337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
428337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return;
429337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().treecodes.push_back(code); //tree symbol code
430337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(code <= 15)  { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code
431337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(code == 16) //repeat previous
432337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
433337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
434337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        replength = 3 + readBitsFromStream(bp, in, 2);
435337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        unsigned long value; //set value to the previous code
436337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if((i - 1) < HLIT) value = bitlen[i - 1];
437337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        else value = bitlenD[i - HLIT - 1];
438337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
439337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        {
440337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes
441337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value;
442337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        }
443337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
444337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(code == 17) //repeat "0" 3-10 times
445337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
446337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
447337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        replength = 3 + readBitsFromStream(bp, in, 3);
448337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().treecodes.push_back(replength); //tree symbol code repetitions
449337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
450337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        {
451337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes
452337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
453337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        }
454337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
455337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(code == 18) //repeat "0" 11-138 times
456337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
457337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
458337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        replength = 11 + readBitsFromStream(bp, in, 7);
459337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().treecodes.push_back(replength); //tree symbol code repetitions
460337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
461337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        {
462337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes
463337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
464337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        }
465337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
466337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen.
467337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
468337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0
469337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    error = tree.makeFromLengths(bitlen, 15);
470337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
471337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    error = treeD.makeFromLengths(bitlenD, 15);
472337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(error) return;
473337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    zlibinfo->back().treebits = bp - bpstart;
474337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //lit/len/end symbol lengths
475337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < bitlen.size(); i++) zlibinfo->back().litlenlengths.push_back(bitlen[i]);
476337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //dist lengths
477337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = 0; i < bitlenD.size(); i++) zlibinfo->back().distlengths.push_back(bitlenD[i]);
478337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
479337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
480337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void inflateHuffmanBlock(std::vector<unsigned char>& out,
481337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                           const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype)
482337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
483337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t numcodes = 0, numlit = 0, numlen = 0; //for logging
484337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(btype == 1) { generateFixedTrees(codetree, codetreeD); }
485337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; }
486337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(;;)
487337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
488337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return;
489337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      numcodes++;
490337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().lz77_lcode.push_back(code); //output code
491337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().lz77_dcode.push_back(0);
492337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().lz77_lbits.push_back(0);
493337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().lz77_dbits.push_back(0);
494337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().lz77_lvalue.push_back(0);
495337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      zlibinfo->back().lz77_dvalue.push_back(0);
496337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
497337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(code == 256) break; //end code
498337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(code <= 255) //literal symbol
499337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
500337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        out.push_back((unsigned char)(code));
501337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        pos++;
502337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        numlit++;
503337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
504337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(code >= 257 && code <= 285) //length code
505337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
506337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
507337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
508337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        length += readBitsFromStream(bp, in, numextrabits);
509337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return;
510337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used)
511337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
512337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
513337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        dist += readBitsFromStream(bp, in, numextrabitsD);
514337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        size_t start = pos, back = start - dist; //backwards
515337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        for(size_t i = 0; i < length; i++)
516337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        {
517337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          out.push_back(out[back++]);
518337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          pos++;
519337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          if(back >= start) back = start - dist;
520337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        }
521337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        numlen++;
522337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().lz77_dcode.back() = codeD; //output distance code
523337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().lz77_lbits.back() = numextrabits; //output length extra bits
524337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().lz77_dbits.back() = numextrabitsD; //output dist extra bits
525337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().lz77_lvalue.back() = length; //output length
526337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        zlibinfo->back().lz77_dvalue.back() = dist; //output dist
527337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
528337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
529337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    zlibinfo->back().numlit = numlit; //output number of literal symbols
530337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    zlibinfo->back().numlen = numlen; //output number of length symbols
531337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
532337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
533337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void inflateNoCompression(std::vector<unsigned char>& out,
534337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne                            const unsigned char* in, size_t& bp, size_t& pos, size_t inlength)
535337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
536337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    while((bp & 0x7) != 0) bp++; //go to first boundary of byte
537337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t p = bp / 8;
538337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory
539337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4;
540337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN
541337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer
542337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(unsigned long n = 0; n < LEN; n++)
543337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
544337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      out.push_back(in[p++]); //read LEN bytes of literal data
545337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      pos++;
546337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
547337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    bp = p * 8;
548337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
549337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
550337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  int decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in) //returns error value
551337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
552337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(in.size() < 2) { return 53; } //error, size of zlib data too small
553337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
554337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if((in[0] * 256 + in[1]) % 31 != 0) { return 24; }
555337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
556337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
557337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(CM != 8 || CINFO > 7) { return 25; }
558337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //error: the PNG spec says about the zlib stream: "The additional flags shall not specify a preset dictionary."
559337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(FDICT != 0) { return 26; }
560337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    inflate(out, in, 2);
561337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    return error; //note: adler32 checksum was skipped and ignored
562337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
563337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne};
564337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
565337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennestruct ExtractPNG //PNG decoding and information extraction
566337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
567337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  std::vector<ZlibBlockInfo>* zlibinfo;
568337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  int error;
569337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
570337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  ExtractPNG(std::vector<ZlibBlockInfo>* output) : zlibinfo(output) {};
571337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
572337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void decode(const unsigned char* in, size_t size)
573337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
574337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    error = 0;
575337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(size == 0 || in == 0) { error = 48; return; } //the given data is empty
576337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    readPngHeader(&in[0], size); if(error) return;
577337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    size_t pos = 33; //first byte of the first chunk after the header
578337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::vector<unsigned char> idat; //the data from idat chunks
579337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    bool IEND = false;
580337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
581337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //IDAT data is put at the start of the in buffer
582337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    while(!IEND)
583337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    {
584337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      //error: size of the in buffer too small to contain next chunk
585337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(pos + 8 >= size) { error = 30; return; }
586337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      size_t chunkLength = read32bitInt(&in[pos]); pos += 4;
587337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(chunkLength > 2147483647) { error = 63; return; }
588337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      //error: size of the in buffer too small to contain next chunk
589337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(pos + chunkLength >= size) { error = 35; return; }
590337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      //IDAT chunk, containing compressed image data
591337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T')
592337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
593337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
594337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        pos += (4 + chunkLength);
595337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
596337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D')
597337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
598337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          pos += 4;
599337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne          IEND = true;
600337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
601337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      else //it's not an implemented chunk type, so ignore it: skip over the data
602337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      {
603337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne        pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
604337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      }
605337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne      pos += 4; //step over CRC (which is ignored)
606337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    }
607337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    std::vector<unsigned char> out; //now the out buffer will be filled
608337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    ExtractZlib zlib(zlibinfo); //decompress with the Zlib decompressor
609337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    error = zlib.decompress(out, idat);
610337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(error) return; //stop if the zlib decompressor returned an error
611337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
612337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
613337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  //read the information from the header and store it in the Info
614337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void readPngHeader(const unsigned char* in, size_t inlength)
615337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
616337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header
617337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71
618337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature
619337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    //error: it doesn't start with a IHDR chunk!
620337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; }
621337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
622337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
623337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits)
624337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
625337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1;
626337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    bitp++;
627337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    return result;
628337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
629337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
630337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits)
631337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
632337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    unsigned long result = 0;
633337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i);
634337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    return result;
635337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
636337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
637337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit)
638337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
639337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    bits[bitp >> 3] |=  (bit << (7 - (bitp & 0x7))); bitp++;
640337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
641337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
642337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  unsigned long read32bitInt(const unsigned char* buffer)
643337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  {
644337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne    return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
645337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  }
646337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne};
647337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
648337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennevoid extractZlibInfo(std::vector<ZlibBlockInfo>& zlibinfo, const std::vector<unsigned char>& in)
649337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne{
650337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  ExtractPNG decoder(&zlibinfo);
651337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  decoder.decode(&in[0], in.size());
652337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
653337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne  if(decoder.error) std::cout << "extract error: " << decoder.error << std::endl;
654337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne}
655337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne
656337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} // namespace lodepng
657