extlz4 0.2.5 → 0.3

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