zopfli 0.0.3 → 0.1.0

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