zopfli 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +1 -1
- data/.travis.yml +24 -0
- data/Gemfile +2 -0
- data/Rakefile +8 -10
- data/ext/extconf.rb +1 -0
- data/ext/zopfli.c +37 -17
- data/lib/zopfli/version.rb +1 -1
- data/smoke.sh +9 -0
- data/{test → spec}/fixtures/alice29.txt +0 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/zopfli_spec.rb +68 -0
- data/vendor/zopfli/src/zopfli/blocksplitter.c +34 -44
- data/vendor/zopfli/src/zopfli/blocksplitter.h +2 -6
- data/vendor/zopfli/src/zopfli/cache.c +3 -1
- data/vendor/zopfli/src/zopfli/deflate.c +351 -287
- data/vendor/zopfli/src/zopfli/deflate.h +8 -2
- data/vendor/zopfli/src/zopfli/gzip_container.c +54 -47
- data/vendor/zopfli/src/zopfli/hash.c +18 -10
- data/vendor/zopfli/src/zopfli/hash.h +6 -3
- data/vendor/zopfli/src/zopfli/katajainen.c +73 -62
- data/vendor/zopfli/src/zopfli/lz77.c +190 -42
- data/vendor/zopfli/src/zopfli/lz77.h +32 -19
- data/vendor/zopfli/src/zopfli/squeeze.c +75 -61
- data/vendor/zopfli/src/zopfli/squeeze.h +1 -0
- data/vendor/zopfli/src/zopfli/symbols.h +239 -0
- data/vendor/zopfli/src/zopfli/util.c +0 -178
- data/vendor/zopfli/src/zopfli/util.h +6 -23
- data/vendor/zopfli/src/zopfli/zlib_container.c +1 -1
- data/vendor/zopfli/src/zopfli/zopfli.h +1 -4
- data/vendor/zopfli/src/zopfli/zopfli_bin.c +11 -8
- data/zopfli.gemspec +8 -27
- metadata +13 -20
- data/test/test_zopfli_deflate.rb +0 -45
- data/vendor/zopfli/CONTRIBUTING.md +0 -24
- data/vendor/zopfli/CONTRIBUTORS +0 -8
- data/vendor/zopfli/Makefile +0 -42
- data/vendor/zopfli/README +0 -32
- data/vendor/zopfli/README.zopflipng +0 -35
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng.cpp +0 -6252
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng.h +0 -1716
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.cpp +0 -656
- data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.h +0 -151
- data/vendor/zopfli/src/zopflipng/zopflipng_bin.cc +0 -408
- data/vendor/zopfli/src/zopflipng/zopflipng_lib.cc +0 -492
- data/vendor/zopfli/src/zopflipng/zopflipng_lib.h +0 -134
@@ -46,13 +46,37 @@ typedef struct ZopfliLZ77Store {
|
|
46
46
|
unsigned short* dists; /* If 0: indicates literal in corresponding litlens,
|
47
47
|
if > 0: length in corresponding litlens, this is the distance. */
|
48
48
|
size_t size;
|
49
|
+
|
50
|
+
const unsigned char* data; /* original data */
|
51
|
+
size_t* pos; /* position in data where this LZ77 command begins */
|
52
|
+
|
53
|
+
unsigned short* ll_symbol;
|
54
|
+
unsigned short* d_symbol;
|
55
|
+
|
56
|
+
/* Cumulative histograms wrapping around per chunk. Each chunk has the amount
|
57
|
+
of distinct symbols as length, so using 1 value per LZ77 symbol, we have a
|
58
|
+
precise histogram at every N symbols, and the rest can be calculated by
|
59
|
+
looping through the actual symbols of this chunk. */
|
60
|
+
size_t* ll_counts;
|
61
|
+
size_t* d_counts;
|
49
62
|
} ZopfliLZ77Store;
|
50
63
|
|
51
|
-
void ZopfliInitLZ77Store(ZopfliLZ77Store* store);
|
64
|
+
void ZopfliInitLZ77Store(const unsigned char* data, ZopfliLZ77Store* store);
|
52
65
|
void ZopfliCleanLZ77Store(ZopfliLZ77Store* store);
|
53
66
|
void ZopfliCopyLZ77Store(const ZopfliLZ77Store* source, ZopfliLZ77Store* dest);
|
54
67
|
void ZopfliStoreLitLenDist(unsigned short length, unsigned short dist,
|
55
|
-
ZopfliLZ77Store* store);
|
68
|
+
size_t pos, ZopfliLZ77Store* store);
|
69
|
+
void ZopfliAppendLZ77Store(const ZopfliLZ77Store* store,
|
70
|
+
ZopfliLZ77Store* target);
|
71
|
+
/* Gets the amount of raw bytes that this range of LZ77 symbols spans. */
|
72
|
+
size_t ZopfliLZ77GetByteRange(const ZopfliLZ77Store* lz77,
|
73
|
+
size_t lstart, size_t lend);
|
74
|
+
/* Gets the histogram of lit/len and dist symbols in the given range, using the
|
75
|
+
cumulative histograms, so faster than adding one by one for large range. Does
|
76
|
+
not add the one end symbol of value 256. */
|
77
|
+
void ZopfliLZ77GetHistogram(const ZopfliLZ77Store* lz77,
|
78
|
+
size_t lstart, size_t lend,
|
79
|
+
size_t* ll_counts, size_t* d_counts);
|
56
80
|
|
57
81
|
/*
|
58
82
|
Some state information for compressing a block.
|
@@ -72,6 +96,11 @@ typedef struct ZopfliBlockState {
|
|
72
96
|
size_t blockend;
|
73
97
|
} ZopfliBlockState;
|
74
98
|
|
99
|
+
void ZopfliInitBlockState(const ZopfliOptions* options,
|
100
|
+
size_t blockstart, size_t blockend, int add_lmc,
|
101
|
+
ZopfliBlockState* s);
|
102
|
+
void ZopfliCleanBlockState(ZopfliBlockState* s);
|
103
|
+
|
75
104
|
/*
|
76
105
|
Finds the longest match (length and corresponding distance) for LZ77
|
77
106
|
compression.
|
@@ -99,22 +128,6 @@ Verifies if length and dist are indeed valid, only used for assertion.
|
|
99
128
|
void ZopfliVerifyLenDist(const unsigned char* data, size_t datasize, size_t pos,
|
100
129
|
unsigned short dist, unsigned short length);
|
101
130
|
|
102
|
-
/*
|
103
|
-
Counts the number of literal, length and distance symbols in the given lz77
|
104
|
-
arrays.
|
105
|
-
litlens: lz77 lit/lengths
|
106
|
-
dists: ll77 distances
|
107
|
-
start: where to begin counting in litlens and dists
|
108
|
-
end: where to stop counting in litlens and dists (not inclusive)
|
109
|
-
ll_count: count of each lit/len symbol, must have size 288 (see deflate
|
110
|
-
standard)
|
111
|
-
d_count: count of each dist symbol, must have size 32 (see deflate standard)
|
112
|
-
*/
|
113
|
-
void ZopfliLZ77Counts(const unsigned short* litlens,
|
114
|
-
const unsigned short* dists,
|
115
|
-
size_t start, size_t end,
|
116
|
-
size_t* ll_count, size_t* d_count);
|
117
|
-
|
118
131
|
/*
|
119
132
|
Does LZ77 using an algorithm similar to gzip, with lazy matching, rather than
|
120
133
|
with the slow but better "squeeze" implementation.
|
@@ -124,6 +137,6 @@ dictionary.
|
|
124
137
|
*/
|
125
138
|
void ZopfliLZ77Greedy(ZopfliBlockState* s, const unsigned char* in,
|
126
139
|
size_t instart, size_t inend,
|
127
|
-
ZopfliLZ77Store* store);
|
140
|
+
ZopfliLZ77Store* store, ZopfliHash* h);
|
128
141
|
|
129
142
|
#endif /* ZOPFLI_LZ77_H_ */
|
@@ -25,35 +25,40 @@ Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
|
|
25
25
|
|
26
26
|
#include "blocksplitter.h"
|
27
27
|
#include "deflate.h"
|
28
|
+
#include "symbols.h"
|
28
29
|
#include "tree.h"
|
29
30
|
#include "util.h"
|
30
31
|
|
31
32
|
typedef struct SymbolStats {
|
32
33
|
/* The literal and length symbols. */
|
33
|
-
size_t litlens[
|
34
|
+
size_t litlens[ZOPFLI_NUM_LL];
|
34
35
|
/* The 32 unique dist symbols, not the 32768 possible dists. */
|
35
|
-
size_t dists[
|
36
|
+
size_t dists[ZOPFLI_NUM_D];
|
36
37
|
|
37
|
-
|
38
|
-
double
|
38
|
+
/* Length of each lit/len symbol in bits. */
|
39
|
+
double ll_symbols[ZOPFLI_NUM_LL];
|
40
|
+
/* Length of each dist symbol in bits. */
|
41
|
+
double d_symbols[ZOPFLI_NUM_D];
|
39
42
|
} SymbolStats;
|
40
43
|
|
41
44
|
/* Sets everything to 0. */
|
42
45
|
static void InitStats(SymbolStats* stats) {
|
43
|
-
memset(stats->litlens, 0,
|
44
|
-
memset(stats->dists, 0,
|
46
|
+
memset(stats->litlens, 0, ZOPFLI_NUM_LL * sizeof(stats->litlens[0]));
|
47
|
+
memset(stats->dists, 0, ZOPFLI_NUM_D * sizeof(stats->dists[0]));
|
45
48
|
|
46
|
-
memset(stats->ll_symbols, 0,
|
47
|
-
memset(stats->d_symbols, 0,
|
49
|
+
memset(stats->ll_symbols, 0, ZOPFLI_NUM_LL * sizeof(stats->ll_symbols[0]));
|
50
|
+
memset(stats->d_symbols, 0, ZOPFLI_NUM_D * sizeof(stats->d_symbols[0]));
|
48
51
|
}
|
49
52
|
|
50
53
|
static void CopyStats(SymbolStats* source, SymbolStats* dest) {
|
51
|
-
memcpy(dest->litlens, source->litlens,
|
52
|
-
|
54
|
+
memcpy(dest->litlens, source->litlens,
|
55
|
+
ZOPFLI_NUM_LL * sizeof(dest->litlens[0]));
|
56
|
+
memcpy(dest->dists, source->dists, ZOPFLI_NUM_D * sizeof(dest->dists[0]));
|
53
57
|
|
54
58
|
memcpy(dest->ll_symbols, source->ll_symbols,
|
55
|
-
|
56
|
-
memcpy(dest->d_symbols, source->d_symbols,
|
59
|
+
ZOPFLI_NUM_LL * sizeof(dest->ll_symbols[0]));
|
60
|
+
memcpy(dest->d_symbols, source->d_symbols,
|
61
|
+
ZOPFLI_NUM_D * sizeof(dest->d_symbols[0]));
|
57
62
|
}
|
58
63
|
|
59
64
|
/* Adds the bit lengths. */
|
@@ -61,11 +66,11 @@ static void AddWeighedStatFreqs(const SymbolStats* stats1, double w1,
|
|
61
66
|
const SymbolStats* stats2, double w2,
|
62
67
|
SymbolStats* result) {
|
63
68
|
size_t i;
|
64
|
-
for (i = 0; i <
|
69
|
+
for (i = 0; i < ZOPFLI_NUM_LL; i++) {
|
65
70
|
result->litlens[i] =
|
66
71
|
(size_t) (stats1->litlens[i] * w1 + stats2->litlens[i] * w2);
|
67
72
|
}
|
68
|
-
for (i = 0; i <
|
73
|
+
for (i = 0; i < ZOPFLI_NUM_D; i++) {
|
69
74
|
result->dists[i] =
|
70
75
|
(size_t) (stats1->dists[i] * w1 + stats2->dists[i] * w2);
|
71
76
|
}
|
@@ -96,15 +101,15 @@ static void RandomizeFreqs(RanState* state, size_t* freqs, int n) {
|
|
96
101
|
}
|
97
102
|
|
98
103
|
static void RandomizeStatFreqs(RanState* state, SymbolStats* stats) {
|
99
|
-
RandomizeFreqs(state, stats->litlens,
|
100
|
-
RandomizeFreqs(state, stats->dists,
|
104
|
+
RandomizeFreqs(state, stats->litlens, ZOPFLI_NUM_LL);
|
105
|
+
RandomizeFreqs(state, stats->dists, ZOPFLI_NUM_D);
|
101
106
|
stats->litlens[256] = 1; /* End symbol. */
|
102
107
|
}
|
103
108
|
|
104
109
|
static void ClearStatFreqs(SymbolStats* stats) {
|
105
110
|
size_t i;
|
106
|
-
for (i = 0; i <
|
107
|
-
for (i = 0; i <
|
111
|
+
for (i = 0; i < ZOPFLI_NUM_LL; i++) stats->litlens[i] = 0;
|
112
|
+
for (i = 0; i < ZOPFLI_NUM_D; i++) stats->dists[i] = 0;
|
108
113
|
}
|
109
114
|
|
110
115
|
/*
|
@@ -126,7 +131,7 @@ static double GetCostFixed(unsigned litlen, unsigned dist, void* unused) {
|
|
126
131
|
int dbits = ZopfliGetDistExtraBits(dist);
|
127
132
|
int lbits = ZopfliGetLengthExtraBits(litlen);
|
128
133
|
int lsym = ZopfliGetLengthSymbol(litlen);
|
129
|
-
|
134
|
+
int cost = 0;
|
130
135
|
if (lsym <= 279) cost += 7;
|
131
136
|
else cost += 8;
|
132
137
|
cost += 5; /* Every dist symbol has length 5. */
|
@@ -147,7 +152,7 @@ static double GetCostStat(unsigned litlen, unsigned dist, void* context) {
|
|
147
152
|
int lbits = ZopfliGetLengthExtraBits(litlen);
|
148
153
|
int dsym = ZopfliGetDistSymbol(dist);
|
149
154
|
int dbits = ZopfliGetDistExtraBits(dist);
|
150
|
-
return stats->ll_symbols[lsym] +
|
155
|
+
return lbits + dbits + stats->ll_symbols[lsym] + stats->d_symbols[dsym];
|
151
156
|
}
|
152
157
|
}
|
153
158
|
|
@@ -192,6 +197,10 @@ static double GetCostModelMinCost(CostModelFun* costmodel, void* costcontext) {
|
|
192
197
|
return costmodel(bestlength, bestdist, costcontext);
|
193
198
|
}
|
194
199
|
|
200
|
+
static size_t zopfli_min(size_t a, size_t b) {
|
201
|
+
return a < b ? a : b;
|
202
|
+
}
|
203
|
+
|
195
204
|
/*
|
196
205
|
Performs the forward pass for "squeeze". Gets the most optimal length to reach
|
197
206
|
every byte from a previous byte, using cost calculations.
|
@@ -209,27 +218,23 @@ static double GetBestLengths(ZopfliBlockState *s,
|
|
209
218
|
const unsigned char* in,
|
210
219
|
size_t instart, size_t inend,
|
211
220
|
CostModelFun* costmodel, void* costcontext,
|
212
|
-
unsigned short* length_array
|
221
|
+
unsigned short* length_array,
|
222
|
+
ZopfliHash* h, float* costs) {
|
213
223
|
/* Best cost to get here so far. */
|
214
224
|
size_t blocksize = inend - instart;
|
215
|
-
|
216
|
-
size_t i = 0, k;
|
225
|
+
size_t i = 0, k, kend;
|
217
226
|
unsigned short leng;
|
218
227
|
unsigned short dist;
|
219
228
|
unsigned short sublen[259];
|
220
229
|
size_t windowstart = instart > ZOPFLI_WINDOW_SIZE
|
221
230
|
? instart - ZOPFLI_WINDOW_SIZE : 0;
|
222
|
-
ZopfliHash hash;
|
223
|
-
ZopfliHash* h = &hash;
|
224
231
|
double result;
|
225
232
|
double mincost = GetCostModelMinCost(costmodel, costcontext);
|
233
|
+
double mincostaddcostj;
|
226
234
|
|
227
235
|
if (instart == inend) return 0;
|
228
236
|
|
229
|
-
|
230
|
-
if (!costs) exit(-1); /* Allocation failed. */
|
231
|
-
|
232
|
-
ZopfliInitHash(ZOPFLI_WINDOW_SIZE, h);
|
237
|
+
ZopfliResetHash(ZOPFLI_WINDOW_SIZE, h);
|
233
238
|
ZopfliWarmupHash(in, windowstart, inend, h);
|
234
239
|
for (i = windowstart; i < instart; i++) {
|
235
240
|
ZopfliUpdateHash(in, i, inend, h);
|
@@ -270,7 +275,7 @@ static double GetBestLengths(ZopfliBlockState *s,
|
|
270
275
|
|
271
276
|
/* Literal. */
|
272
277
|
if (i + 1 <= inend) {
|
273
|
-
double newCost =
|
278
|
+
double newCost = costmodel(in[i], 0, costcontext) + costs[j];
|
274
279
|
assert(newCost >= 0);
|
275
280
|
if (newCost < costs[j + 1]) {
|
276
281
|
costs[j + 1] = newCost;
|
@@ -278,14 +283,16 @@ static double GetBestLengths(ZopfliBlockState *s,
|
|
278
283
|
}
|
279
284
|
}
|
280
285
|
/* Lengths. */
|
281
|
-
|
286
|
+
kend = zopfli_min(leng, inend-i);
|
287
|
+
mincostaddcostj = mincost + costs[j];
|
288
|
+
for (k = 3; k <= kend; k++) {
|
282
289
|
double newCost;
|
283
290
|
|
284
291
|
/* Calling the cost model is expensive, avoid this if we are already at
|
285
292
|
the minimum possible cost that it can return. */
|
286
|
-
if (costs[j + k]
|
293
|
+
if (costs[j + k] <= mincostaddcostj) continue;
|
287
294
|
|
288
|
-
newCost =
|
295
|
+
newCost = costmodel(k, sublen[k], costcontext) + costs[j];
|
289
296
|
assert(newCost >= 0);
|
290
297
|
if (newCost < costs[j + k]) {
|
291
298
|
assert(k <= ZOPFLI_MAX_MATCH);
|
@@ -298,9 +305,6 @@ static double GetBestLengths(ZopfliBlockState *s,
|
|
298
305
|
assert(costs[blocksize] >= 0);
|
299
306
|
result = costs[blocksize];
|
300
307
|
|
301
|
-
ZopfliCleanHash(h);
|
302
|
-
free(costs);
|
303
|
-
|
304
308
|
return result;
|
305
309
|
}
|
306
310
|
|
@@ -334,19 +338,16 @@ static void TraceBackwards(size_t size, const unsigned short* length_array,
|
|
334
338
|
static void FollowPath(ZopfliBlockState* s,
|
335
339
|
const unsigned char* in, size_t instart, size_t inend,
|
336
340
|
unsigned short* path, size_t pathsize,
|
337
|
-
ZopfliLZ77Store* store) {
|
341
|
+
ZopfliLZ77Store* store, ZopfliHash *h) {
|
338
342
|
size_t i, j, pos = 0;
|
339
343
|
size_t windowstart = instart > ZOPFLI_WINDOW_SIZE
|
340
344
|
? instart - ZOPFLI_WINDOW_SIZE : 0;
|
341
345
|
|
342
346
|
size_t total_length_test = 0;
|
343
347
|
|
344
|
-
ZopfliHash hash;
|
345
|
-
ZopfliHash* h = &hash;
|
346
|
-
|
347
348
|
if (instart == inend) return;
|
348
349
|
|
349
|
-
|
350
|
+
ZopfliResetHash(ZOPFLI_WINDOW_SIZE, h);
|
350
351
|
ZopfliWarmupHash(in, windowstart, inend, h);
|
351
352
|
for (i = windowstart; i < instart; i++) {
|
352
353
|
ZopfliUpdateHash(in, i, inend, h);
|
@@ -369,11 +370,11 @@ static void FollowPath(ZopfliBlockState* s,
|
|
369
370
|
&dist, &dummy_length);
|
370
371
|
assert(!(dummy_length != length && length > 2 && dummy_length > 2));
|
371
372
|
ZopfliVerifyLenDist(in, inend, pos, dist, length);
|
372
|
-
ZopfliStoreLitLenDist(length, dist, store);
|
373
|
+
ZopfliStoreLitLenDist(length, dist, pos, store);
|
373
374
|
total_length_test += length;
|
374
375
|
} else {
|
375
376
|
length = 1;
|
376
|
-
ZopfliStoreLitLenDist(in[pos], 0, store);
|
377
|
+
ZopfliStoreLitLenDist(in[pos], 0, pos, store);
|
377
378
|
total_length_test++;
|
378
379
|
}
|
379
380
|
|
@@ -385,14 +386,12 @@ static void FollowPath(ZopfliBlockState* s,
|
|
385
386
|
|
386
387
|
pos += length;
|
387
388
|
}
|
388
|
-
|
389
|
-
ZopfliCleanHash(h);
|
390
389
|
}
|
391
390
|
|
392
391
|
/* Calculates the entropy of the statistics */
|
393
392
|
static void CalculateStatistics(SymbolStats* stats) {
|
394
|
-
ZopfliCalculateEntropy(stats->litlens,
|
395
|
-
ZopfliCalculateEntropy(stats->dists,
|
393
|
+
ZopfliCalculateEntropy(stats->litlens, ZOPFLI_NUM_LL, stats->ll_symbols);
|
394
|
+
ZopfliCalculateEntropy(stats->dists, ZOPFLI_NUM_D, stats->d_symbols);
|
396
395
|
}
|
397
396
|
|
398
397
|
/* Appends the symbol statistics from the store. */
|
@@ -414,14 +413,13 @@ static void GetStatistics(const ZopfliLZ77Store* store, SymbolStats* stats) {
|
|
414
413
|
/*
|
415
414
|
Does a single run for ZopfliLZ77Optimal. For good compression, repeated runs
|
416
415
|
with updated statistics should be performed.
|
417
|
-
|
418
416
|
s: the block state
|
419
417
|
in: the input data array
|
420
418
|
instart: where to start
|
421
419
|
inend: where to stop (not inclusive)
|
422
420
|
path: pointer to dynamically allocated memory to store the path
|
423
421
|
pathsize: pointer to the size of the dynamic path array
|
424
|
-
length_array: array
|
422
|
+
length_array: array of size (inend - instart) used to store lengths
|
425
423
|
costmodel: function to use as the cost model for this squeeze run
|
426
424
|
costcontext: abstract context for the costmodel function
|
427
425
|
store: place to output the LZ77 data
|
@@ -432,20 +430,22 @@ static double LZ77OptimalRun(ZopfliBlockState* s,
|
|
432
430
|
const unsigned char* in, size_t instart, size_t inend,
|
433
431
|
unsigned short** path, size_t* pathsize,
|
434
432
|
unsigned short* length_array, CostModelFun* costmodel,
|
435
|
-
void* costcontext, ZopfliLZ77Store* store
|
436
|
-
|
437
|
-
|
433
|
+
void* costcontext, ZopfliLZ77Store* store,
|
434
|
+
ZopfliHash* h, float* costs) {
|
435
|
+
double cost = GetBestLengths(s, in, instart, inend, costmodel,
|
436
|
+
costcontext, length_array, h, costs);
|
438
437
|
free(*path);
|
439
438
|
*path = 0;
|
440
439
|
*pathsize = 0;
|
441
440
|
TraceBackwards(inend - instart, length_array, path, pathsize);
|
442
|
-
FollowPath(s, in, instart, inend, *path, *pathsize, store);
|
441
|
+
FollowPath(s, in, instart, inend, *path, *pathsize, store, h);
|
443
442
|
assert(cost < ZOPFLI_LARGE_FLOAT);
|
444
443
|
return cost;
|
445
444
|
}
|
446
445
|
|
447
446
|
void ZopfliLZ77Optimal(ZopfliBlockState *s,
|
448
447
|
const unsigned char* in, size_t instart, size_t inend,
|
448
|
+
int numiterations,
|
449
449
|
ZopfliLZ77Store* store) {
|
450
450
|
/* Dist to get to here with smallest cost. */
|
451
451
|
size_t blocksize = inend - instart;
|
@@ -454,8 +454,11 @@ void ZopfliLZ77Optimal(ZopfliBlockState *s,
|
|
454
454
|
unsigned short* path = 0;
|
455
455
|
size_t pathsize = 0;
|
456
456
|
ZopfliLZ77Store currentstore;
|
457
|
+
ZopfliHash hash;
|
458
|
+
ZopfliHash* h = &hash;
|
457
459
|
SymbolStats stats, beststats, laststats;
|
458
460
|
int i;
|
461
|
+
float* costs = (float*)malloc(sizeof(float) * (blocksize + 1));
|
459
462
|
double cost;
|
460
463
|
double bestcost = ZOPFLI_LARGE_FLOAT;
|
461
464
|
double lastcost = 0;
|
@@ -463,29 +466,30 @@ void ZopfliLZ77Optimal(ZopfliBlockState *s,
|
|
463
466
|
RanState ran_state;
|
464
467
|
int lastrandomstep = -1;
|
465
468
|
|
469
|
+
if (!costs) exit(-1); /* Allocation failed. */
|
466
470
|
if (!length_array) exit(-1); /* Allocation failed. */
|
467
471
|
|
468
472
|
InitRanState(&ran_state);
|
469
473
|
InitStats(&stats);
|
470
|
-
ZopfliInitLZ77Store(¤tstore);
|
474
|
+
ZopfliInitLZ77Store(in, ¤tstore);
|
475
|
+
ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h);
|
471
476
|
|
472
477
|
/* Do regular deflate, then loop multiple shortest path runs, each time using
|
473
478
|
the statistics of the previous run. */
|
474
479
|
|
475
480
|
/* Initial run. */
|
476
|
-
ZopfliLZ77Greedy(s, in, instart, inend, ¤tstore);
|
481
|
+
ZopfliLZ77Greedy(s, in, instart, inend, ¤tstore, h);
|
477
482
|
GetStatistics(¤tstore, &stats);
|
478
483
|
|
479
484
|
/* Repeat statistics with each time the cost model from the previous stat
|
480
485
|
run. */
|
481
|
-
for (i = 0; i <
|
486
|
+
for (i = 0; i < numiterations; i++) {
|
482
487
|
ZopfliCleanLZ77Store(¤tstore);
|
483
|
-
ZopfliInitLZ77Store(¤tstore);
|
488
|
+
ZopfliInitLZ77Store(in, ¤tstore);
|
484
489
|
LZ77OptimalRun(s, in, instart, inend, &path, &pathsize,
|
485
490
|
length_array, GetCostStat, (void*)&stats,
|
486
|
-
¤tstore);
|
487
|
-
cost = ZopfliCalculateBlockSize(currentstore
|
488
|
-
0, currentstore.size, 2);
|
491
|
+
¤tstore, h, costs);
|
492
|
+
cost = ZopfliCalculateBlockSize(¤tstore, 0, currentstore.size, 2);
|
489
493
|
if (s->options->verbose_more || (s->options->verbose && cost < bestcost)) {
|
490
494
|
fprintf(stderr, "Iteration %d: %d bit\n", i, (int) cost);
|
491
495
|
}
|
@@ -516,7 +520,9 @@ void ZopfliLZ77Optimal(ZopfliBlockState *s,
|
|
516
520
|
|
517
521
|
free(length_array);
|
518
522
|
free(path);
|
523
|
+
free(costs);
|
519
524
|
ZopfliCleanLZ77Store(¤tstore);
|
525
|
+
ZopfliCleanHash(h);
|
520
526
|
}
|
521
527
|
|
522
528
|
void ZopfliLZ77OptimalFixed(ZopfliBlockState *s,
|
@@ -530,17 +536,25 @@ void ZopfliLZ77OptimalFixed(ZopfliBlockState *s,
|
|
530
536
|
(unsigned short*)malloc(sizeof(unsigned short) * (blocksize + 1));
|
531
537
|
unsigned short* path = 0;
|
532
538
|
size_t pathsize = 0;
|
539
|
+
ZopfliHash hash;
|
540
|
+
ZopfliHash* h = &hash;
|
541
|
+
float* costs = (float*)malloc(sizeof(float) * (blocksize + 1));
|
533
542
|
|
543
|
+
if (!costs) exit(-1); /* Allocation failed. */
|
534
544
|
if (!length_array) exit(-1); /* Allocation failed. */
|
535
545
|
|
546
|
+
ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h);
|
547
|
+
|
536
548
|
s->blockstart = instart;
|
537
549
|
s->blockend = inend;
|
538
550
|
|
539
551
|
/* Shortest path for fixed tree This one should give the shortest possible
|
540
552
|
result for fixed tree, no repeated runs are needed since the tree is known. */
|
541
553
|
LZ77OptimalRun(s, in, instart, inend, &path, &pathsize,
|
542
|
-
length_array, GetCostFixed, 0, store);
|
554
|
+
length_array, GetCostFixed, 0, store, h, costs);
|
543
555
|
|
544
556
|
free(length_array);
|
545
557
|
free(path);
|
558
|
+
free(costs);
|
559
|
+
ZopfliCleanHash(h);
|
546
560
|
}
|