• 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 "lz77.h"
21 #include "util.h"
22 
23 #include <assert.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 
ZopfliInitLZ77Store(ZopfliLZ77Store * store)27 void ZopfliInitLZ77Store(ZopfliLZ77Store* store) {
28   store->size = 0;
29   store->litlens = 0;
30   store->dists = 0;
31 }
32 
ZopfliCleanLZ77Store(ZopfliLZ77Store * store)33 void ZopfliCleanLZ77Store(ZopfliLZ77Store* store) {
34   free(store->litlens);
35   free(store->dists);
36 }
37 
ZopfliCopyLZ77Store(const ZopfliLZ77Store * source,ZopfliLZ77Store * dest)38 void ZopfliCopyLZ77Store(
39     const ZopfliLZ77Store* source, ZopfliLZ77Store* dest) {
40   size_t i;
41   ZopfliCleanLZ77Store(dest);
42   dest->litlens =
43       (unsigned short*)malloc(sizeof(*dest->litlens) * source->size);
44   dest->dists = (unsigned short*)malloc(sizeof(*dest->dists) * source->size);
45 
46   if (!dest->litlens || !dest->dists) exit(-1); /* Allocation failed. */
47 
48   dest->size = source->size;
49   for (i = 0; i < source->size; i++) {
50     dest->litlens[i] = source->litlens[i];
51     dest->dists[i] = source->dists[i];
52   }
53 }
54 
55 /*
56 Appends the length and distance to the LZ77 arrays of the ZopfliLZ77Store.
57 context must be a ZopfliLZ77Store*.
58 */
ZopfliStoreLitLenDist(unsigned short length,unsigned short dist,ZopfliLZ77Store * store)59 void ZopfliStoreLitLenDist(unsigned short length, unsigned short dist,
60                            ZopfliLZ77Store* store) {
61   size_t size2 = store->size;  /* Needed for using ZOPFLI_APPEND_DATA twice. */
62   ZOPFLI_APPEND_DATA(length, &store->litlens, &store->size);
63   ZOPFLI_APPEND_DATA(dist, &store->dists, &size2);
64 }
65 
66 /*
67 Gets a score of the length given the distance. Typically, the score of the
68 length is the length itself, but if the distance is very long, decrease the
69 score of the length a bit to make up for the fact that long distances use large
70 amounts of extra bits.
71 
72 This is not an accurate score, it is a heuristic only for the greedy LZ77
73 implementation. More accurate cost models are employed later. Making this
74 heuristic more accurate may hurt rather than improve compression.
75 
76 The two direct uses of this heuristic are:
77 -avoid using a length of 3 in combination with a long distance. This only has
78  an effect if length == 3.
79 -make a slightly better choice between the two options of the lazy matching.
80 
81 Indirectly, this affects:
82 -the block split points if the default of block splitting first is used, in a
83  rather unpredictable way
84 -the first zopfli run, so it affects the chance of the first run being closer
85  to the optimal output
86 */
GetLengthScore(int length,int distance)87 static int GetLengthScore(int length, int distance) {
88   /*
89   At 1024, the distance uses 9+ extra bits and this seems to be the sweet spot
90   on tested files.
91   */
92   return distance > 1024 ? length - 1 : length;
93 }
94 
ZopfliVerifyLenDist(const unsigned char * data,size_t datasize,size_t pos,unsigned short dist,unsigned short length)95 void ZopfliVerifyLenDist(const unsigned char* data, size_t datasize, size_t pos,
96                          unsigned short dist, unsigned short length) {
97 
98   /* TODO(lode): make this only run in a debug compile, it's for assert only. */
99   size_t i;
100 
101   assert(pos + length <= datasize);
102   for (i = 0; i < length; i++) {
103     if (data[pos - dist + i] != data[pos + i]) {
104       assert(data[pos - dist + i] == data[pos + i]);
105       break;
106     }
107   }
108 }
109 
110 /*
111 Finds how long the match of scan and match is. Can be used to find how many
112 bytes starting from scan, and from match, are equal. Returns the last byte
113 after scan, which is still equal to the correspondinb byte after match.
114 scan is the position to compare
115 match is the earlier position to compare.
116 end is the last possible byte, beyond which to stop looking.
117 safe_end is a few (8) bytes before end, for comparing multiple bytes at once.
118 */
GetMatch(const unsigned char * scan,const unsigned char * match,const unsigned char * end,const unsigned char * safe_end)119 static const unsigned char* GetMatch(const unsigned char* scan,
120                                      const unsigned char* match,
121                                      const unsigned char* end,
122                                      const unsigned char* safe_end) {
123 
124   if (sizeof(size_t) == 8) {
125     /* 8 checks at once per array bounds check (size_t is 64-bit). */
126     while (scan < safe_end && *((size_t*)scan) == *((size_t*)match)) {
127       scan += 8;
128       match += 8;
129     }
130   } else if (sizeof(unsigned int) == 4) {
131     /* 4 checks at once per array bounds check (unsigned int is 32-bit). */
132     while (scan < safe_end
133         && *((unsigned int*)scan) == *((unsigned int*)match)) {
134       scan += 4;
135       match += 4;
136     }
137   } else {
138     /* do 8 checks at once per array bounds check. */
139     while (scan < safe_end && *scan == *match && *++scan == *++match
140           && *++scan == *++match && *++scan == *++match
141           && *++scan == *++match && *++scan == *++match
142           && *++scan == *++match && *++scan == *++match) {
143       scan++; match++;
144     }
145   }
146 
147   /* The remaining few bytes. */
148   while (scan != end && *scan == *match) {
149     scan++; match++;
150   }
151 
152   return scan;
153 }
154 
155 #ifdef ZOPFLI_LONGEST_MATCH_CACHE
156 /*
157 Gets distance, length and sublen values from the cache if possible.
158 Returns 1 if it got the values from the cache, 0 if not.
159 Updates the limit value to a smaller one if possible with more limited
160 information from the cache.
161 */
TryGetFromLongestMatchCache(ZopfliBlockState * s,size_t pos,size_t * limit,unsigned short * sublen,unsigned short * distance,unsigned short * length)162 static int TryGetFromLongestMatchCache(ZopfliBlockState* s,
163     size_t pos, size_t* limit,
164     unsigned short* sublen, unsigned short* distance, unsigned short* length) {
165   /* The LMC cache starts at the beginning of the block rather than the
166      beginning of the whole array. */
167   size_t lmcpos = pos - s->blockstart;
168 
169   /* Length > 0 and dist 0 is invalid combination, which indicates on purpose
170      that this cache value is not filled in yet. */
171   unsigned char cache_available = s->lmc && (s->lmc->length[lmcpos] == 0 ||
172       s->lmc->dist[lmcpos] != 0);
173   unsigned char limit_ok_for_cache = cache_available &&
174       (*limit == ZOPFLI_MAX_MATCH || s->lmc->length[lmcpos] <= *limit ||
175       (sublen && ZopfliMaxCachedSublen(s->lmc,
176           lmcpos, s->lmc->length[lmcpos]) >= *limit));
177 
178   if (s->lmc && limit_ok_for_cache && cache_available) {
179     if (!sublen || s->lmc->length[lmcpos]
180         <= ZopfliMaxCachedSublen(s->lmc, lmcpos, s->lmc->length[lmcpos])) {
181       *length = s->lmc->length[lmcpos];
182       if (*length > *limit) *length = *limit;
183       if (sublen) {
184         ZopfliCacheToSublen(s->lmc, lmcpos, *length, sublen);
185         *distance = sublen[*length];
186         if (*limit == ZOPFLI_MAX_MATCH && *length >= ZOPFLI_MIN_MATCH) {
187           assert(sublen[*length] == s->lmc->dist[lmcpos]);
188         }
189       } else {
190         *distance = s->lmc->dist[lmcpos];
191       }
192       return 1;
193     }
194     /* Can't use much of the cache, since the "sublens" need to be calculated,
195        but at  least we already know when to stop. */
196     *limit = s->lmc->length[lmcpos];
197   }
198 
199   return 0;
200 }
201 
202 /*
203 Stores the found sublen, distance and length in the longest match cache, if
204 possible.
205 */
StoreInLongestMatchCache(ZopfliBlockState * s,size_t pos,size_t limit,const unsigned short * sublen,unsigned short distance,unsigned short length)206 static void StoreInLongestMatchCache(ZopfliBlockState* s,
207     size_t pos, size_t limit,
208     const unsigned short* sublen,
209     unsigned short distance, unsigned short length) {
210   /* The LMC cache starts at the beginning of the block rather than the
211      beginning of the whole array. */
212   size_t lmcpos = pos - s->blockstart;
213 
214   /* Length > 0 and dist 0 is invalid combination, which indicates on purpose
215      that this cache value is not filled in yet. */
216   unsigned char cache_available = s->lmc && (s->lmc->length[lmcpos] == 0 ||
217       s->lmc->dist[lmcpos] != 0);
218 
219   if (s->lmc && limit == ZOPFLI_MAX_MATCH && sublen && !cache_available) {
220     assert(s->lmc->length[lmcpos] == 1 && s->lmc->dist[lmcpos] == 0);
221     s->lmc->dist[lmcpos] = length < ZOPFLI_MIN_MATCH ? 0 : distance;
222     s->lmc->length[lmcpos] = length < ZOPFLI_MIN_MATCH ? 0 : length;
223     assert(!(s->lmc->length[lmcpos] == 1 && s->lmc->dist[lmcpos] == 0));
224     ZopfliSublenToCache(sublen, lmcpos, length, s->lmc);
225   }
226 }
227 #endif
228 
ZopfliFindLongestMatch(ZopfliBlockState * s,const ZopfliHash * h,const unsigned char * array,size_t pos,size_t size,size_t limit,unsigned short * sublen,unsigned short * distance,unsigned short * length)229 void ZopfliFindLongestMatch(ZopfliBlockState* s, const ZopfliHash* h,
230     const unsigned char* array,
231     size_t pos, size_t size, size_t limit,
232     unsigned short* sublen, unsigned short* distance, unsigned short* length) {
233   unsigned short hpos = pos & ZOPFLI_WINDOW_MASK, p, pp;
234   unsigned short bestdist = 0;
235   unsigned short bestlength = 1;
236   const unsigned char* scan;
237   const unsigned char* match;
238   const unsigned char* arrayend;
239   const unsigned char* arrayend_safe;
240 #if ZOPFLI_MAX_CHAIN_HITS < ZOPFLI_WINDOW_SIZE
241   int chain_counter = ZOPFLI_MAX_CHAIN_HITS;  /* For quitting early. */
242 #endif
243 
244   unsigned dist = 0;  /* Not unsigned short on purpose. */
245 
246   int* hhead = h->head;
247   unsigned short* hprev = h->prev;
248   int* hhashval = h->hashval;
249   int hval = h->val;
250 
251 #ifdef ZOPFLI_LONGEST_MATCH_CACHE
252   if (TryGetFromLongestMatchCache(s, pos, &limit, sublen, distance, length)) {
253     assert(pos + *length <= size);
254     return;
255   }
256 #endif
257 
258   assert(limit <= ZOPFLI_MAX_MATCH);
259   assert(limit >= ZOPFLI_MIN_MATCH);
260   assert(pos < size);
261 
262   if (size - pos < ZOPFLI_MIN_MATCH) {
263     /* The rest of the code assumes there are at least ZOPFLI_MIN_MATCH bytes to
264        try. */
265     *length = 0;
266     *distance = 0;
267     return;
268   }
269 
270   if (pos + limit > size) {
271     limit = size - pos;
272   }
273   arrayend = &array[pos] + limit;
274   arrayend_safe = arrayend - 8;
275 
276   assert(hval < 65536);
277 
278   pp = hhead[hval];  /* During the whole loop, p == hprev[pp]. */
279   p = hprev[pp];
280 
281   assert(pp == hpos);
282 
283   dist = p < pp ? pp - p : ((ZOPFLI_WINDOW_SIZE - p) + pp);
284 
285   /* Go through all distances. */
286   while (dist < ZOPFLI_WINDOW_SIZE) {
287     unsigned short currentlength = 0;
288 
289     assert(p < ZOPFLI_WINDOW_SIZE);
290     assert(p == hprev[pp]);
291     assert(hhashval[p] == hval);
292 
293     if (dist > 0) {
294       assert(pos < size);
295       assert(dist <= pos);
296       scan = &array[pos];
297       match = &array[pos - dist];
298 
299       /* Testing the byte at position bestlength first, goes slightly faster. */
300       if (pos + bestlength >= size
301           || *(scan + bestlength) == *(match + bestlength)) {
302 
303 #ifdef ZOPFLI_HASH_SAME
304         unsigned short same0 = h->same[pos & ZOPFLI_WINDOW_MASK];
305         if (same0 > 2 && *scan == *match) {
306           unsigned short same1 = h->same[(pos - dist) & ZOPFLI_WINDOW_MASK];
307           unsigned short same = same0 < same1 ? same0 : same1;
308           if (same > limit) same = limit;
309           scan += same;
310           match += same;
311         }
312 #endif
313         scan = GetMatch(scan, match, arrayend, arrayend_safe);
314         currentlength = scan - &array[pos];  /* The found length. */
315       }
316 
317       if (currentlength > bestlength) {
318         if (sublen) {
319           unsigned short j;
320           for (j = bestlength + 1; j <= currentlength; j++) {
321             sublen[j] = dist;
322           }
323         }
324         bestdist = dist;
325         bestlength = currentlength;
326         if (currentlength >= limit) break;
327       }
328     }
329 
330 
331 #ifdef ZOPFLI_HASH_SAME_HASH
332     /* Switch to the other hash once this will be more efficient. */
333     if (hhead != h->head2 && bestlength >= h->same[hpos] &&
334         h->val2 == h->hashval2[p]) {
335       /* Now use the hash that encodes the length and first byte. */
336       hhead = h->head2;
337       hprev = h->prev2;
338       hhashval = h->hashval2;
339       hval = h->val2;
340     }
341 #endif
342 
343     pp = p;
344     p = hprev[p];
345     if (p == pp) break;  /* Uninited prev value. */
346 
347     dist += p < pp ? pp - p : ((ZOPFLI_WINDOW_SIZE - p) + pp);
348 
349 #if ZOPFLI_MAX_CHAIN_HITS < ZOPFLI_WINDOW_SIZE
350     chain_counter--;
351     if (chain_counter <= 0) break;
352 #endif
353   }
354 
355 #ifdef ZOPFLI_LONGEST_MATCH_CACHE
356   StoreInLongestMatchCache(s, pos, limit, sublen, bestdist, bestlength);
357 #endif
358 
359   assert(bestlength <= limit);
360 
361   *distance = bestdist;
362   *length = bestlength;
363   assert(pos + *length <= size);
364 }
365 
ZopfliLZ77Greedy(ZopfliBlockState * s,const unsigned char * in,size_t instart,size_t inend,ZopfliLZ77Store * store)366 void ZopfliLZ77Greedy(ZopfliBlockState* s, const unsigned char* in,
367                       size_t instart, size_t inend,
368                       ZopfliLZ77Store* store) {
369   size_t i = 0, j;
370   unsigned short leng;
371   unsigned short dist;
372   int lengthscore;
373   size_t windowstart = instart > ZOPFLI_WINDOW_SIZE
374       ? instart - ZOPFLI_WINDOW_SIZE : 0;
375   unsigned short dummysublen[259];
376 
377   ZopfliHash hash;
378   ZopfliHash* h = &hash;
379 
380 #ifdef ZOPFLI_LAZY_MATCHING
381   /* Lazy matching. */
382   unsigned prev_length = 0;
383   unsigned prev_match = 0;
384   int prevlengthscore;
385   int match_available = 0;
386 #endif
387 
388   if (instart == inend) return;
389 
390   ZopfliInitHash(ZOPFLI_WINDOW_SIZE, h);
391   ZopfliWarmupHash(in, windowstart, inend, h);
392   for (i = windowstart; i < instart; i++) {
393     ZopfliUpdateHash(in, i, inend, h);
394   }
395 
396   for (i = instart; i < inend; i++) {
397     ZopfliUpdateHash(in, i, inend, h);
398 
399     ZopfliFindLongestMatch(s, h, in, i, inend, ZOPFLI_MAX_MATCH, dummysublen,
400                            &dist, &leng);
401     lengthscore = GetLengthScore(leng, dist);
402 
403 #ifdef ZOPFLI_LAZY_MATCHING
404     /* Lazy matching. */
405     prevlengthscore = GetLengthScore(prev_length, prev_match);
406     if (match_available) {
407       match_available = 0;
408       if (lengthscore > prevlengthscore + 1) {
409         ZopfliStoreLitLenDist(in[i - 1], 0, store);
410         if (lengthscore >= ZOPFLI_MIN_MATCH && leng < ZOPFLI_MAX_MATCH) {
411           match_available = 1;
412           prev_length = leng;
413           prev_match = dist;
414           continue;
415         }
416       } else {
417         /* Add previous to output. */
418         leng = prev_length;
419         dist = prev_match;
420         lengthscore = prevlengthscore;
421         /* Add to output. */
422         ZopfliVerifyLenDist(in, inend, i - 1, dist, leng);
423         ZopfliStoreLitLenDist(leng, dist, store);
424         for (j = 2; j < leng; j++) {
425           assert(i < inend);
426           i++;
427           ZopfliUpdateHash(in, i, inend, h);
428         }
429         continue;
430       }
431     }
432     else if (lengthscore >= ZOPFLI_MIN_MATCH && leng < ZOPFLI_MAX_MATCH) {
433       match_available = 1;
434       prev_length = leng;
435       prev_match = dist;
436       continue;
437     }
438     /* End of lazy matching. */
439 #endif
440 
441     /* Add to output. */
442     if (lengthscore >= ZOPFLI_MIN_MATCH) {
443       ZopfliVerifyLenDist(in, inend, i, dist, leng);
444       ZopfliStoreLitLenDist(leng, dist, store);
445     } else {
446       leng = 1;
447       ZopfliStoreLitLenDist(in[i], 0, store);
448     }
449     for (j = 1; j < leng; j++) {
450       assert(i < inend);
451       i++;
452       ZopfliUpdateHash(in, i, inend, h);
453     }
454   }
455 
456   ZopfliCleanHash(h);
457 }
458 
ZopfliLZ77Counts(const unsigned short * litlens,const unsigned short * dists,size_t start,size_t end,size_t * ll_count,size_t * d_count)459 void ZopfliLZ77Counts(const unsigned short* litlens,
460                       const unsigned short* dists,
461                       size_t start, size_t end,
462                       size_t* ll_count, size_t* d_count) {
463   size_t i;
464 
465   for (i = 0; i < 288; i++) {
466     ll_count[i] = 0;
467   }
468   for (i = 0; i < 32; i++) {
469     d_count[i] = 0;
470   }
471 
472   for (i = start; i < end; i++) {
473     if (dists[i] == 0) {
474       ll_count[litlens[i]]++;
475     } else {
476       ll_count[ZopfliGetLengthSymbol(litlens[i])]++;
477       d_count[ZopfliGetDistSymbol(dists[i])]++;
478     }
479   }
480 
481   ll_count[256] = 1;  /* End symbol. */
482 }
483