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