extlz4 0.2.5 → 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }