• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright 2011 Google Inc. All Rights Reserved.
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8     http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 Author: lode.vandevenne@gmail.com (Lode Vandevenne)
17 Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
18 */
19 
20 #include "squeeze.h"
21 
22 #include <assert.h>
23 #include <math.h>
24 #include <stdio.h>
25 
26 #include "blocksplitter.h"
27 #include "deflate.h"
28 #include "tree.h"
29 #include "util.h"
30 
31 typedef struct SymbolStats {
32   /* The literal and length symbols. */
33   size_t litlens[288];
34   /* The 32 unique dist symbols, not the 32768 possible dists. */
35   size_t dists[32];
36 
37   double ll_symbols[288];  /* Length of each lit/len symbol in bits. */
38   double d_symbols[32];  /* Length of each dist symbol in bits. */
39 } SymbolStats;
40 
41 /* Sets everything to 0. */
InitStats(SymbolStats * stats)42 static void InitStats(SymbolStats* stats) {
43   memset(stats->litlens, 0, 288 * sizeof(stats->litlens[0]));
44   memset(stats->dists, 0, 32 * sizeof(stats->dists[0]));
45 
46   memset(stats->ll_symbols, 0, 288 * sizeof(stats->ll_symbols[0]));
47   memset(stats->d_symbols, 0, 32 * sizeof(stats->d_symbols[0]));
48 }
49 
CopyStats(SymbolStats * source,SymbolStats * dest)50 static void CopyStats(SymbolStats* source, SymbolStats* dest) {
51   memcpy(dest->litlens, source->litlens, 288 * sizeof(dest->litlens[0]));
52   memcpy(dest->dists, source->dists, 32 * sizeof(dest->dists[0]));
53 
54   memcpy(dest->ll_symbols, source->ll_symbols,
55          288 * sizeof(dest->ll_symbols[0]));
56   memcpy(dest->d_symbols, source->d_symbols, 32 * sizeof(dest->d_symbols[0]));
57 }
58 
59 /* Adds the bit lengths. */
AddWeighedStatFreqs(const SymbolStats * stats1,double w1,const SymbolStats * stats2,double w2,SymbolStats * result)60 static void AddWeighedStatFreqs(const SymbolStats* stats1, double w1,
61                                 const SymbolStats* stats2, double w2,
62                                 SymbolStats* result) {
63   size_t i;
64   for (i = 0; i < 288; i++) {
65     result->litlens[i] =
66         (size_t) (stats1->litlens[i] * w1 + stats2->litlens[i] * w2);
67   }
68   for (i = 0; i < 32; i++) {
69     result->dists[i] =
70         (size_t) (stats1->dists[i] * w1 + stats2->dists[i] * w2);
71   }
72   result->litlens[256] = 1;  /* End symbol. */
73 }
74 
75 typedef struct RanState {
76   unsigned int m_w, m_z;
77 } RanState;
78 
InitRanState(RanState * state)79 static void InitRanState(RanState* state) {
80   state->m_w = 1;
81   state->m_z = 2;
82 }
83 
84 /* Get random number: "Multiply-With-Carry" generator of G. Marsaglia */
Ran(RanState * state)85 static unsigned int Ran(RanState* state) {
86   state->m_z = 36969 * (state->m_z & 65535) + (state->m_z >> 16);
87   state->m_w = 18000 * (state->m_w & 65535) + (state->m_w >> 16);
88   return (state->m_z << 16) + state->m_w;  /* 32-bit result. */
89 }
90 
RandomizeFreqs(RanState * state,size_t * freqs,int n)91 static void RandomizeFreqs(RanState* state, size_t* freqs, int n) {
92   int i;
93   for (i = 0; i < n; i++) {
94     if ((Ran(state) >> 4) % 3 == 0) freqs[i] = freqs[Ran(state) % n];
95   }
96 }
97 
RandomizeStatFreqs(RanState * state,SymbolStats * stats)98 static void RandomizeStatFreqs(RanState* state, SymbolStats* stats) {
99   RandomizeFreqs(state, stats->litlens, 288);
100   RandomizeFreqs(state, stats->dists, 32);
101   stats->litlens[256] = 1;  /* End symbol. */
102 }
103 
ClearStatFreqs(SymbolStats * stats)104 static void ClearStatFreqs(SymbolStats* stats) {
105   size_t i;
106   for (i = 0; i < 288; i++) stats->litlens[i] = 0;
107   for (i = 0; i < 32; i++) stats->dists[i] = 0;
108 }
109 
110 /*
111 Function that calculates a cost based on a model for the given LZ77 symbol.
112 litlen: means literal symbol if dist is 0, length otherwise.
113 */
114 typedef double CostModelFun(unsigned litlen, unsigned dist, void* context);
115 
116 /*
117 Cost model which should exactly match fixed tree.
118 type: CostModelFun
119 */
GetCostFixed(unsigned litlen,unsigned dist,void * unused)120 static double GetCostFixed(unsigned litlen, unsigned dist, void* unused) {
121   (void)unused;
122   if (dist == 0) {
123     if (litlen <= 143) return 8;
124     else return 9;
125   } else {
126     int dbits = ZopfliGetDistExtraBits(dist);
127     int lbits = ZopfliGetLengthExtraBits(litlen);
128     int lsym = ZopfliGetLengthSymbol(litlen);
129     double cost = 0;
130     if (lsym <= 279) cost += 7;
131     else cost += 8;
132     cost += 5;  /* Every dist symbol has length 5. */
133     return cost + dbits + lbits;
134   }
135 }
136 
137 /*
138 Cost model based on symbol statistics.
139 type: CostModelFun
140 */
GetCostStat(unsigned litlen,unsigned dist,void * context)141 static double GetCostStat(unsigned litlen, unsigned dist, void* context) {
142   SymbolStats* stats = (SymbolStats*)context;
143   if (dist == 0) {
144     return stats->ll_symbols[litlen];
145   } else {
146     int lsym = ZopfliGetLengthSymbol(litlen);
147     int lbits = ZopfliGetLengthExtraBits(litlen);
148     int dsym = ZopfliGetDistSymbol(dist);
149     int dbits = ZopfliGetDistExtraBits(dist);
150     return stats->ll_symbols[lsym] + lbits + stats->d_symbols[dsym] + dbits;
151   }
152 }
153 
154 /*
155 Finds the minimum possible cost this cost model can return for valid length and
156 distance symbols.
157 */
GetCostModelMinCost(CostModelFun * costmodel,void * costcontext)158 static double GetCostModelMinCost(CostModelFun* costmodel, void* costcontext) {
159   double mincost;
160   int bestlength = 0; /* length that has lowest cost in the cost model */
161   int bestdist = 0; /* distance that has lowest cost in the cost model */
162   int i;
163   /*
164   Table of distances that have a different distance symbol in the deflate
165   specification. Each value is the first distance that has a new symbol. Only
166   different symbols affect the cost model so only these need to be checked.
167   See RFC 1951 section 3.2.5. Compressed blocks (length and distance codes).
168   */
169   static const int dsymbols[30] = {
170     1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
171     769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
172   };
173 
174   mincost = ZOPFLI_LARGE_FLOAT;
175   for (i = 3; i < 259; i++) {
176     double c = costmodel(i, 1, costcontext);
177     if (c < mincost) {
178       bestlength = i;
179       mincost = c;
180     }
181   }
182 
183   mincost = ZOPFLI_LARGE_FLOAT;
184   for (i = 0; i < 30; i++) {
185     double c = costmodel(3, dsymbols[i], costcontext);
186     if (c < mincost) {
187       bestdist = dsymbols[i];
188       mincost = c;
189     }
190   }
191 
192   return costmodel(bestlength, bestdist, costcontext);
193 }
194 
195 /*
196 Performs the forward pass for "squeeze". Gets the most optimal length to reach
197 every byte from a previous byte, using cost calculations.
198 s: the ZopfliBlockState
199 in: the input data array
200 instart: where to start
201 inend: where to stop (not inclusive)
202 costmodel: function to calculate the cost of some lit/len/dist pair.
203 costcontext: abstract context for the costmodel function
204 length_array: output array of size (inend - instart) which will receive the best
205     length to reach this byte from a previous byte.
206 returns the cost that was, according to the costmodel, needed to get to the end.
207 */
GetBestLengths(ZopfliBlockState * s,const unsigned char * in,size_t instart,size_t inend,CostModelFun * costmodel,void * costcontext,unsigned short * length_array)208 static double GetBestLengths(ZopfliBlockState *s,
209                              const unsigned char* in,
210                              size_t instart, size_t inend,
211                              CostModelFun* costmodel, void* costcontext,
212                              unsigned short* length_array) {
213   /* Best cost to get here so far. */
214   size_t blocksize = inend - instart;
215   float* costs;
216   size_t i = 0, k;
217   unsigned short leng;
218   unsigned short dist;
219   unsigned short sublen[259];
220   size_t windowstart = instart > ZOPFLI_WINDOW_SIZE
221       ? instart - ZOPFLI_WINDOW_SIZE : 0;
222   ZopfliHash hash;
223   ZopfliHash* h = &hash;
224   double result;
225   double mincost = GetCostModelMinCost(costmodel, costcontext);
226 
227   if (instart == inend) return 0;
228 
229   costs = (float*)malloc(sizeof(float) * (blocksize + 1));
230   if (!costs) exit(-1); /* Allocation failed. */
231 
232   ZopfliInitHash(ZOPFLI_WINDOW_SIZE, h);
233   ZopfliWarmupHash(in, windowstart, inend, h);
234   for (i = windowstart; i < instart; i++) {
235     ZopfliUpdateHash(in, i, inend, h);
236   }
237 
238   for (i = 1; i < blocksize + 1; i++) costs[i] = ZOPFLI_LARGE_FLOAT;
239   costs[0] = 0;  /* Because it's the start. */
240   length_array[0] = 0;
241 
242   for (i = instart; i < inend; i++) {
243     size_t j = i - instart;  /* Index in the costs array and length_array. */
244     ZopfliUpdateHash(in, i, inend, h);
245 
246 #ifdef ZOPFLI_SHORTCUT_LONG_REPETITIONS
247     /* If we're in a long repetition of the same character and have more than
248     ZOPFLI_MAX_MATCH characters before and after our position. */
249     if (h->same[i & ZOPFLI_WINDOW_MASK] > ZOPFLI_MAX_MATCH * 2
250         && i > instart + ZOPFLI_MAX_MATCH + 1
251         && i + ZOPFLI_MAX_MATCH * 2 + 1 < inend
252         && h->same[(i - ZOPFLI_MAX_MATCH) & ZOPFLI_WINDOW_MASK]
253             > ZOPFLI_MAX_MATCH) {
254       double symbolcost = costmodel(ZOPFLI_MAX_MATCH, 1, costcontext);
255       /* Set the length to reach each one to ZOPFLI_MAX_MATCH, and the cost to
256       the cost corresponding to that length. Doing this, we skip
257       ZOPFLI_MAX_MATCH values to avoid calling ZopfliFindLongestMatch. */
258       for (k = 0; k < ZOPFLI_MAX_MATCH; k++) {
259         costs[j + ZOPFLI_MAX_MATCH] = costs[j] + symbolcost;
260         length_array[j + ZOPFLI_MAX_MATCH] = ZOPFLI_MAX_MATCH;
261         i++;
262         j++;
263         ZopfliUpdateHash(in, i, inend, h);
264       }
265     }
266 #endif
267 
268     ZopfliFindLongestMatch(s, h, in, i, inend, ZOPFLI_MAX_MATCH, sublen,
269                            &dist, &leng);
270 
271     /* Literal. */
272     if (i + 1 <= inend) {
273       double newCost = costs[j] + costmodel(in[i], 0, costcontext);
274       assert(newCost >= 0);
275       if (newCost < costs[j + 1]) {
276         costs[j + 1] = newCost;
277         length_array[j + 1] = 1;
278       }
279     }
280     /* Lengths. */
281     for (k = 3; k <= leng && i + k <= inend; k++) {
282       double newCost;
283 
284       /* Calling the cost model is expensive, avoid this if we are already at
285       the minimum possible cost that it can return. */
286      if (costs[j + k] - costs[j] <= mincost) continue;
287 
288       newCost = costs[j] + costmodel(k, sublen[k], costcontext);
289       assert(newCost >= 0);
290       if (newCost < costs[j + k]) {
291         assert(k <= ZOPFLI_MAX_MATCH);
292         costs[j + k] = newCost;
293         length_array[j + k] = k;
294       }
295     }
296   }
297 
298   assert(costs[blocksize] >= 0);
299   result = costs[blocksize];
300 
301   ZopfliCleanHash(h);
302   free(costs);
303 
304   return result;
305 }
306 
307 /*
308 Calculates the optimal path of lz77 lengths to use, from the calculated
309 length_array. The length_array must contain the optimal length to reach that
310 byte. The path will be filled with the lengths to use, so its data size will be
311 the amount of lz77 symbols.
312 */
TraceBackwards(size_t size,const unsigned short * length_array,unsigned short ** path,size_t * pathsize)313 static void TraceBackwards(size_t size, const unsigned short* length_array,
314                            unsigned short** path, size_t* pathsize) {
315   size_t index = size;
316   if (size == 0) return;
317   for (;;) {
318     ZOPFLI_APPEND_DATA(length_array[index], path, pathsize);
319     assert(length_array[index] <= index);
320     assert(length_array[index] <= ZOPFLI_MAX_MATCH);
321     assert(length_array[index] != 0);
322     index -= length_array[index];
323     if (index == 0) break;
324   }
325 
326   /* Mirror result. */
327   for (index = 0; index < *pathsize / 2; index++) {
328     unsigned short temp = (*path)[index];
329     (*path)[index] = (*path)[*pathsize - index - 1];
330     (*path)[*pathsize - index - 1] = temp;
331   }
332 }
333 
FollowPath(ZopfliBlockState * s,const unsigned char * in,size_t instart,size_t inend,unsigned short * path,size_t pathsize,ZopfliLZ77Store * store)334 static void FollowPath(ZopfliBlockState* s,
335                        const unsigned char* in, size_t instart, size_t inend,
336                        unsigned short* path, size_t pathsize,
337                        ZopfliLZ77Store* store) {
338   size_t i, j, pos = 0;
339   size_t windowstart = instart > ZOPFLI_WINDOW_SIZE
340       ? instart - ZOPFLI_WINDOW_SIZE : 0;
341 
342   size_t total_length_test = 0;
343 
344   ZopfliHash hash;
345   ZopfliHash* h = &hash;
346 
347   if (instart == inend) return;
348 
349   ZopfliInitHash(ZOPFLI_WINDOW_SIZE, h);
350   ZopfliWarmupHash(in, windowstart, inend, h);
351   for (i = windowstart; i < instart; i++) {
352     ZopfliUpdateHash(in, i, inend, h);
353   }
354 
355   pos = instart;
356   for (i = 0; i < pathsize; i++) {
357     unsigned short length = path[i];
358     unsigned short dummy_length;
359     unsigned short dist;
360     assert(pos < inend);
361 
362     ZopfliUpdateHash(in, pos, inend, h);
363 
364     /* Add to output. */
365     if (length >= ZOPFLI_MIN_MATCH) {
366       /* Get the distance by recalculating longest match. The found length
367       should match the length from the path. */
368       ZopfliFindLongestMatch(s, h, in, pos, inend, length, 0,
369                              &dist, &dummy_length);
370       assert(!(dummy_length != length && length > 2 && dummy_length > 2));
371       ZopfliVerifyLenDist(in, inend, pos, dist, length);
372       ZopfliStoreLitLenDist(length, dist, store);
373       total_length_test += length;
374     } else {
375       length = 1;
376       ZopfliStoreLitLenDist(in[pos], 0, store);
377       total_length_test++;
378     }
379 
380 
381     assert(pos + length <= inend);
382     for (j = 1; j < length; j++) {
383       ZopfliUpdateHash(in, pos + j, inend, h);
384     }
385 
386     pos += length;
387   }
388 
389   ZopfliCleanHash(h);
390 }
391 
392 /* Calculates the entropy of the statistics */
CalculateStatistics(SymbolStats * stats)393 static void CalculateStatistics(SymbolStats* stats) {
394   ZopfliCalculateEntropy(stats->litlens, 288, stats->ll_symbols);
395   ZopfliCalculateEntropy(stats->dists, 32, stats->d_symbols);
396 }
397 
398 /* Appends the symbol statistics from the store. */
GetStatistics(const ZopfliLZ77Store * store,SymbolStats * stats)399 static void GetStatistics(const ZopfliLZ77Store* store, SymbolStats* stats) {
400   size_t i;
401   for (i = 0; i < store->size; i++) {
402     if (store->dists[i] == 0) {
403       stats->litlens[store->litlens[i]]++;
404     } else {
405       stats->litlens[ZopfliGetLengthSymbol(store->litlens[i])]++;
406       stats->dists[ZopfliGetDistSymbol(store->dists[i])]++;
407     }
408   }
409   stats->litlens[256] = 1;  /* End symbol. */
410 
411   CalculateStatistics(stats);
412 }
413 
414 /*
415 Does a single run for ZopfliLZ77Optimal. For good compression, repeated runs
416 with updated statistics should be performed.
417 
418 s: the block state
419 in: the input data array
420 instart: where to start
421 inend: where to stop (not inclusive)
422 path: pointer to dynamically allocated memory to store the path
423 pathsize: pointer to the size of the dynamic path array
424 length_array: array if size (inend - instart) used to store lengths
425 costmodel: function to use as the cost model for this squeeze run
426 costcontext: abstract context for the costmodel function
427 store: place to output the LZ77 data
428 returns the cost that was, according to the costmodel, needed to get to the end.
429     This is not the actual cost.
430 */
LZ77OptimalRun(ZopfliBlockState * s,const unsigned char * in,size_t instart,size_t inend,unsigned short ** path,size_t * pathsize,unsigned short * length_array,CostModelFun * costmodel,void * costcontext,ZopfliLZ77Store * store)431 static double LZ77OptimalRun(ZopfliBlockState* s,
432     const unsigned char* in, size_t instart, size_t inend,
433     unsigned short** path, size_t* pathsize,
434     unsigned short* length_array, CostModelFun* costmodel,
435     void* costcontext, ZopfliLZ77Store* store) {
436   double cost = GetBestLengths(
437       s, in, instart, inend, costmodel, costcontext, length_array);
438   free(*path);
439   *path = 0;
440   *pathsize = 0;
441   TraceBackwards(inend - instart, length_array, path, pathsize);
442   FollowPath(s, in, instart, inend, *path, *pathsize, store);
443   assert(cost < ZOPFLI_LARGE_FLOAT);
444   return cost;
445 }
446 
ZopfliLZ77Optimal(ZopfliBlockState * s,const unsigned char * in,size_t instart,size_t inend,ZopfliLZ77Store * store)447 void ZopfliLZ77Optimal(ZopfliBlockState *s,
448                        const unsigned char* in, size_t instart, size_t inend,
449                        ZopfliLZ77Store* store) {
450   /* Dist to get to here with smallest cost. */
451   size_t blocksize = inend - instart;
452   unsigned short* length_array =
453       (unsigned short*)malloc(sizeof(unsigned short) * (blocksize + 1));
454   unsigned short* path = 0;
455   size_t pathsize = 0;
456   ZopfliLZ77Store currentstore;
457   SymbolStats stats, beststats, laststats;
458   int i;
459   double cost;
460   double bestcost = ZOPFLI_LARGE_FLOAT;
461   double lastcost = 0;
462   /* Try randomizing the costs a bit once the size stabilizes. */
463   RanState ran_state;
464   int lastrandomstep = -1;
465 
466   if (!length_array) exit(-1); /* Allocation failed. */
467 
468   InitRanState(&ran_state);
469   InitStats(&stats);
470   ZopfliInitLZ77Store(&currentstore);
471 
472   /* Do regular deflate, then loop multiple shortest path runs, each time using
473   the statistics of the previous run. */
474 
475   /* Initial run. */
476   ZopfliLZ77Greedy(s, in, instart, inend, &currentstore);
477   GetStatistics(&currentstore, &stats);
478 
479   /* Repeat statistics with each time the cost model from the previous stat
480   run. */
481   for (i = 0; i < s->options->numiterations; i++) {
482     ZopfliCleanLZ77Store(&currentstore);
483     ZopfliInitLZ77Store(&currentstore);
484     LZ77OptimalRun(s, in, instart, inend, &path, &pathsize,
485                    length_array, GetCostStat, (void*)&stats,
486                    &currentstore);
487     cost = ZopfliCalculateBlockSize(currentstore.litlens, currentstore.dists,
488                                     0, currentstore.size, 2);
489     if (s->options->verbose_more || (s->options->verbose && cost < bestcost)) {
490       fprintf(stderr, "Iteration %d: %d bit\n", i, (int) cost);
491     }
492     if (cost < bestcost) {
493       /* Copy to the output store. */
494       ZopfliCopyLZ77Store(&currentstore, store);
495       CopyStats(&stats, &beststats);
496       bestcost = cost;
497     }
498     CopyStats(&stats, &laststats);
499     ClearStatFreqs(&stats);
500     GetStatistics(&currentstore, &stats);
501     if (lastrandomstep != -1) {
502       /* This makes it converge slower but better. Do it only once the
503       randomness kicks in so that if the user does few iterations, it gives a
504       better result sooner. */
505       AddWeighedStatFreqs(&stats, 1.0, &laststats, 0.5, &stats);
506       CalculateStatistics(&stats);
507     }
508     if (i > 5 && cost == lastcost) {
509       CopyStats(&beststats, &stats);
510       RandomizeStatFreqs(&ran_state, &stats);
511       CalculateStatistics(&stats);
512       lastrandomstep = i;
513     }
514     lastcost = cost;
515   }
516 
517   free(length_array);
518   free(path);
519   ZopfliCleanLZ77Store(&currentstore);
520 }
521 
ZopfliLZ77OptimalFixed(ZopfliBlockState * s,const unsigned char * in,size_t instart,size_t inend,ZopfliLZ77Store * store)522 void ZopfliLZ77OptimalFixed(ZopfliBlockState *s,
523                             const unsigned char* in,
524                             size_t instart, size_t inend,
525                             ZopfliLZ77Store* store)
526 {
527   /* Dist to get to here with smallest cost. */
528   size_t blocksize = inend - instart;
529   unsigned short* length_array =
530       (unsigned short*)malloc(sizeof(unsigned short) * (blocksize + 1));
531   unsigned short* path = 0;
532   size_t pathsize = 0;
533 
534   if (!length_array) exit(-1); /* Allocation failed. */
535 
536   s->blockstart = instart;
537   s->blockend = inend;
538 
539   /* Shortest path for fixed tree This one should give the shortest possible
540   result for fixed tree, no repeated runs are needed since the tree is known. */
541   LZ77OptimalRun(s, in, instart, inend, &path, &pathsize,
542                  length_array, GetCostFixed, 0, store);
543 
544   free(length_array);
545   free(path);
546 }
547