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