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