File Coverage

lz4hc.c
Criterion Covered Total %
statement 0 409 0.0
branch 0 630 0.0
condition n/a
subroutine n/a
pod n/a
total 0 1039 0.0


line stmt bran cond sub pod time code
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             #define LZ4_COMMONDEFS_ONLY
65             #include "lz4.c" /* LZ4_count, constants, mem */
66              
67              
68             /*=== Constants ===*/
69             #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
70              
71              
72             /*=== Macros ===*/
73             #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
74             #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
75             #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
76             #define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
77             #define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
78              
79 0           static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
80              
81              
82              
83             /**************************************
84             * HC Compression
85             **************************************/
86 0           static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start)
87             {
88 0           MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
89 0           MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
90 0           hc4->nextToUpdate = 64 KB;
91 0           hc4->base = start - 64 KB;
92 0           hc4->end = start;
93 0           hc4->dictBase = start - 64 KB;
94 0           hc4->dictLimit = 64 KB;
95 0           hc4->lowLimit = 64 KB;
96 0           }
97              
98              
99             /* Update chains up to ip (excluded) */
100             LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
101             {
102 0           U16* const chainTable = hc4->chainTable;
103 0           U32* const hashTable = hc4->hashTable;
104 0           const BYTE* const base = hc4->base;
105 0           U32 const target = (U32)(ip - base);
106 0           U32 idx = hc4->nextToUpdate;
107              
108 0 0         while (idx < target) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
109 0           U32 const h = LZ4HC_hashPtr(base+idx);
110 0           size_t delta = idx - hashTable[h];
111 0 0         if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
112 0           DELTANEXTU16(chainTable, idx) = (U16)delta;
113 0           hashTable[h] = idx;
114 0           idx++;
115             }
116              
117 0           hc4->nextToUpdate = target;
118             }
119              
120             /** LZ4HC_countBack() :
121             * @return : negative value, nb of common bytes before ip/match */
122             LZ4_FORCE_INLINE
123             int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
124             const BYTE* const iMin, const BYTE* const mMin)
125             {
126             int back=0;
127             while ( (ip+back > iMin)
128             && (match+back > mMin)
129             && (ip[back-1] == match[back-1]))
130             back--;
131             return back;
132             }
133              
134             /* LZ4HC_countPattern() :
135             * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
136 0           static unsigned LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
137             {
138 0           const BYTE* const iStart = ip;
139 0           reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << 32) : pattern32;
140              
141 0 0         while (likely(ip < iEnd-(sizeof(pattern)-1))) {
142 0           reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;
143 0 0         if (!diff) { ip+=sizeof(pattern); continue; }
144 0           ip += LZ4_NbCommonBytes(diff);
145 0           return (unsigned)(ip - iStart);
146             }
147              
148 0 0         if (LZ4_isLittleEndian()) {
149 0           reg_t patternByte = pattern;
150 0 0         while ((ip
    0          
151 0           ip++; patternByte >>= 8;
152             }
153             } else { /* big endian */
154 0           U32 bitOffset = (sizeof(pattern)*8) - 8;
155 0 0         while (ip < iEnd) {
156 0           BYTE const byte = (BYTE)(pattern >> bitOffset);
157 0 0         if (*ip != byte) break;
158 0           ip ++; bitOffset -= 8;
159             }
160             }
161              
162 0           return (unsigned)(ip - iStart);
163             }
164              
165             /* LZ4HC_reverseCountPattern() :
166             * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
167             * read using natural platform endianess */
168 0           static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
169             {
170 0           const BYTE* const iStart = ip;
171              
172 0 0         while (likely(ip >= iLow+4)) {
173 0 0         if (LZ4_read32(ip-4) != pattern) break;
174 0           ip -= 4;
175             }
176 0           { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */
177 0 0         while (likely(ip>iLow)) {
178 0 0         if (ip[-1] != *bytePtr) break;
179 0           ip--; bytePtr--;
180             } }
181 0           return (unsigned)(iStart - ip);
182             }
183              
184             typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
185              
186             LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
187             LZ4HC_CCtx_internal* hc4,
188             const BYTE* const ip,
189             const BYTE* const iLowLimit,
190             const BYTE* const iHighLimit,
191             int longest,
192             const BYTE** matchpos,
193             const BYTE** startpos,
194             const int maxNbAttempts,
195             const int patternAnalysis)
196             {
197 0           U16* const chainTable = hc4->chainTable;
198 0           U32* const HashTable = hc4->hashTable;
199 0           const BYTE* const base = hc4->base;
200 0           const U32 dictLimit = hc4->dictLimit;
201 0           const BYTE* const lowPrefixPtr = base + dictLimit;
202 0 0         const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - MAX_DISTANCE;
    0          
    0          
    0          
    0          
    0          
203 0           const BYTE* const dictBase = hc4->dictBase;
204 0           int const delta = (int)(ip-iLowLimit);
205 0           int nbAttempts = maxNbAttempts;
206 0           U32 const pattern = LZ4_read32(ip);
207             U32 matchIndex;
208 0           repeat_state_e repeat = rep_untested;
209 0           size_t srcPatternLength = 0;
210              
211             DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
212             /* First Match */
213             LZ4HC_Insert(hc4, ip);
214 0           matchIndex = HashTable[LZ4HC_hashPtr(ip)];
215             DEBUGLOG(7, "First match at index %u / %u (lowLimit)",
216             matchIndex, lowLimit);
217              
218 0 0         while ((matchIndex>=lowLimit) && (nbAttempts)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
219             DEBUGLOG(7, "remaining attempts : %i", nbAttempts);
220 0           nbAttempts--;
221 0 0         if (matchIndex >= dictLimit) {
    0          
    0          
    0          
    0          
    0          
222 0           const BYTE* const matchPtr = base + matchIndex;
223 0 0         if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) {
    0          
    0          
    0          
    0          
    0          
224 0 0         if (LZ4_read32(matchPtr) == pattern) {
    0          
    0          
    0          
    0          
    0          
225 0           int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
226             #if 0
227             /* more generic but unfortunately slower on clang */
228             int const back = LZ4HC_countBack(ip, matchPtr, iLowLimit, lowPrefixPtr);
229             #else
230 0           int back = 0;
231 0 0         while ( (ip+back > iLowLimit)
    0          
    0          
    0          
    0          
    0          
232 0 0         && (matchPtr+back > lowPrefixPtr)
    0          
    0          
    0          
    0          
    0          
233 0 0         && (ip[back-1] == matchPtr[back-1])) {
    0          
    0          
    0          
    0          
    0          
234 0           back--;
235             }
236             #endif
237 0           mlt -= back;
238              
239 0 0         if (mlt > longest) {
    0          
    0          
    0          
    0          
    0          
240 0           longest = mlt;
241 0           *matchpos = matchPtr+back;
242 0           *startpos = ip+back;
243             } }
244             }
245             } else { /* matchIndex < dictLimit */
246 0           const BYTE* const matchPtr = dictBase + matchIndex;
247 0 0         if (LZ4_read32(matchPtr) == pattern) {
    0          
    0          
    0          
    0          
    0          
248             int mlt;
249 0           int back = 0;
250 0           const BYTE* vLimit = ip + (dictLimit - matchIndex);
251 0 0         if (vLimit > iHighLimit) vLimit = iHighLimit;
    0          
    0          
    0          
    0          
    0          
252 0           mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
253 0 0         if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
254 0           mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
255 0 0         while ( (ip+back > iLowLimit)
    0          
    0          
    0          
    0          
    0          
256 0 0         && (matchIndex+back > lowLimit)
    0          
    0          
    0          
    0          
    0          
257 0 0         && (ip[back-1] == matchPtr[back-1]))
    0          
    0          
    0          
    0          
    0          
258 0           back--;
259 0           mlt -= back;
260 0 0         if (mlt > longest) {
    0          
    0          
    0          
    0          
    0          
261 0           longest = mlt;
262 0           *matchpos = base + matchIndex + back;
263 0           *startpos = ip + back;
264             } } }
265              
266 0           { U32 const nextOffset = DELTANEXTU16(chainTable, matchIndex);
267 0           matchIndex -= nextOffset;
268 0 0         if (patternAnalysis && nextOffset==1) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
269             /* may be a repeated pattern */
270 0 0         if (repeat == rep_untested) {
    0          
    0          
    0          
    0          
    0          
271 0 0         if ( ((pattern & 0xFFFF) == (pattern >> 16))
    0          
    0          
    0          
    0          
    0          
272 0           & ((pattern & 0xFF) == (pattern >> 24)) ) {
273 0           repeat = rep_confirmed;
274 0           srcPatternLength = LZ4HC_countPattern(ip+4, iHighLimit, pattern) + 4;
275             } else {
276 0           repeat = rep_not;
277             } }
278 0 0         if ( (repeat == rep_confirmed)
    0          
    0          
    0          
    0          
    0          
279 0 0         && (matchIndex >= dictLimit) ) { /* same segment only */
    0          
    0          
    0          
    0          
    0          
280 0           const BYTE* const matchPtr = base + matchIndex;
281 0 0         if (LZ4_read32(matchPtr) == pattern) { /* good candidate */
    0          
    0          
    0          
    0          
    0          
282 0           size_t const forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
283 0 0         const BYTE* const maxLowPtr = (lowPrefixPtr + MAX_DISTANCE >= ip) ? lowPrefixPtr : ip - MAX_DISTANCE;
    0          
    0          
    0          
    0          
    0          
284 0           size_t const backLength = LZ4HC_reverseCountPattern(matchPtr, maxLowPtr, pattern);
285 0           size_t const currentSegmentLength = backLength + forwardPatternLength;
286              
287 0           if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
288 0 0         && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
    0          
    0          
    0          
    0          
    0          
289 0           matchIndex += (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
290             } else {
291 0           matchIndex -= (U32)backLength; /* let's go to farthest segment position, will find a match of length currentSegmentLength + maybe some back */
292             }
293             } } } }
294             } /* while ((matchIndex>=lowLimit) && (nbAttempts)) */
295              
296 0           return longest;
297             }
298              
299             LZ4_FORCE_INLINE
300             int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
301             const BYTE* const ip, const BYTE* const iLimit,
302             const BYTE** matchpos,
303             const int maxNbAttempts,
304             const int patternAnalysis)
305             {
306 0           const BYTE* uselessPtr = ip;
307             /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
308             * but this won't be the case here, as we define iLowLimit==ip,
309             * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
310 0           return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis);
311             }
312              
313              
314              
315             typedef enum {
316             noLimit = 0,
317             limitedOutput = 1,
318             limitedDestSize = 2,
319             } limitedOutput_directive;
320              
321             /* LZ4HC_encodeSequence() :
322             * @return : 0 if ok,
323             * 1 if buffer issue detected */
324             LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
325             const BYTE** ip,
326             BYTE** op,
327             const BYTE** anchor,
328             int matchLength,
329             const BYTE* const match,
330             limitedOutput_directive limit,
331             BYTE* oend)
332             {
333             size_t length;
334 0           BYTE* const token = (*op)++;
335              
336             #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 2)
337             static const BYTE* start = NULL;
338             static U32 totalCost = 0;
339             U32 const pos = (start==NULL) ? 0 : (U32)(*anchor - start);
340             U32 const ll = (U32)(*ip - *anchor);
341             U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
342             U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
343             U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
344             if (start==NULL) start = *anchor; /* only works for single segment */
345             //g_debuglog_enable = (pos >= 2228) & (pos <= 2262);
346             DEBUGLOG(2, "pos:%7u -- literals:%3u, match:%4i, offset:%5u, cost:%3u + %u",
347             pos,
348             (U32)(*ip - *anchor), matchLength, (U32)(*ip-match),
349             cost, totalCost);
350             totalCost += cost;
351             #endif
352              
353             /* Encode Literal length */
354 0           length = (size_t)(*ip - *anchor);
355 0 0         if ((limit) && ((*op + (length >> 8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
356 0 0         if (length >= RUN_MASK) {
    0          
    0          
    0          
    0          
    0          
    0          
357 0           size_t len = length - RUN_MASK;
358 0           *token = (RUN_MASK << ML_BITS);
359 0 0         for(; len >= 255 ; len -= 255) *(*op)++ = 255;
    0          
    0          
    0          
    0          
    0          
    0          
360 0           *(*op)++ = (BYTE)len;
361             } else {
362 0           *token = (BYTE)(length << ML_BITS);
363             }
364              
365             /* Copy Literals */
366 0           LZ4_wildCopy(*op, *anchor, (*op) + length);
367 0           *op += length;
368              
369             /* Encode Offset */
370 0           LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
371              
372             /* Encode MatchLength */
373             assert(matchLength >= MINMATCH);
374 0           length = (size_t)(matchLength - MINMATCH);
375 0 0         if ((limit) && (*op + (length >> 8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
376 0 0         if (length >= ML_MASK) {
    0          
    0          
    0          
    0          
    0          
    0          
377 0           *token += ML_MASK;
378 0           length -= ML_MASK;
379 0 0         for(; length >= 510 ; length -= 510) { *(*op)++ = 255; *(*op)++ = 255; }
    0          
    0          
    0          
    0          
    0          
    0          
380 0 0         if (length >= 255) { length -= 255; *(*op)++ = 255; }
    0          
    0          
    0          
    0          
    0          
    0          
381 0           *(*op)++ = (BYTE)length;
382             } else {
383 0           *token += (BYTE)(length);
384             }
385              
386             /* Prepare next loop */
387 0           *ip += matchLength;
388 0           *anchor = *ip;
389              
390 0           return 0;
391             }
392              
393             /* btopt */
394             #include "lz4opt.h"
395              
396              
397 0           static int LZ4HC_compress_hashChain (
398             LZ4HC_CCtx_internal* const ctx,
399             const char* const source,
400             char* const dest,
401             int* srcSizePtr,
402             int const maxOutputSize,
403             unsigned maxNbAttempts,
404             limitedOutput_directive limit
405             )
406             {
407 0           const int inputSize = *srcSizePtr;
408 0           const int patternAnalysis = (maxNbAttempts > 64); /* levels 8+ */
409              
410 0           const BYTE* ip = (const BYTE*) source;
411 0           const BYTE* anchor = ip;
412 0           const BYTE* const iend = ip + inputSize;
413 0           const BYTE* const mflimit = iend - MFLIMIT;
414 0           const BYTE* const matchlimit = (iend - LASTLITERALS);
415              
416 0           BYTE* optr = (BYTE*) dest;
417 0           BYTE* op = (BYTE*) dest;
418 0           BYTE* oend = op + maxOutputSize;
419              
420             int ml, ml2, ml3, ml0;
421 0           const BYTE* ref = NULL;
422 0           const BYTE* start2 = NULL;
423 0           const BYTE* ref2 = NULL;
424 0           const BYTE* start3 = NULL;
425 0           const BYTE* ref3 = NULL;
426             const BYTE* start0;
427             const BYTE* ref0;
428              
429             /* init */
430 0           *srcSizePtr = 0;
431 0 0         if (limit == limitedDestSize) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
432 0 0         if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
433              
434             /* Main Loop */
435 0 0         while (ip < mflimit) {
436 0           ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis);
437 0 0         if (ml
438              
439             /* saved, in case we would skip too much */
440 0           start0 = ip;
441 0           ref0 = ref;
442 0           ml0 = ml;
443              
444             _Search2:
445 0 0         if (ip+ml < mflimit)
446 0           ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
447 0           ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
448             maxNbAttempts, patternAnalysis);
449             else
450 0           ml2 = ml;
451              
452 0 0         if (ml2 == ml) { /* No better match */
453 0           optr = op;
454 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
455 0           continue;
456             }
457              
458 0 0         if (start0 < ip) {
459 0 0         if (start2 < ip + ml0) { /* empirical */
460 0           ip = start0;
461 0           ref = ref0;
462 0           ml = ml0;
463             }
464             }
465              
466             /* Here, start0==ip */
467 0 0         if ((start2 - ip) < 3) { /* First Match too small : removed */
468 0           ml = ml2;
469 0           ip = start2;
470 0           ref =ref2;
471 0           goto _Search2;
472             }
473              
474             _Search3:
475             /* At this stage, we have :
476             * ml2 > ml1, and
477             * ip1+3 <= ip2 (usually < ip1+ml1) */
478 0 0         if ((start2 - ip) < OPTIMAL_ML) {
479             int correction;
480 0           int new_ml = ml;
481 0 0         if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
482 0 0         if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
483 0           correction = new_ml - (int)(start2 - ip);
484 0 0         if (correction > 0) {
485 0           start2 += correction;
486 0           ref2 += correction;
487 0           ml2 -= correction;
488             }
489             }
490             /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
491              
492 0 0         if (start2 + ml2 < mflimit)
493 0           ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
494 0           start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
495             maxNbAttempts, patternAnalysis);
496             else
497 0           ml3 = ml2;
498              
499 0 0         if (ml3 == ml2) { /* No better match : 2 sequences to encode */
500             /* ip & ref are known; Now for ml */
501 0 0         if (start2 < ip+ml) ml = (int)(start2 - ip);
502             /* Now, encode 2 sequences */
503 0           optr = op;
504 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
505 0           ip = start2;
506 0           optr = op;
507 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) goto _dest_overflow;
508 0           continue;
509             }
510              
511 0 0         if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */
512 0 0         if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
513 0 0         if (start2 < ip+ml) {
514 0           int correction = (int)(ip+ml - start2);
515 0           start2 += correction;
516 0           ref2 += correction;
517 0           ml2 -= correction;
518 0 0         if (ml2 < MINMATCH) {
519 0           start2 = start3;
520 0           ref2 = ref3;
521 0           ml2 = ml3;
522             }
523             }
524              
525 0           optr = op;
526 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
527 0           ip = start3;
528 0           ref = ref3;
529 0           ml = ml3;
530              
531 0           start0 = start2;
532 0           ref0 = ref2;
533 0           ml0 = ml2;
534 0           goto _Search2;
535             }
536              
537 0           start2 = start3;
538 0           ref2 = ref3;
539 0           ml2 = ml3;
540 0           goto _Search3;
541             }
542              
543             /*
544             * OK, now we have 3 ascending matches; let's write at least the first one
545             * ip & ref are known; Now for ml
546             */
547 0 0         if (start2 < ip+ml) {
548 0 0         if ((start2 - ip) < (int)ML_MASK) {
549             int correction;
550 0 0         if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
551 0 0         if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
552 0           correction = ml - (int)(start2 - ip);
553 0 0         if (correction > 0) {
554 0           start2 += correction;
555 0           ref2 += correction;
556 0           ml2 -= correction;
557             }
558             } else {
559 0           ml = (int)(start2 - ip);
560             }
561             }
562 0           optr = op;
563 0 0         if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow;
564              
565 0           ip = start2;
566 0           ref = ref2;
567 0           ml = ml2;
568              
569 0           start2 = start3;
570 0           ref2 = ref3;
571 0           ml2 = ml3;
572              
573 0           goto _Search3;
574             }
575              
576             _last_literals:
577             /* Encode Last Literals */
578 0           { size_t lastRunSize = (size_t)(iend - anchor); /* literals */
579 0           size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
580 0           size_t const totalSize = 1 + litLength + lastRunSize;
581 0 0         if (limit == limitedDestSize) oend += LASTLITERALS; /* restore correct value */
582 0 0         if (limit && (op + totalSize > oend)) {
    0          
583 0 0         if (limit == limitedOutput) return 0; /* Check output limit */
584             /* adapt lastRunSize to fill 'dest' */
585 0           lastRunSize = (size_t)(oend - op) - 1;
586 0           litLength = (lastRunSize + 255 - RUN_MASK) / 255;
587 0           lastRunSize -= litLength;
588             }
589 0           ip = anchor + lastRunSize;
590              
591 0 0         if (lastRunSize >= RUN_MASK) {
592 0           size_t accumulator = lastRunSize - RUN_MASK;
593 0           *op++ = (RUN_MASK << ML_BITS);
594 0 0         for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
595 0           *op++ = (BYTE) accumulator;
596             } else {
597 0           *op++ = (BYTE)(lastRunSize << ML_BITS);
598             }
599 0           memcpy(op, anchor, lastRunSize);
600 0           op += lastRunSize;
601             }
602              
603             /* End */
604 0           *srcSizePtr = (int) (((const char*)ip) - source);
605 0           return (int) (((char*)op)-dest);
606              
607             _dest_overflow:
608 0 0         if (limit == limitedDestSize) {
609 0           op = optr; /* restore correct out pointer */
610 0           goto _last_literals;
611             }
612 0           return 0;
613             }
614              
615              
616 0           static int LZ4HC_compress_generic (
617             LZ4HC_CCtx_internal* const ctx,
618             const char* const src,
619             char* const dst,
620             int* const srcSizePtr,
621             int const dstCapacity,
622             int cLevel,
623             limitedOutput_directive limit
624             )
625             {
626             typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
627             typedef struct {
628             lz4hc_strat_e strat;
629             U32 nbSearches;
630             U32 targetLength;
631             } cParams_t;
632             static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {
633             { lz4hc, 2, 16 }, /* 0, unused */
634             { lz4hc, 2, 16 }, /* 1, unused */
635             { lz4hc, 2, 16 }, /* 2, unused */
636             { lz4hc, 4, 16 }, /* 3 */
637             { lz4hc, 8, 16 }, /* 4 */
638             { lz4hc, 16, 16 }, /* 5 */
639             { lz4hc, 32, 16 }, /* 6 */
640             { lz4hc, 64, 16 }, /* 7 */
641             { lz4hc, 128, 16 }, /* 8 */
642             { lz4hc, 256, 16 }, /* 9 */
643             { lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/
644             { lz4opt, 512,128 }, /*11 */
645             { lz4opt,8192, LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
646             };
647              
648 0 0         if (limit == limitedDestSize && dstCapacity < 1) return 0; /* Impossible to store anything */
    0          
649 0 0         if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
650              
651 0           ctx->end += *srcSizePtr;
652 0 0         if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */
653 0           cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
654             assert(cLevel >= 0);
655             assert(cLevel <= LZ4HC_CLEVEL_MAX);
656 0           { cParams_t const cParam = clTable[cLevel];
657 0 0         if (cParam.strat == lz4hc)
658 0           return LZ4HC_compress_hashChain(ctx,
659             src, dst, srcSizePtr, dstCapacity,
660             cParam.nbSearches, limit);
661             assert(cParam.strat == lz4opt);
662 0           return LZ4HC_compress_optimal(ctx,
663             src, dst, srcSizePtr, dstCapacity,
664 0           cParam.nbSearches, cParam.targetLength, limit,
665             cLevel == LZ4HC_CLEVEL_MAX); /* ultra mode */
666             }
667             }
668              
669              
670 0           int LZ4_sizeofStateHC(void) { return sizeof(LZ4_streamHC_t); }
671              
672 0           int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
673             {
674 0           LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
675 0 0         if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
676 0           LZ4HC_init (ctx, (const BYTE*)src);
677 0 0         if (dstCapacity < LZ4_compressBound(srcSize))
678 0           return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);
679             else
680 0           return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, noLimit);
681             }
682              
683 0           int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
684             {
685             #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
686 0           LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t));
687             #else
688             LZ4_streamHC_t state;
689             LZ4_streamHC_t* const statePtr = &state;
690             #endif
691 0           int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
692             #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
693 0           free(statePtr);
694             #endif
695 0           return cSize;
696             }
697              
698             /* LZ4_compress_HC_destSize() :
699             * only compatible with regular HC parser */
700 0           int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
701             {
702 0           LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
703 0           LZ4HC_init(ctx, (const BYTE*) source);
704 0           return LZ4HC_compress_generic(ctx, source, dest, sourceSizePtr, targetDestSize, cLevel, limitedDestSize);
705             }
706              
707              
708              
709             /**************************************
710             * Streaming Functions
711             **************************************/
712             /* allocation */
713 0           LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
714 0           int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) {
715 0 0         if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
716 0           free(LZ4_streamHCPtr);
717 0           return 0;
718             }
719              
720              
721             /* initialization */
722 0           void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
723             {
724             LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= sizeof(size_t) * LZ4_STREAMHCSIZE_SIZET); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
725 0           LZ4_streamHCPtr->internal_donotuse.base = NULL;
726 0           LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
727 0           }
728              
729 0           void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
730             {
731 0 0         if (compressionLevel < 1) compressionLevel = 1;
732 0 0         if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;
733 0           LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel;
734 0           }
735              
736 0           int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
737             {
738 0           LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
739 0 0         if (dictSize > 64 KB) {
740 0           dictionary += dictSize - 64 KB;
741 0           dictSize = 64 KB;
742             }
743 0           LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
744 0           ctxPtr->end = (const BYTE*)dictionary + dictSize;
745 0 0         if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
746 0           return dictSize;
747             }
748              
749              
750             /* compression */
751              
752 0           static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
753             {
754 0 0         if (ctxPtr->end >= ctxPtr->base + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
755              
756             /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
757 0           ctxPtr->lowLimit = ctxPtr->dictLimit;
758 0           ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
759 0           ctxPtr->dictBase = ctxPtr->base;
760 0           ctxPtr->base = newBlock - ctxPtr->dictLimit;
761 0           ctxPtr->end = newBlock;
762 0           ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
763 0           }
764              
765 0           static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
766             const char* src, char* dst,
767             int* srcSizePtr, int dstCapacity,
768             limitedOutput_directive limit)
769             {
770 0           LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
771             /* auto-init if forgotten */
772 0 0         if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) src);
773              
774             /* Check overflow */
775 0 0         if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
776 0           size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
777 0 0         if (dictSize > 64 KB) dictSize = 64 KB;
778 0           LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
779             }
780              
781             /* Check if blocks follow each other */
782 0 0         if ((const BYTE*)src != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
783              
784             /* Check overlapping input/dictionary space */
785 0           { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
786 0           const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
787 0           const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
788 0 0         if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
    0          
789 0 0         if (sourceEnd > dictEnd) sourceEnd = dictEnd;
790 0           ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
791 0 0         if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
792             }
793             }
794              
795 0           return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
796             }
797              
798 0           int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
799             {
800 0 0         if (dstCapacity < LZ4_compressBound(srcSize))
801 0           return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
802             else
803 0           return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, noLimit);
804             }
805              
806 0           int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)
807             {
808 0           return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, limitedDestSize);
809             }
810              
811              
812              
813             /* dictionary saving */
814              
815 0           int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
816             {
817 0           LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
818 0           int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
819 0 0         if (dictSize > 64 KB) dictSize = 64 KB;
820 0 0         if (dictSize < 4) dictSize = 0;
821 0 0         if (dictSize > prefixSize) dictSize = prefixSize;
822 0           memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
823 0           { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
824 0           streamPtr->end = (const BYTE*)safeBuffer + dictSize;
825 0           streamPtr->base = streamPtr->end - endIndex;
826 0           streamPtr->dictLimit = endIndex - dictSize;
827 0           streamPtr->lowLimit = endIndex - dictSize;
828 0 0         if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
829             }
830 0           return dictSize;
831             }
832              
833              
834             /***********************************
835             * Deprecated Functions
836             ***********************************/
837             /* These functions currently generate deprecation warnings */
838             /* Deprecated compression functions */
839 0           int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
840 0           int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
841 0           int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
842 0           int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
843 0           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); }
844 0           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); }
845 0           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); }
846 0           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); }
847 0           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)); }
848 0           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); }
849              
850              
851             /* Deprecated streaming functions */
852 0           int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
853              
854 0           int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
855             {
856 0           LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
857 0 0         if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */
858 0           LZ4HC_init(ctx, (const BYTE*)inputBuffer);
859 0           ctx->inputBuffer = (BYTE*)inputBuffer;
860 0           return 0;
861             }
862              
863 0           void* LZ4_createHC (char* inputBuffer)
864             {
865 0           LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t));
866 0 0         if (hc4 == NULL) return NULL; /* not enough memory */
867 0           LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
868 0           hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer;
869 0           return hc4;
870             }
871              
872 0           int LZ4_freeHC (void* LZ4HC_Data) {
873 0 0         if (!LZ4HC_Data) return 0; /* support free on NULL */
874 0           FREEMEM(LZ4HC_Data);
875 0           return 0;
876             }
877              
878 0           int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
879             {
880 0           return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, noLimit);
881             }
882              
883 0           int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
884             {
885 0           return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
886             }
887              
888 0           char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
889             {
890 0           LZ4HC_CCtx_internal* const hc4 = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
891 0           int const dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
892 0           return (char*)(hc4->inputBuffer + dictSize);
893             }