extlz4 0.2.4.2 → 0.3.2

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