1 /*
2     LZ4 HC - High Compression Mode of LZ4
3     Copyright (C) 2011-2020, Yann Collet.
4 
5     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 
7     Redistribution and use in source and binary forms, with or without
8     modification, are permitted provided that the following conditions are
9     met:
10 
11     * Redistributions of source code must retain the above copyright
12     notice, this list of conditions and the following disclaimer.
13     * Redistributions in binary form must reproduce the above
14     copyright notice, this list of conditions and the following disclaimer
15     in the documentation and/or other materials provided with the
16     distribution.
17 
18     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22     OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30     You can contact the author at :
31        - LZ4 source repository : https://github.com/lz4/lz4
32        - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
33 */
34 /* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
35 
36 
37 /* *************************************
38 *  Tuning Parameter
39 ***************************************/
40 
41 /*! HEAPMODE :
42  *  Select how default compression function will allocate workplace memory,
43  *  in stack (0:fastest), or in heap (1:requires malloc()).
44  *  Since workplace is rather large, heap mode is recommended.
45  */
46 #ifndef LZ4HC_HEAPMODE
47 #  define LZ4HC_HEAPMODE 1
48 #endif
49 
50 
51 /*===    Dependency    ===*/
52 #define LZ4_HC_STATIC_LINKING_ONLY
53 #include "lz4hc.h"
54 
55 
56 /*===   Common definitions   ===*/
57 #if defined(__GNUC__)
58 #  pragma GCC diagnostic ignored "-Wunused-function"
59 #endif
60 #if defined (__clang__)
61 #  pragma clang diagnostic ignored "-Wunused-function"
62 #endif
63 
64 #define LZ4_COMMONDEFS_ONLY
65 #ifndef LZ4_SRC_INCLUDED
66 #include "lz4.c"   /* LZ4_count, constants, mem */
67 #endif
68 
69 
70 /*===   Enums   ===*/
71 typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
72 
73 
74 /*===   Constants   ===*/
75 #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
76 #define LZ4_OPT_NUM   (1<<12)
77 
78 
79 /*===   Macros   ===*/
80 #define MIN(a,b)   ( (a) < (b) ? (a) : (b) )
81 #define MAX(a,b)   ( (a) > (b) ? (a) : (b) )
82 #define HASH_FUNCTION(i)         (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
83 #define DELTANEXTMAXD(p)         chainTable[(p) & LZ4HC_MAXD_MASK]    /* flexible, LZ4HC_MAXD dependent */
84 #define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */
85 /* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
86 #define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
87 
LZ4HC_hashPtr(const void * ptr)88 static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
89 
90 
91 /**************************************
92 *  HC Compression
93 **************************************/
LZ4HC_clearTables(LZ4HC_CCtx_internal * hc4)94 static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
95 {
96     MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));
97     MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
98 }
99 
LZ4HC_init_internal(LZ4HC_CCtx_internal * hc4,const BYTE * start)100 static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
101 {
102     uptrval startingOffset = (uptrval)(hc4->end - hc4->base);
103     if (startingOffset > 1 GB) {
104         LZ4HC_clearTables(hc4);
105         startingOffset = 0;
106     }
107     startingOffset += 64 KB;
108     hc4->nextToUpdate = (U32) startingOffset;
109     hc4->base = start - startingOffset;
110     hc4->end = start;
111     hc4->dictBase = start - startingOffset;
112     hc4->dictLimit = (U32) startingOffset;
113     hc4->lowLimit = (U32) startingOffset;
114 }
115 
116 
117 /* Update chains up to ip (excluded) */
LZ4HC_Insert(LZ4HC_CCtx_internal * hc4,const BYTE * ip)118 LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
119 {
120     U16* const chainTable = hc4->chainTable;
121     U32* const hashTable  = hc4->hashTable;
122     const BYTE* const base = hc4->base;
123     U32 const target = (U32)(ip - base);
124     U32 idx = hc4->nextToUpdate;
125 
126     while (idx < target) {
127         U32 const h = LZ4HC_hashPtr(base+idx);
128         size_t delta = idx - hashTable[h];
129         if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
130         DELTANEXTU16(chainTable, idx) = (U16)delta;
131         hashTable[h] = idx;
132         idx++;
133     }
134 
135     hc4->nextToUpdate = target;
136 }
137 
138 /** LZ4HC_countBack() :
139  * @return : negative value, nb of common bytes before ip/match */
140 LZ4_FORCE_INLINE
LZ4HC_countBack(const BYTE * const ip,const BYTE * const match,const BYTE * const iMin,const BYTE * const mMin)141 int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
142                     const BYTE* const iMin, const BYTE* const mMin)
143 {
144     int back = 0;
145     int const min = (int)MAX(iMin - ip, mMin - match);
146     assert(min <= 0);
147     assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
148     assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
149     while ( (back > min)
150          && (ip[back-1] == match[back-1]) )
151             back--;
152     return back;
153 }
154 
155 #if defined(_MSC_VER)
156 #  define LZ4HC_rotl32(x,r) _rotl(x,r)
157 #else
158 #  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))
159 #endif
160 
161 
LZ4HC_rotatePattern(size_t const rotate,U32 const pattern)162 static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)
163 {
164     size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;
165     if (bitsToRotate == 0) return pattern;
166     return LZ4HC_rotl32(pattern, (int)bitsToRotate);
167 }
168 
169 /* LZ4HC_countPattern() :
170  * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
171 static unsigned
LZ4HC_countPattern(const BYTE * ip,const BYTE * const iEnd,U32 const pattern32)172 LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
173 {
174     const BYTE* const iStart = ip;
175     reg_t const pattern = (sizeof(pattern)==8) ?
176         (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;
177 
178     while (likely(ip < iEnd-(sizeof(pattern)-1))) {
179         reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;
180         if (!diff) { ip+=sizeof(pattern); continue; }
181         ip += LZ4_NbCommonBytes(diff);
182         return (unsigned)(ip - iStart);
183     }
184 
185     if (LZ4_isLittleEndian()) {
186         reg_t patternByte = pattern;
187         while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {
188             ip++; patternByte >>= 8;
189         }
190     } else {  /* big endian */
191         U32 bitOffset = (sizeof(pattern)*8) - 8;
192         while (ip < iEnd) {
193             BYTE const byte = (BYTE)(pattern >> bitOffset);
194             if (*ip != byte) break;
195             ip ++; bitOffset -= 8;
196         }
197     }
198 
199     return (unsigned)(ip - iStart);
200 }
201 
202 /* LZ4HC_reverseCountPattern() :
203  * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
204  * read using natural platform endianess */
205 static unsigned
LZ4HC_reverseCountPattern(const BYTE * ip,const BYTE * const iLow,U32 pattern)206 LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
207 {
208     const BYTE* const iStart = ip;
209 
210     while (likely(ip >= iLow+4)) {
211         if (LZ4_read32(ip-4) != pattern) break;
212         ip -= 4;
213     }
214     {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */
215         while (likely(ip>iLow)) {
216             if (ip[-1] != *bytePtr) break;
217             ip--; bytePtr--;
218     }   }
219     return (unsigned)(iStart - ip);
220 }
221 
222 /* LZ4HC_protectDictEnd() :
223  * Checks if the match is in the last 3 bytes of the dictionary, so reading the
224  * 4 byte MINMATCH would overflow.
225  * @returns true if the match index is okay.
226  */
LZ4HC_protectDictEnd(U32 const dictLimit,U32 const matchIndex)227 static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
228 {
229     return ((U32)((dictLimit - 1) - matchIndex) >= 3);
230 }
231 
232 typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
233 typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
234 
235 LZ4_FORCE_INLINE int
LZ4HC_InsertAndGetWiderMatch(LZ4HC_CCtx_internal * hc4,const BYTE * const ip,const BYTE * const iLowLimit,const BYTE * const iHighLimit,int longest,const BYTE ** matchpos,const BYTE ** startpos,const int maxNbAttempts,const int patternAnalysis,const int chainSwap,const dictCtx_directive dict,const HCfavor_e favorDecSpeed)236 LZ4HC_InsertAndGetWiderMatch (
237     LZ4HC_CCtx_internal* hc4,
238     const BYTE* const ip,
239     const BYTE* const iLowLimit,
240     const BYTE* const iHighLimit,
241     int longest,
242     const BYTE** matchpos,
243     const BYTE** startpos,
244     const int maxNbAttempts,
245     const int patternAnalysis,
246     const int chainSwap,
247     const dictCtx_directive dict,
248     const HCfavor_e favorDecSpeed)
249 {
250     U16* const chainTable = hc4->chainTable;
251     U32* const HashTable = hc4->hashTable;
252     const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
253     const BYTE* const base = hc4->base;
254     const U32 dictLimit = hc4->dictLimit;
255     const BYTE* const lowPrefixPtr = base + dictLimit;
256     const U32 ipIndex = (U32)(ip - base);
257     const U32 lowestMatchIndex = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
258     const BYTE* const dictBase = hc4->dictBase;
259     int const lookBackLength = (int)(ip-iLowLimit);
260     int nbAttempts = maxNbAttempts;
261     U32 matchChainPos = 0;
262     U32 const pattern = LZ4_read32(ip);
263     U32 matchIndex;
264     repeat_state_e repeat = rep_untested;
265     size_t srcPatternLength = 0;
266 
267     DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
268     /* First Match */
269     LZ4HC_Insert(hc4, ip);
270     matchIndex = HashTable[LZ4HC_hashPtr(ip)];
271     DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
272                 matchIndex, lowestMatchIndex);
273 
274     while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
275         int matchLength=0;
276         nbAttempts--;
277         assert(matchIndex < ipIndex);
278         if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
279             /* do nothing */
280         } else if (matchIndex >= dictLimit) {   /* within current Prefix */
281             const BYTE* const matchPtr = base + matchIndex;
282             assert(matchPtr >= lowPrefixPtr);
283             assert(matchPtr < ip);
284             assert(longest >= 1);
285             if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
286                 if (LZ4_read32(matchPtr) == pattern) {
287                     int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, lowPrefixPtr) : 0;
288                     matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
289                     matchLength -= back;
290                     if (matchLength > longest) {
291                         longest = matchLength;
292                         *matchpos = matchPtr + back;
293                         *startpos = ip + back;
294             }   }   }
295         } else {   /* lowestMatchIndex <= matchIndex < dictLimit */
296             const BYTE* const matchPtr = dictBase + matchIndex;
297             if (LZ4_read32(matchPtr) == pattern) {
298                 const BYTE* const dictStart = dictBase + hc4->lowLimit;
299                 int back = 0;
300                 const BYTE* vLimit = ip + (dictLimit - matchIndex);
301                 if (vLimit > iHighLimit) vLimit = iHighLimit;
302                 matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
303                 if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
304                     matchLength += LZ4_count(ip+matchLength, lowPrefixPtr, iHighLimit);
305                 back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
306                 matchLength -= back;
307                 if (matchLength > longest) {
308                     longest = matchLength;
309                     *matchpos = base + matchIndex + back;   /* virtual pos, relative to ip, to retrieve offset */
310                     *startpos = ip + back;
311         }   }   }
312 
313         if (chainSwap && matchLength==longest) {    /* better match => select a better chain */
314             assert(lookBackLength==0);   /* search forward only */
315             if (matchIndex + (U32)longest <= ipIndex) {
316                 int const kTrigger = 4;
317                 U32 distanceToNextMatch = 1;
318                 int const end = longest - MINMATCH + 1;
319                 int step = 1;
320                 int accel = 1 << kTrigger;
321                 int pos;
322                 for (pos = 0; pos < end; pos += step) {
323                     U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
324                     step = (accel++ >> kTrigger);
325                     if (candidateDist > distanceToNextMatch) {
326                         distanceToNextMatch = candidateDist;
327                         matchChainPos = (U32)pos;
328                         accel = 1 << kTrigger;
329                     }
330                 }
331                 if (distanceToNextMatch > 1) {
332                     if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */
333                     matchIndex -= distanceToNextMatch;
334                     continue;
335         }   }   }
336 
337         {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
338             if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
339                 U32 const matchCandidateIdx = matchIndex-1;
340                 /* may be a repeated pattern */
341                 if (repeat == rep_untested) {
342                     if ( ((pattern & 0xFFFF) == (pattern >> 16))
343                       &  ((pattern & 0xFF)   == (pattern >> 24)) ) {
344                         repeat = rep_confirmed;
345                         srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
346                     } else {
347                         repeat = rep_not;
348                 }   }
349                 if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
350                   && LZ4HC_protectDictEnd(dictLimit, matchCandidateIdx) ) {
351                     const int extDict = matchCandidateIdx < dictLimit;
352                     const BYTE* const matchPtr = (extDict ? dictBase : base) + matchCandidateIdx;
353                     if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */
354                         const BYTE* const dictStart = dictBase + hc4->lowLimit;
355                         const BYTE* const iLimit = extDict ? dictBase + dictLimit : iHighLimit;
356                         size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
357                         if (extDict && matchPtr + forwardPatternLength == iLimit) {
358                             U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
359                             forwardPatternLength += LZ4HC_countPattern(lowPrefixPtr, iHighLimit, rotatedPattern);
360                         }
361                         {   const BYTE* const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr;
362                             size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
363                             size_t currentSegmentLength;
364                             if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) {
365                                 U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
366                                 backLength += LZ4HC_reverseCountPattern(dictBase + dictLimit, dictStart, rotatedPattern);
367                             }
368                             /* Limit backLength not go further than lowestMatchIndex */
369                             backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
370                             assert(matchCandidateIdx - backLength >= lowestMatchIndex);
371                             currentSegmentLength = backLength + forwardPatternLength;
372                             /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */
373                             if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */
374                               && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
375                                 U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */
376                                 if (LZ4HC_protectDictEnd(dictLimit, newMatchIndex))
377                                     matchIndex = newMatchIndex;
378                                 else {
379                                     /* Can only happen if started in the prefix */
380                                     assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);
381                                     matchIndex = dictLimit;
382                                 }
383                             } else {
384                                 U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */
385                                 if (!LZ4HC_protectDictEnd(dictLimit, newMatchIndex)) {
386                                     assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);
387                                     matchIndex = dictLimit;
388                                 } else {
389                                     matchIndex = newMatchIndex;
390                                     if (lookBackLength==0) {  /* no back possible */
391                                         size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
392                                         if ((size_t)longest < maxML) {
393                                             assert(base + matchIndex != ip);
394                                             if ((size_t)(ip - base) - matchIndex > LZ4_DISTANCE_MAX) break;
395                                             assert(maxML < 2 GB);
396                                             longest = (int)maxML;
397                                             *matchpos = base + matchIndex;   /* virtual pos, relative to ip, to retrieve offset */
398                                             *startpos = ip;
399                                         }
400                                         {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
401                                             if (distToNextPattern > matchIndex) break;  /* avoid overflow */
402                                             matchIndex -= distToNextPattern;
403                         }   }   }   }   }
404                         continue;
405                 }   }
406         }   }   /* PA optimization */
407 
408         /* follow current chain */
409         matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
410 
411     }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
412 
413     if ( dict == usingDictCtxHc
414       && nbAttempts > 0
415       && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
416         size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);
417         U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
418         assert(dictEndOffset <= 1 GB);
419         matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
420         while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
421             const BYTE* const matchPtr = dictCtx->base + dictMatchIndex;
422 
423             if (LZ4_read32(matchPtr) == pattern) {
424                 int mlt;
425                 int back = 0;
426                 const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
427                 if (vLimit > iHighLimit) vLimit = iHighLimit;
428                 mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
429                 back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->base + dictCtx->dictLimit) : 0;
430                 mlt -= back;
431                 if (mlt > longest) {
432                     longest = mlt;
433                     *matchpos = base + matchIndex + back;
434                     *startpos = ip + back;
435             }   }
436 
437             {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
438                 dictMatchIndex -= nextOffset;
439                 matchIndex -= nextOffset;
440     }   }   }
441 
442     return longest;
443 }
444 
445 LZ4_FORCE_INLINE
LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal * const hc4,const BYTE * const ip,const BYTE * const iLimit,const BYTE ** matchpos,const int maxNbAttempts,const int patternAnalysis,const dictCtx_directive dict)446 int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */
447                                  const BYTE* const ip, const BYTE* const iLimit,
448                                  const BYTE** matchpos,
449                                  const int maxNbAttempts,
450                                  const int patternAnalysis,
451                                  const dictCtx_directive dict)
452 {
453     const BYTE* uselessPtr = ip;
454     /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
455      * but this won't be the case here, as we define iLowLimit==ip,
456      * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
457     return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
458 }
459 
460 /* LZ4HC_encodeSequence() :
461  * @return : 0 if ok,
462  *           1 if buffer issue detected */
LZ4HC_encodeSequence(const BYTE ** _ip,BYTE ** _op,const BYTE ** _anchor,int matchLength,const BYTE * const match,limitedOutput_directive limit,BYTE * oend)463 LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
464     const BYTE** _ip,
465     BYTE** _op,
466     const BYTE** _anchor,
467     int matchLength,
468     const BYTE* const match,
469     limitedOutput_directive limit,
470     BYTE* oend)
471 {
472 #define ip      (*_ip)
473 #define op      (*_op)
474 #define anchor  (*_anchor)
475 
476     size_t length;
477     BYTE* const token = op++;
478 
479 #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
480     static const BYTE* start = NULL;
481     static U32 totalCost = 0;
482     U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
483     U32 const ll = (U32)(ip - anchor);
484     U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
485     U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
486     U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
487     if (start==NULL) start = anchor;  /* only works for single segment */
488     /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
489     DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
490                 pos,
491                 (U32)(ip - anchor), matchLength, (U32)(ip-match),
492                 cost, totalCost);
493     totalCost += cost;
494 #endif
495 
496     /* Encode Literal length */
497     length = (size_t)(ip - anchor);
498     LZ4_STATIC_ASSERT(notLimited == 0);
499     /* Check output limit */
500     if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
501         DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
502                 (int)length, (int)(oend - op));
503         return 1;
504     }
505     if (length >= RUN_MASK) {
506         size_t len = length - RUN_MASK;
507         *token = (RUN_MASK << ML_BITS);
508         for(; len >= 255 ; len -= 255) *op++ = 255;
509         *op++ = (BYTE)len;
510     } else {
511         *token = (BYTE)(length << ML_BITS);
512     }
513 
514     /* Copy Literals */
515     LZ4_wildCopy8(op, anchor, op + length);
516     op += length;
517 
518     /* Encode Offset */
519     assert( (ip - match) <= LZ4_DISTANCE_MAX );   /* note : consider providing offset as a value, rather than as a pointer difference */
520     LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
521 
522     /* Encode MatchLength */
523     assert(matchLength >= MINMATCH);
524     length = (size_t)matchLength - MINMATCH;
525     if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
526         DEBUGLOG(6, "Not enough room to write match length");
527         return 1;   /* Check output limit */
528     }
529     if (length >= ML_MASK) {
530         *token += ML_MASK;
531         length -= ML_MASK;
532         for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
533         if (length >= 255) { length -= 255; *op++ = 255; }
534         *op++ = (BYTE)length;
535     } else {
536         *token += (BYTE)(length);
537     }
538 
539     /* Prepare next loop */
540     ip += matchLength;
541     anchor = ip;
542 
543     return 0;
544 }
545 #undef ip
546 #undef op
547 #undef anchor
548 
LZ4HC_compress_hashChain(LZ4HC_CCtx_internal * const ctx,const char * const source,char * const dest,int * srcSizePtr,int const maxOutputSize,int maxNbAttempts,const limitedOutput_directive limit,const dictCtx_directive dict)549 LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
550     LZ4HC_CCtx_internal* const ctx,
551     const char* const source,
552     char* const dest,
553     int* srcSizePtr,
554     int const maxOutputSize,
555     int maxNbAttempts,
556     const limitedOutput_directive limit,
557     const dictCtx_directive dict
558     )
559 {
560     const int inputSize = *srcSizePtr;
561     const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */
562 
563     const BYTE* ip = (const BYTE*) source;
564     const BYTE* anchor = ip;
565     const BYTE* const iend = ip + inputSize;
566     const BYTE* const mflimit = iend - MFLIMIT;
567     const BYTE* const matchlimit = (iend - LASTLITERALS);
568 
569     BYTE* optr = (BYTE*) dest;
570     BYTE* op = (BYTE*) dest;
571     BYTE* oend = op + maxOutputSize;
572 
573     int   ml0, ml, ml2, ml3;
574     const BYTE* start0;
575     const BYTE* ref0;
576     const BYTE* ref = NULL;
577     const BYTE* start2 = NULL;
578     const BYTE* ref2 = NULL;
579     const BYTE* start3 = NULL;
580     const BYTE* ref3 = NULL;
581 
582     /* init */
583     *srcSizePtr = 0;
584     if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */
585     if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */
586 
587     /* Main Loop */
588     while (ip <= mflimit) {
589         ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);
590         if (ml<MINMATCH) { ip++; continue; }
591 
592         /* saved, in case we would skip too much */
593         start0 = ip; ref0 = ref; ml0 = ml;
594 
595 _Search2:
596         if (ip+ml <= mflimit) {
597             ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
598                             ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
599                             maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
600         } else {
601             ml2 = ml;
602         }
603 
604         if (ml2 == ml) { /* No better match => encode ML1 */
605             optr = op;
606             if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
607             continue;
608         }
609 
610         if (start0 < ip) {   /* first match was skipped at least once */
611             if (start2 < ip + ml0) {  /* squeezing ML1 between ML0(original ML1) and ML2 */
612                 ip = start0; ref = ref0; ml = ml0;  /* restore initial ML1 */
613         }   }
614 
615         /* Here, start0==ip */
616         if ((start2 - ip) < 3) {  /* First Match too small : removed */
617             ml = ml2;
618             ip = start2;
619             ref =ref2;
620             goto _Search2;
621         }
622 
623 _Search3:
624         /* At this stage, we have :
625         *  ml2 > ml1, and
626         *  ip1+3 <= ip2 (usually < ip1+ml1) */
627         if ((start2 - ip) < OPTIMAL_ML) {
628             int correction;
629             int new_ml = ml;
630             if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
631             if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
632             correction = new_ml - (int)(start2 - ip);
633             if (correction > 0) {
634                 start2 += correction;
635                 ref2 += correction;
636                 ml2 -= correction;
637             }
638         }
639         /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
640 
641         if (start2 + ml2 <= mflimit) {
642             ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
643                             start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
644                             maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
645         } else {
646             ml3 = ml2;
647         }
648 
649         if (ml3 == ml2) {  /* No better match => encode ML1 and ML2 */
650             /* ip & ref are known; Now for ml */
651             if (start2 < ip+ml)  ml = (int)(start2 - ip);
652             /* Now, encode 2 sequences */
653             optr = op;
654             if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
655             ip = start2;
656             optr = op;
657             if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {
658                 ml  = ml2;
659                 ref = ref2;
660                 goto _dest_overflow;
661             }
662             continue;
663         }
664 
665         if (start3 < ip+ml+3) {  /* Not enough space for match 2 : remove it */
666             if (start3 >= (ip+ml)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
667                 if (start2 < ip+ml) {
668                     int correction = (int)(ip+ml - start2);
669                     start2 += correction;
670                     ref2 += correction;
671                     ml2 -= correction;
672                     if (ml2 < MINMATCH) {
673                         start2 = start3;
674                         ref2 = ref3;
675                         ml2 = ml3;
676                     }
677                 }
678 
679                 optr = op;
680                 if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
681                 ip  = start3;
682                 ref = ref3;
683                 ml  = ml3;
684 
685                 start0 = start2;
686                 ref0 = ref2;
687                 ml0 = ml2;
688                 goto _Search2;
689             }
690 
691             start2 = start3;
692             ref2 = ref3;
693             ml2 = ml3;
694             goto _Search3;
695         }
696 
697         /*
698         * OK, now we have 3 ascending matches;
699         * let's write the first one ML1.
700         * ip & ref are known; Now decide ml.
701         */
702         if (start2 < ip+ml) {
703             if ((start2 - ip) < OPTIMAL_ML) {
704                 int correction;
705                 if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
706                 if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
707                 correction = ml - (int)(start2 - ip);
708                 if (correction > 0) {
709                     start2 += correction;
710                     ref2 += correction;
711                     ml2 -= correction;
712                 }
713             } else {
714                 ml = (int)(start2 - ip);
715             }
716         }
717         optr = op;
718         if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
719 
720         /* ML2 becomes ML1 */
721         ip = start2; ref = ref2; ml = ml2;
722 
723         /* ML3 becomes ML2 */
724         start2 = start3; ref2 = ref3; ml2 = ml3;
725 
726         /* let's find a new ML3 */
727         goto _Search3;
728     }
729 
730 _last_literals:
731     /* Encode Last Literals */
732     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
733         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
734         size_t const totalSize = 1 + llAdd + lastRunSize;
735         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
736         if (limit && (op + totalSize > oend)) {
737             if (limit == limitedOutput) return 0;
738             /* adapt lastRunSize to fill 'dest' */
739             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
740             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
741             lastRunSize -= llAdd;
742         }
743         DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
744         ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */
745 
746         if (lastRunSize >= RUN_MASK) {
747             size_t accumulator = lastRunSize - RUN_MASK;
748             *op++ = (RUN_MASK << ML_BITS);
749             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
750             *op++ = (BYTE) accumulator;
751         } else {
752             *op++ = (BYTE)(lastRunSize << ML_BITS);
753         }
754         memcpy(op, anchor, lastRunSize);
755         op += lastRunSize;
756     }
757 
758     /* End */
759     *srcSizePtr = (int) (((const char*)ip) - source);
760     return (int) (((char*)op)-dest);
761 
762 _dest_overflow:
763     if (limit == fillOutput) {
764         /* Assumption : ip, anchor, ml and ref must be set correctly */
765         size_t const ll = (size_t)(ip - anchor);
766         size_t const ll_addbytes = (ll + 240) / 255;
767         size_t const ll_totalCost = 1 + ll_addbytes + ll;
768         BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
769         DEBUGLOG(6, "Last sequence overflowing");
770         op = optr;  /* restore correct out pointer */
771         if (op + ll_totalCost <= maxLitPos) {
772             /* ll validated; now adjust match length */
773             size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
774             size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
775             assert(maxMlSize < INT_MAX); assert(ml >= 0);
776             if ((size_t)ml > maxMlSize) ml = (int)maxMlSize;
777             if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) {
778                 LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend);
779         }   }
780         goto _last_literals;
781     }
782     /* compression failed */
783     return 0;
784 }
785 
786 
787 static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
788     const char* const source, char* dst,
789     int* srcSizePtr, int dstCapacity,
790     int const nbSearches, size_t sufficient_len,
791     const limitedOutput_directive limit, int const fullUpdate,
792     const dictCtx_directive dict,
793     const HCfavor_e favorDecSpeed);
794 
795 
LZ4HC_compress_generic_internal(LZ4HC_CCtx_internal * const ctx,const char * const src,char * const dst,int * const srcSizePtr,int const dstCapacity,int cLevel,const limitedOutput_directive limit,const dictCtx_directive dict)796 LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
797     LZ4HC_CCtx_internal* const ctx,
798     const char* const src,
799     char* const dst,
800     int* const srcSizePtr,
801     int const dstCapacity,
802     int cLevel,
803     const limitedOutput_directive limit,
804     const dictCtx_directive dict
805     )
806 {
807     typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
808     typedef struct {
809         lz4hc_strat_e strat;
810         int nbSearches;
811         U32 targetLength;
812     } cParams_t;
813     static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {
814         { lz4hc,     2, 16 },  /* 0, unused */
815         { lz4hc,     2, 16 },  /* 1, unused */
816         { lz4hc,     2, 16 },  /* 2, unused */
817         { lz4hc,     4, 16 },  /* 3 */
818         { lz4hc,     8, 16 },  /* 4 */
819         { lz4hc,    16, 16 },  /* 5 */
820         { lz4hc,    32, 16 },  /* 6 */
821         { lz4hc,    64, 16 },  /* 7 */
822         { lz4hc,   128, 16 },  /* 8 */
823         { lz4hc,   256, 16 },  /* 9 */
824         { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/
825         { lz4opt,  512,128 },  /*11 */
826         { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */
827     };
828 
829     DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
830                 ctx, src, *srcSizePtr, limit);
831 
832     if (limit == fillOutput && dstCapacity < 1) return 0;   /* Impossible to store anything */
833     if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;    /* Unsupported input size (too large or negative) */
834 
835     ctx->end += *srcSizePtr;
836     if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT;   /* note : convention is different from lz4frame, maybe something to review */
837     cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
838     {   cParams_t const cParam = clTable[cLevel];
839         HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
840         int result;
841 
842         if (cParam.strat == lz4hc) {
843             result = LZ4HC_compress_hashChain(ctx,
844                                 src, dst, srcSizePtr, dstCapacity,
845                                 cParam.nbSearches, limit, dict);
846         } else {
847             assert(cParam.strat == lz4opt);
848             result = LZ4HC_compress_optimal(ctx,
849                                 src, dst, srcSizePtr, dstCapacity,
850                                 cParam.nbSearches, cParam.targetLength, limit,
851                                 cLevel == LZ4HC_CLEVEL_MAX,   /* ultra mode */
852                                 dict, favor);
853         }
854         if (result <= 0) ctx->dirty = 1;
855         return result;
856     }
857 }
858 
859 static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);
860 
861 static int
LZ4HC_compress_generic_noDictCtx(LZ4HC_CCtx_internal * const ctx,const char * const src,char * const dst,int * const srcSizePtr,int const dstCapacity,int cLevel,limitedOutput_directive limit)862 LZ4HC_compress_generic_noDictCtx (
863         LZ4HC_CCtx_internal* const ctx,
864         const char* const src,
865         char* const dst,
866         int* const srcSizePtr,
867         int const dstCapacity,
868         int cLevel,
869         limitedOutput_directive limit
870         )
871 {
872     assert(ctx->dictCtx == NULL);
873     return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
874 }
875 
876 static int
LZ4HC_compress_generic_dictCtx(LZ4HC_CCtx_internal * const ctx,const char * const src,char * const dst,int * const srcSizePtr,int const dstCapacity,int cLevel,limitedOutput_directive limit)877 LZ4HC_compress_generic_dictCtx (
878         LZ4HC_CCtx_internal* const ctx,
879         const char* const src,
880         char* const dst,
881         int* const srcSizePtr,
882         int const dstCapacity,
883         int cLevel,
884         limitedOutput_directive limit
885         )
886 {
887     const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit;
888     assert(ctx->dictCtx != NULL);
889     if (position >= 64 KB) {
890         ctx->dictCtx = NULL;
891         return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
892     } else if (position == 0 && *srcSizePtr > 4 KB) {
893         memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
894         LZ4HC_setExternalDict(ctx, (const BYTE *)src);
895         ctx->compressionLevel = (short)cLevel;
896         return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
897     } else {
898         return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
899     }
900 }
901 
902 static int
LZ4HC_compress_generic(LZ4HC_CCtx_internal * const ctx,const char * const src,char * const dst,int * const srcSizePtr,int const dstCapacity,int cLevel,limitedOutput_directive limit)903 LZ4HC_compress_generic (
904         LZ4HC_CCtx_internal* const ctx,
905         const char* const src,
906         char* const dst,
907         int* const srcSizePtr,
908         int const dstCapacity,
909         int cLevel,
910         limitedOutput_directive limit
911         )
912 {
913     if (ctx->dictCtx == NULL) {
914         return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
915     } else {
916         return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
917     }
918 }
919 
920 
LZ4_sizeofStateHC(void)921 int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }
922 
LZ4_streamHC_t_alignment(void)923 static size_t LZ4_streamHC_t_alignment(void)
924 {
925 #if LZ4_ALIGN_TEST
926     typedef struct { char c; LZ4_streamHC_t t; } t_a;
927     return sizeof(t_a) - sizeof(LZ4_streamHC_t);
928 #else
929     return 1;  /* effectively disabled */
930 #endif
931 }
932 
933 /* state is presumed correctly initialized,
934  * in which case its size and alignment have already been validate */
LZ4_compress_HC_extStateHC_fastReset(void * state,const char * src,char * dst,int srcSize,int dstCapacity,int compressionLevel)935 int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
936 {
937     LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
938     if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;
939     LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);
940     LZ4HC_init_internal (ctx, (const BYTE*)src);
941     if (dstCapacity < LZ4_compressBound(srcSize))
942         return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
943     else
944         return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);
945 }
946 
LZ4_compress_HC_extStateHC(void * state,const char * src,char * dst,int srcSize,int dstCapacity,int compressionLevel)947 int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
948 {
949     LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
950     if (ctx==NULL) return 0;   /* init failure */
951     return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
952 }
953 
LZ4_compress_HC(const char * src,char * dst,int srcSize,int dstCapacity,int compressionLevel)954 int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
955 {
956 #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
957     LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
958 #else
959     LZ4_streamHC_t state;
960     LZ4_streamHC_t* const statePtr = &state;
961 #endif
962     int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
963 #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
964     FREEMEM(statePtr);
965 #endif
966     return cSize;
967 }
968 
969 /* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
LZ4_compress_HC_destSize(void * state,const char * source,char * dest,int * sourceSizePtr,int targetDestSize,int cLevel)970 int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
971 {
972     LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
973     if (ctx==NULL) return 0;   /* init failure */
974     LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);
975     LZ4_setCompressionLevel(ctx, cLevel);
976     return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);
977 }
978 
979 
980 
981 /**************************************
982 *  Streaming Functions
983 **************************************/
984 /* allocation */
LZ4_createStreamHC(void)985 LZ4_streamHC_t* LZ4_createStreamHC(void)
986 {
987     LZ4_streamHC_t* const state =
988         (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));
989     if (state == NULL) return NULL;
990     LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);
991     return state;
992 }
993 
LZ4_freeStreamHC(LZ4_streamHC_t * LZ4_streamHCPtr)994 int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
995 {
996     DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
997     if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */
998     FREEMEM(LZ4_streamHCPtr);
999     return 0;
1000 }
1001 
1002 
LZ4_initStreamHC(void * buffer,size_t size)1003 LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
1004 {
1005     LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
1006     /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
1007     LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);
1008     DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
1009     /* check conditions */
1010     if (buffer == NULL) return NULL;
1011     if (size < sizeof(LZ4_streamHC_t)) return NULL;
1012     if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
1013     /* init */
1014     { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
1015       MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
1016     LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
1017     return LZ4_streamHCPtr;
1018 }
1019 
1020 /* just a stub */
LZ4_resetStreamHC(LZ4_streamHC_t * LZ4_streamHCPtr,int compressionLevel)1021 void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1022 {
1023     LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1024     LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
1025 }
1026 
LZ4_resetStreamHC_fast(LZ4_streamHC_t * LZ4_streamHCPtr,int compressionLevel)1027 void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1028 {
1029     DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1030     if (LZ4_streamHCPtr->internal_donotuse.dirty) {
1031         LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1032     } else {
1033         /* preserve end - base : can trigger clearTable's threshold */
1034         if (LZ4_streamHCPtr->internal_donotuse.end != NULL) {
1035             LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.base;
1036         } else {
1037             assert(LZ4_streamHCPtr->internal_donotuse.base == NULL);
1038         }
1039         LZ4_streamHCPtr->internal_donotuse.base = NULL;
1040         LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
1041     }
1042     LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
1043 }
1044 
LZ4_setCompressionLevel(LZ4_streamHC_t * LZ4_streamHCPtr,int compressionLevel)1045 void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1046 {
1047     DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1048     if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
1049     if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
1050     LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;
1051 }
1052 
LZ4_favorDecompressionSpeed(LZ4_streamHC_t * LZ4_streamHCPtr,int favor)1053 void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)
1054 {
1055     LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);
1056 }
1057 
1058 /* LZ4_loadDictHC() :
1059  * LZ4_streamHCPtr is presumed properly initialized */
LZ4_loadDictHC(LZ4_streamHC_t * LZ4_streamHCPtr,const char * dictionary,int dictSize)1060 int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
1061               const char* dictionary, int dictSize)
1062 {
1063     LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1064     DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);
1065     assert(LZ4_streamHCPtr != NULL);
1066     if (dictSize > 64 KB) {
1067         dictionary += (size_t)dictSize - 64 KB;
1068         dictSize = 64 KB;
1069     }
1070     /* need a full initialization, there are bad side-effects when using resetFast() */
1071     {   int const cLevel = ctxPtr->compressionLevel;
1072         LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1073         LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
1074     }
1075     LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
1076     ctxPtr->end = (const BYTE*)dictionary + dictSize;
1077     if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
1078     return dictSize;
1079 }
1080 
LZ4_attach_HC_dictionary(LZ4_streamHC_t * working_stream,const LZ4_streamHC_t * dictionary_stream)1081 void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {
1082     working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
1083 }
1084 
1085 /* compression */
1086 
LZ4HC_setExternalDict(LZ4HC_CCtx_internal * ctxPtr,const BYTE * newBlock)1087 static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
1088 {
1089     DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
1090     if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4)
1091         LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */
1092 
1093     /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
1094     ctxPtr->lowLimit  = ctxPtr->dictLimit;
1095     ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
1096     ctxPtr->dictBase  = ctxPtr->base;
1097     ctxPtr->base = newBlock - ctxPtr->dictLimit;
1098     ctxPtr->end  = newBlock;
1099     ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */
1100 
1101     /* cannot reference an extDict and a dictCtx at the same time */
1102     ctxPtr->dictCtx = NULL;
1103 }
1104 
1105 static int
LZ4_compressHC_continue_generic(LZ4_streamHC_t * LZ4_streamHCPtr,const char * src,char * dst,int * srcSizePtr,int dstCapacity,limitedOutput_directive limit)1106 LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
1107                                  const char* src, char* dst,
1108                                  int* srcSizePtr, int dstCapacity,
1109                                  limitedOutput_directive limit)
1110 {
1111     LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1112     DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
1113                 LZ4_streamHCPtr, src, *srcSizePtr, limit);
1114     assert(ctxPtr != NULL);
1115     /* auto-init if forgotten */
1116     if (ctxPtr->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
1117 
1118     /* Check overflow */
1119     if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
1120         size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
1121         if (dictSize > 64 KB) dictSize = 64 KB;
1122         LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
1123     }
1124 
1125     /* Check if blocks follow each other */
1126     if ((const BYTE*)src != ctxPtr->end)
1127         LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
1128 
1129     /* Check overlapping input/dictionary space */
1130     {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
1131         const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
1132         const BYTE* const dictEnd   = ctxPtr->dictBase + ctxPtr->dictLimit;
1133         if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
1134             if (sourceEnd > dictEnd) sourceEnd = dictEnd;
1135             ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
1136             if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
1137     }   }
1138 
1139     return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
1140 }
1141 
LZ4_compress_HC_continue(LZ4_streamHC_t * LZ4_streamHCPtr,const char * src,char * dst,int srcSize,int dstCapacity)1142 int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
1143 {
1144     if (dstCapacity < LZ4_compressBound(srcSize))
1145         return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
1146     else
1147         return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);
1148 }
1149 
LZ4_compress_HC_continue_destSize(LZ4_streamHC_t * LZ4_streamHCPtr,const char * src,char * dst,int * srcSizePtr,int targetDestSize)1150 int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
1151 {
1152     return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);
1153 }
1154 
1155 
1156 
1157 /* LZ4_saveDictHC :
1158  * save history content
1159  * into a user-provided buffer
1160  * which is then used to continue compression
1161  */
LZ4_saveDictHC(LZ4_streamHC_t * LZ4_streamHCPtr,char * safeBuffer,int dictSize)1162 int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
1163 {
1164     LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
1165     int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
1166     DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
1167     assert(prefixSize >= 0);
1168     if (dictSize > 64 KB) dictSize = 64 KB;
1169     if (dictSize < 4) dictSize = 0;
1170     if (dictSize > prefixSize) dictSize = prefixSize;
1171     if (safeBuffer == NULL) assert(dictSize == 0);
1172     if (dictSize > 0)
1173         memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
1174     {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
1175         streamPtr->end = (const BYTE*)safeBuffer + dictSize;
1176         streamPtr->base = streamPtr->end - endIndex;
1177         streamPtr->dictLimit = endIndex - (U32)dictSize;
1178         streamPtr->lowLimit = endIndex - (U32)dictSize;
1179         if (streamPtr->nextToUpdate < streamPtr->dictLimit)
1180             streamPtr->nextToUpdate = streamPtr->dictLimit;
1181     }
1182     return dictSize;
1183 }
1184 
1185 
1186 /***************************************************
1187 *  Deprecated Functions
1188 ***************************************************/
1189 
1190 /* These functions currently generate deprecation warnings */
1191 
1192 /* Wrappers for deprecated compression functions */
LZ4_compressHC(const char * src,char * dst,int srcSize)1193 int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
LZ4_compressHC_limitedOutput(const char * src,char * dst,int srcSize,int maxDstSize)1194 int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
LZ4_compressHC2(const char * src,char * dst,int srcSize,int cLevel)1195 int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
LZ4_compressHC2_limitedOutput(const char * src,char * dst,int srcSize,int maxDstSize,int cLevel)1196 int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
LZ4_compressHC_withStateHC(void * state,const char * src,char * dst,int srcSize)1197 int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
LZ4_compressHC_limitedOutput_withStateHC(void * state,const char * src,char * dst,int srcSize,int maxDstSize)1198 int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
LZ4_compressHC2_withStateHC(void * state,const char * src,char * dst,int srcSize,int cLevel)1199 int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
LZ4_compressHC2_limitedOutput_withStateHC(void * state,const char * src,char * dst,int srcSize,int maxDstSize,int cLevel)1200 int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
LZ4_compressHC_continue(LZ4_streamHC_t * ctx,const char * src,char * dst,int srcSize)1201 int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
LZ4_compressHC_limitedOutput_continue(LZ4_streamHC_t * ctx,const char * src,char * dst,int srcSize,int maxDstSize)1202 int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
1203 
1204 
1205 /* Deprecated streaming functions */
LZ4_sizeofStreamStateHC(void)1206 int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
1207 
1208 /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
1209  * @return : 0 on success, !=0 if error */
LZ4_resetStreamStateHC(void * state,char * inputBuffer)1210 int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
1211 {
1212     LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
1213     if (hc4 == NULL) return 1;   /* init failed */
1214     LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
1215     return 0;
1216 }
1217 
LZ4_createHC(const char * inputBuffer)1218 void* LZ4_createHC (const char* inputBuffer)
1219 {
1220     LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
1221     if (hc4 == NULL) return NULL;   /* not enough memory */
1222     LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
1223     return hc4;
1224 }
1225 
LZ4_freeHC(void * LZ4HC_Data)1226 int LZ4_freeHC (void* LZ4HC_Data)
1227 {
1228     if (!LZ4HC_Data) return 0;  /* support free on NULL */
1229     FREEMEM(LZ4HC_Data);
1230     return 0;
1231 }
1232 
LZ4_compressHC2_continue(void * LZ4HC_Data,const char * src,char * dst,int srcSize,int cLevel)1233 int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
1234 {
1235     return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
1236 }
1237 
LZ4_compressHC2_limitedOutput_continue(void * LZ4HC_Data,const char * src,char * dst,int srcSize,int dstCapacity,int cLevel)1238 int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
1239 {
1240     return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
1241 }
1242 
LZ4_slideInputBufferHC(void * LZ4HC_Data)1243 char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
1244 {
1245     LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;
1246     const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;
1247     LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);
1248     /* avoid const char * -> char * conversion warning :( */
1249     return (char *)(uptrval)bufferStart;
1250 }
1251 
1252 
1253 /* ================================================
1254  *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
1255  * ===============================================*/
1256 typedef struct {
1257     int price;
1258     int off;
1259     int mlen;
1260     int litlen;
1261 } LZ4HC_optimal_t;
1262 
1263 /* price in bytes */
LZ4HC_literalsPrice(int const litlen)1264 LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
1265 {
1266     int price = litlen;
1267     assert(litlen >= 0);
1268     if (litlen >= (int)RUN_MASK)
1269         price += 1 + ((litlen-(int)RUN_MASK) / 255);
1270     return price;
1271 }
1272 
1273 
1274 /* requires mlen >= MINMATCH */
LZ4HC_sequencePrice(int litlen,int mlen)1275 LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
1276 {
1277     int price = 1 + 2 ; /* token + 16-bit offset */
1278     assert(litlen >= 0);
1279     assert(mlen >= MINMATCH);
1280 
1281     price += LZ4HC_literalsPrice(litlen);
1282 
1283     if (mlen >= (int)(ML_MASK+MINMATCH))
1284         price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);
1285 
1286     return price;
1287 }
1288 
1289 
1290 typedef struct {
1291     int off;
1292     int len;
1293 } LZ4HC_match_t;
1294 
1295 LZ4_FORCE_INLINE LZ4HC_match_t
LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal * const ctx,const BYTE * ip,const BYTE * const iHighLimit,int minLen,int nbSearches,const dictCtx_directive dict,const HCfavor_e favorDecSpeed)1296 LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
1297                       const BYTE* ip, const BYTE* const iHighLimit,
1298                       int minLen, int nbSearches,
1299                       const dictCtx_directive dict,
1300                       const HCfavor_e favorDecSpeed)
1301 {
1302     LZ4HC_match_t match = { 0 , 0 };
1303     const BYTE* matchPtr = NULL;
1304     /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
1305      * but this won't be the case here, as we define iLowLimit==ip,
1306      * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
1307     int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
1308     if (matchLength <= minLen) return match;
1309     if (favorDecSpeed) {
1310         if ((matchLength>18) & (matchLength<=36)) matchLength=18;   /* favor shortcut */
1311     }
1312     match.len = matchLength;
1313     match.off = (int)(ip-matchPtr);
1314     return match;
1315 }
1316 
1317 
LZ4HC_compress_optimal(LZ4HC_CCtx_internal * ctx,const char * const source,char * dst,int * srcSizePtr,int dstCapacity,int const nbSearches,size_t sufficient_len,const limitedOutput_directive limit,int const fullUpdate,const dictCtx_directive dict,const HCfavor_e favorDecSpeed)1318 static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
1319                                     const char* const source,
1320                                     char* dst,
1321                                     int* srcSizePtr,
1322                                     int dstCapacity,
1323                                     int const nbSearches,
1324                                     size_t sufficient_len,
1325                                     const limitedOutput_directive limit,
1326                                     int const fullUpdate,
1327                                     const dictCtx_directive dict,
1328                                     const HCfavor_e favorDecSpeed)
1329 {
1330     int retval = 0;
1331 #define TRAILING_LITERALS 3
1332 #ifdef LZ4HC_HEAPMODE
1333     LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
1334 #else
1335     LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which is a bit large for stack... */
1336 #endif
1337 
1338     const BYTE* ip = (const BYTE*) source;
1339     const BYTE* anchor = ip;
1340     const BYTE* const iend = ip + *srcSizePtr;
1341     const BYTE* const mflimit = iend - MFLIMIT;
1342     const BYTE* const matchlimit = iend - LASTLITERALS;
1343     BYTE* op = (BYTE*) dst;
1344     BYTE* opSaved = (BYTE*) dst;
1345     BYTE* oend = op + dstCapacity;
1346     int ovml = MINMATCH;  /* overflow - last sequence */
1347     const BYTE* ovref = NULL;
1348 
1349     /* init */
1350 #ifdef LZ4HC_HEAPMODE
1351     if (opt == NULL) goto _return_label;
1352 #endif
1353     DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
1354     *srcSizePtr = 0;
1355     if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */
1356     if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;
1357 
1358     /* Main Loop */
1359     while (ip <= mflimit) {
1360          int const llen = (int)(ip - anchor);
1361          int best_mlen, best_off;
1362          int cur, last_match_pos = 0;
1363 
1364          LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
1365          if (firstMatch.len==0) { ip++; continue; }
1366 
1367          if ((size_t)firstMatch.len > sufficient_len) {
1368              /* good enough solution : immediate encoding */
1369              int const firstML = firstMatch.len;
1370              const BYTE* const matchPos = ip - firstMatch.off;
1371              opSaved = op;
1372              if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) {  /* updates ip, op and anchor */
1373                  ovml = firstML;
1374                  ovref = matchPos;
1375                  goto _dest_overflow;
1376              }
1377              continue;
1378          }
1379 
1380          /* set prices for first positions (literals) */
1381          {   int rPos;
1382              for (rPos = 0 ; rPos < MINMATCH ; rPos++) {
1383                  int const cost = LZ4HC_literalsPrice(llen + rPos);
1384                  opt[rPos].mlen = 1;
1385                  opt[rPos].off = 0;
1386                  opt[rPos].litlen = llen + rPos;
1387                  opt[rPos].price = cost;
1388                  DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
1389                              rPos, cost, opt[rPos].litlen);
1390          }   }
1391          /* set prices using initial match */
1392          {   int mlen = MINMATCH;
1393              int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */
1394              int const offset = firstMatch.off;
1395              assert(matchML < LZ4_OPT_NUM);
1396              for ( ; mlen <= matchML ; mlen++) {
1397                  int const cost = LZ4HC_sequencePrice(llen, mlen);
1398                  opt[mlen].mlen = mlen;
1399                  opt[mlen].off = offset;
1400                  opt[mlen].litlen = llen;
1401                  opt[mlen].price = cost;
1402                  DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",
1403                              mlen, cost, mlen);
1404          }   }
1405          last_match_pos = firstMatch.len;
1406          {   int addLit;
1407              for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
1408                  opt[last_match_pos+addLit].mlen = 1; /* literal */
1409                  opt[last_match_pos+addLit].off = 0;
1410                  opt[last_match_pos+addLit].litlen = addLit;
1411                  opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
1412                  DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",
1413                              last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
1414          }   }
1415 
1416          /* check further positions */
1417          for (cur = 1; cur < last_match_pos; cur++) {
1418              const BYTE* const curPtr = ip + cur;
1419              LZ4HC_match_t newMatch;
1420 
1421              if (curPtr > mflimit) break;
1422              DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",
1423                      cur, opt[cur].price, opt[cur+1].price, cur+1);
1424              if (fullUpdate) {
1425                  /* not useful to search here if next position has same (or lower) cost */
1426                  if ( (opt[cur+1].price <= opt[cur].price)
1427                    /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */
1428                    && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )
1429                      continue;
1430              } else {
1431                  /* not useful to search here if next position has same (or lower) cost */
1432                  if (opt[cur+1].price <= opt[cur].price) continue;
1433              }
1434 
1435              DEBUGLOG(7, "search at rPos:%u", cur);
1436              if (fullUpdate)
1437                  newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);
1438              else
1439                  /* only test matches of minimum length; slightly faster, but misses a few bytes */
1440                  newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);
1441              if (!newMatch.len) continue;
1442 
1443              if ( ((size_t)newMatch.len > sufficient_len)
1444                || (newMatch.len + cur >= LZ4_OPT_NUM) ) {
1445                  /* immediate encoding */
1446                  best_mlen = newMatch.len;
1447                  best_off = newMatch.off;
1448                  last_match_pos = cur + 1;
1449                  goto encode;
1450              }
1451 
1452              /* before match : set price with literals at beginning */
1453              {   int const baseLitlen = opt[cur].litlen;
1454                  int litlen;
1455                  for (litlen = 1; litlen < MINMATCH; litlen++) {
1456                      int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);
1457                      int const pos = cur + litlen;
1458                      if (price < opt[pos].price) {
1459                          opt[pos].mlen = 1; /* literal */
1460                          opt[pos].off = 0;
1461                          opt[pos].litlen = baseLitlen+litlen;
1462                          opt[pos].price = price;
1463                          DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",
1464                                      pos, price, opt[pos].litlen);
1465              }   }   }
1466 
1467              /* set prices using match at position = cur */
1468              {   int const matchML = newMatch.len;
1469                  int ml = MINMATCH;
1470 
1471                  assert(cur + newMatch.len < LZ4_OPT_NUM);
1472                  for ( ; ml <= matchML ; ml++) {
1473                      int const pos = cur + ml;
1474                      int const offset = newMatch.off;
1475                      int price;
1476                      int ll;
1477                      DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",
1478                                  pos, last_match_pos);
1479                      if (opt[cur].mlen == 1) {
1480                          ll = opt[cur].litlen;
1481                          price = ((cur > ll) ? opt[cur - ll].price : 0)
1482                                + LZ4HC_sequencePrice(ll, ml);
1483                      } else {
1484                          ll = 0;
1485                          price = opt[cur].price + LZ4HC_sequencePrice(0, ml);
1486                      }
1487 
1488                     assert((U32)favorDecSpeed <= 1);
1489                      if (pos > last_match_pos+TRAILING_LITERALS
1490                       || price <= opt[pos].price - (int)favorDecSpeed) {
1491                          DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",
1492                                      pos, price, ml);
1493                          assert(pos < LZ4_OPT_NUM);
1494                          if ( (ml == matchML)  /* last pos of last match */
1495                            && (last_match_pos < pos) )
1496                              last_match_pos = pos;
1497                          opt[pos].mlen = ml;
1498                          opt[pos].off = offset;
1499                          opt[pos].litlen = ll;
1500                          opt[pos].price = price;
1501              }   }   }
1502              /* complete following positions with literals */
1503              {   int addLit;
1504                  for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {
1505                      opt[last_match_pos+addLit].mlen = 1; /* literal */
1506                      opt[last_match_pos+addLit].off = 0;
1507                      opt[last_match_pos+addLit].litlen = addLit;
1508                      opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);
1509                      DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);
1510              }   }
1511          }  /* for (cur = 1; cur <= last_match_pos; cur++) */
1512 
1513          assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);
1514          best_mlen = opt[last_match_pos].mlen;
1515          best_off = opt[last_match_pos].off;
1516          cur = last_match_pos - best_mlen;
1517 
1518 encode: /* cur, last_match_pos, best_mlen, best_off must be set */
1519          assert(cur < LZ4_OPT_NUM);
1520          assert(last_match_pos >= 1);  /* == 1 when only one candidate */
1521          DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);
1522          {   int candidate_pos = cur;
1523              int selected_matchLength = best_mlen;
1524              int selected_offset = best_off;
1525              while (1) {  /* from end to beginning */
1526                  int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */
1527                  int const next_offset = opt[candidate_pos].off;
1528                  DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);
1529                  opt[candidate_pos].mlen = selected_matchLength;
1530                  opt[candidate_pos].off = selected_offset;
1531                  selected_matchLength = next_matchLength;
1532                  selected_offset = next_offset;
1533                  if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */
1534                  assert(next_matchLength > 0);  /* can be 1, means literal */
1535                  candidate_pos -= next_matchLength;
1536          }   }
1537 
1538          /* encode all recorded sequences in order */
1539          {   int rPos = 0;  /* relative position (to ip) */
1540              while (rPos < last_match_pos) {
1541                  int const ml = opt[rPos].mlen;
1542                  int const offset = opt[rPos].off;
1543                  if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */
1544                  rPos += ml;
1545                  assert(ml >= MINMATCH);
1546                  assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
1547                  opSaved = op;
1548                  if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) {  /* updates ip, op and anchor */
1549                      ovml = ml;
1550                      ovref = ip - offset;
1551                      goto _dest_overflow;
1552          }   }   }
1553      }  /* while (ip <= mflimit) */
1554 
1555 _last_literals:
1556      /* Encode Last Literals */
1557      {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */
1558          size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
1559          size_t const totalSize = 1 + llAdd + lastRunSize;
1560          if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */
1561          if (limit && (op + totalSize > oend)) {
1562              if (limit == limitedOutput) { /* Check output limit */
1563                 retval = 0;
1564                 goto _return_label;
1565              }
1566              /* adapt lastRunSize to fill 'dst' */
1567              lastRunSize  = (size_t)(oend - op) - 1 /*token*/;
1568              llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
1569              lastRunSize -= llAdd;
1570          }
1571          DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
1572          ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
1573 
1574          if (lastRunSize >= RUN_MASK) {
1575              size_t accumulator = lastRunSize - RUN_MASK;
1576              *op++ = (RUN_MASK << ML_BITS);
1577              for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
1578              *op++ = (BYTE) accumulator;
1579          } else {
1580              *op++ = (BYTE)(lastRunSize << ML_BITS);
1581          }
1582          memcpy(op, anchor, lastRunSize);
1583          op += lastRunSize;
1584      }
1585 
1586      /* End */
1587      *srcSizePtr = (int) (((const char*)ip) - source);
1588      retval = (int) ((char*)op-dst);
1589      goto _return_label;
1590 
1591 _dest_overflow:
1592 if (limit == fillOutput) {
1593      /* Assumption : ip, anchor, ovml and ovref must be set correctly */
1594      size_t const ll = (size_t)(ip - anchor);
1595      size_t const ll_addbytes = (ll + 240) / 255;
1596      size_t const ll_totalCost = 1 + ll_addbytes + ll;
1597      BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
1598      DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));
1599      op = opSaved;  /* restore correct out pointer */
1600      if (op + ll_totalCost <= maxLitPos) {
1601          /* ll validated; now adjust match length */
1602          size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
1603          size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
1604          assert(maxMlSize < INT_MAX); assert(ovml >= 0);
1605          if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;
1606          if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
1607              DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
1608              DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
1609              LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);
1610              DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
1611      }   }
1612      goto _last_literals;
1613 }
1614 _return_label:
1615 #ifdef LZ4HC_HEAPMODE
1616      FREEMEM(opt);
1617 #endif
1618      return retval;
1619 }
1620