extlz4 0.3.3 → 0.3.5

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +43 -3
  4. data/contrib/lz4/CODING_STYLE +57 -0
  5. data/contrib/lz4/LICENSE +3 -2
  6. data/contrib/lz4/Makefile.inc +56 -30
  7. data/contrib/lz4/NEWS +46 -0
  8. data/contrib/lz4/README.md +17 -6
  9. data/contrib/lz4/SECURITY.md +17 -0
  10. data/contrib/lz4/build/README.md +4 -15
  11. data/contrib/lz4/build/VS2022/_build.bat +39 -0
  12. data/contrib/lz4/build/VS2022/_setup.bat +35 -0
  13. data/contrib/lz4/build/VS2022/_test.bat +38 -0
  14. data/contrib/lz4/build/VS2022/build-and-test-win32-debug.bat +26 -0
  15. data/contrib/lz4/build/VS2022/build-and-test-win32-release.bat +26 -0
  16. data/contrib/lz4/build/VS2022/build-and-test-x64-debug.bat +26 -0
  17. data/contrib/lz4/build/VS2022/build-and-test-x64-release.bat +26 -0
  18. data/contrib/lz4/build/{VS2017 → VS2022}/datagen/datagen.vcxproj +11 -7
  19. data/contrib/lz4/build/{VS2017 → VS2022}/frametest/frametest.vcxproj +4 -4
  20. data/contrib/lz4/build/{VS2017 → VS2022}/fullbench/fullbench.vcxproj +4 -4
  21. data/contrib/lz4/build/{VS2017 → VS2022}/fullbench-dll/fullbench-dll.vcxproj +4 -4
  22. data/contrib/lz4/build/{VS2017 → VS2022}/fuzzer/fuzzer.vcxproj +4 -4
  23. data/contrib/lz4/build/{VS2017 → VS2022}/liblz4/liblz4.vcxproj +4 -4
  24. data/contrib/lz4/build/{VS2010 → VS2022}/liblz4-dll/liblz4-dll.rc +1 -1
  25. data/contrib/lz4/build/{VS2017 → VS2022}/liblz4-dll/liblz4-dll.vcxproj +4 -4
  26. data/contrib/lz4/build/{VS2010 → VS2022}/lz4/lz4.rc +1 -1
  27. data/contrib/lz4/build/{VS2017 → VS2022}/lz4/lz4.vcxproj +33 -8
  28. data/contrib/lz4/build/{VS2017 → VS2022}/lz4.sln +5 -2
  29. data/contrib/lz4/build/cmake/CMakeLists.txt +133 -100
  30. data/contrib/lz4/build/cmake/lz4Config.cmake.in +2 -0
  31. data/contrib/lz4/build/meson/GetLz4LibraryVersion.py +39 -0
  32. data/contrib/lz4/build/meson/README.md +34 -0
  33. data/contrib/lz4/build/meson/meson/contrib/gen_manual/meson.build +42 -0
  34. data/contrib/lz4/build/meson/meson/contrib/meson.build +11 -0
  35. data/contrib/lz4/build/meson/meson/examples/meson.build +32 -0
  36. data/contrib/lz4/build/meson/meson/lib/meson.build +87 -0
  37. data/contrib/lz4/build/meson/meson/meson.build +135 -0
  38. data/contrib/lz4/build/meson/meson/ossfuzz/meson.build +35 -0
  39. data/contrib/lz4/build/meson/meson/programs/meson.build +91 -0
  40. data/contrib/lz4/build/meson/meson/tests/meson.build +162 -0
  41. data/contrib/lz4/build/meson/meson.build +31 -0
  42. data/contrib/lz4/build/meson/meson_options.txt +44 -0
  43. data/contrib/lz4/build/visual/README.md +5 -0
  44. data/contrib/lz4/build/visual/generate_solution.cmd +55 -0
  45. data/contrib/lz4/build/visual/generate_vs2015.cmd +3 -0
  46. data/contrib/lz4/build/visual/generate_vs2017.cmd +3 -0
  47. data/contrib/lz4/build/visual/generate_vs2019.cmd +3 -0
  48. data/contrib/lz4/build/visual/generate_vs2022.cmd +3 -0
  49. data/contrib/lz4/lib/LICENSE +1 -1
  50. data/contrib/lz4/lib/README.md +69 -13
  51. data/contrib/lz4/lib/liblz4-dll.rc.in +1 -1
  52. data/contrib/lz4/lib/liblz4.pc.in +3 -3
  53. data/contrib/lz4/lib/lz4.c +608 -274
  54. data/contrib/lz4/lib/lz4.h +212 -102
  55. data/contrib/lz4/lib/lz4file.c +341 -0
  56. data/contrib/lz4/lib/lz4file.h +93 -0
  57. data/contrib/lz4/lib/lz4frame.c +545 -308
  58. data/contrib/lz4/lib/lz4frame.h +252 -124
  59. data/contrib/lz4/lib/lz4frame_static.h +1 -1
  60. data/contrib/lz4/lib/lz4hc.c +1038 -461
  61. data/contrib/lz4/lib/lz4hc.h +57 -56
  62. data/contrib/lz4/lib/xxhash.c +21 -21
  63. data/contrib/lz4/ossfuzz/Makefile +1 -0
  64. data/contrib/lz4/ossfuzz/decompress_fuzzer.c +18 -2
  65. data/contrib/lz4/ossfuzz/fuzz_helpers.h +4 -3
  66. data/contrib/lz4/ossfuzz/round_trip_frame_uncompressed_fuzzer.c +134 -0
  67. data/contrib/lz4/ossfuzz/round_trip_fuzzer.c +66 -6
  68. data/ext/blockapi.c +19 -19
  69. data/ext/extlz4.h +12 -0
  70. data/ext/frameapi.c +26 -26
  71. data/ext/hashargs.c +7 -1
  72. metadata +47 -30
  73. data/contrib/lz4/build/VS2010/datagen/datagen.vcxproj +0 -169
  74. data/contrib/lz4/build/VS2010/frametest/frametest.vcxproj +0 -176
  75. data/contrib/lz4/build/VS2010/fullbench/fullbench.vcxproj +0 -176
  76. data/contrib/lz4/build/VS2010/fullbench-dll/fullbench-dll.vcxproj +0 -180
  77. data/contrib/lz4/build/VS2010/fuzzer/fuzzer.vcxproj +0 -173
  78. data/contrib/lz4/build/VS2010/liblz4/liblz4.vcxproj +0 -175
  79. data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.vcxproj +0 -179
  80. data/contrib/lz4/build/VS2010/lz4/lz4.vcxproj +0 -189
  81. data/contrib/lz4/build/VS2010/lz4.sln +0 -98
  82. data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.rc +0 -51
  83. data/contrib/lz4/build/VS2017/lz4/lz4.rc +0 -51
  84. data/contrib/lz4/tmp +0 -0
  85. data/contrib/lz4/tmpsparse +0 -0
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  LZ4 HC - High Compression Mode of LZ4
3
- Copyright (C) 2011-2017, Yann Collet.
3
+ Copyright (C) 2011-2020, Yann Collet.
4
4
 
5
5
  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
6
 
@@ -39,10 +39,11 @@
39
39
  ***************************************/
40
40
 
41
41
  /*! HEAPMODE :
42
- * Select how default compression function will allocate workplace memory,
43
- * in stack (0:fastest), or in heap (1:requires malloc()).
44
- * Since workplace is rather large, heap mode is recommended.
45
- */
42
+ * Select how stateless HC compression functions like `LZ4_compress_HC()`
43
+ * allocate memory for their workspace:
44
+ * in stack (0:fastest), or in heap (1:default, requires malloc()).
45
+ * Since workspace is rather large, heap mode is recommended.
46
+ **/
46
47
  #ifndef LZ4HC_HEAPMODE
47
48
  # define LZ4HC_HEAPMODE 1
48
49
  #endif
@@ -51,19 +52,19 @@
51
52
  /*=== Dependency ===*/
52
53
  #define LZ4_HC_STATIC_LINKING_ONLY
53
54
  #include "lz4hc.h"
55
+ #include <limits.h>
54
56
 
55
57
 
56
- /*=== Common definitions ===*/
57
- #if defined(__GNUC__)
58
+ /*=== Shared lz4.c code ===*/
59
+ #ifndef LZ4_SRC_INCLUDED
60
+ # if defined(__GNUC__)
58
61
  # pragma GCC diagnostic ignored "-Wunused-function"
59
- #endif
60
- #if defined (__clang__)
62
+ # endif
63
+ # if defined (__clang__)
61
64
  # pragma clang diagnostic ignored "-Wunused-function"
62
- #endif
63
-
64
- #define LZ4_COMMONDEFS_ONLY
65
- #ifndef LZ4_SRC_INCLUDED
66
- #include "lz4.c" /* LZ4_count, constants, mem */
65
+ # endif
66
+ # define LZ4_COMMONDEFS_ONLY
67
+ # include "lz4.c" /* LZ4_count, constants, mem */
67
68
  #endif
68
69
 
69
70
 
@@ -79,17 +80,158 @@ typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;
79
80
  /*=== Macros ===*/
80
81
  #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
81
82
  #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
82
- #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
83
- #define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
83
+
84
+
85
+ /*=== Levels definition ===*/
86
+ typedef enum { lz4mid, lz4hc, lz4opt } lz4hc_strat_e;
87
+ typedef struct {
88
+ lz4hc_strat_e strat;
89
+ int nbSearches;
90
+ U32 targetLength;
91
+ } cParams_t;
92
+ static const cParams_t k_clTable[LZ4HC_CLEVEL_MAX+1] = {
93
+ { lz4mid, 2, 16 }, /* 0, unused */
94
+ { lz4mid, 2, 16 }, /* 1, unused */
95
+ { lz4mid, 2, 16 }, /* 2 */
96
+ { lz4hc, 4, 16 }, /* 3 */
97
+ { lz4hc, 8, 16 }, /* 4 */
98
+ { lz4hc, 16, 16 }, /* 5 */
99
+ { lz4hc, 32, 16 }, /* 6 */
100
+ { lz4hc, 64, 16 }, /* 7 */
101
+ { lz4hc, 128, 16 }, /* 8 */
102
+ { lz4hc, 256, 16 }, /* 9 */
103
+ { lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/
104
+ { lz4opt, 512,128 }, /*11 */
105
+ { lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
106
+ };
107
+
108
+ static cParams_t LZ4HC_getCLevelParams(int cLevel)
109
+ {
110
+ /* note : clevel convention is a bit different from lz4frame,
111
+ * possibly something worth revisiting for consistency */
112
+ if (cLevel < 1)
113
+ cLevel = LZ4HC_CLEVEL_DEFAULT;
114
+ cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);
115
+ return k_clTable[cLevel];
116
+ }
117
+
118
+
119
+ /*=== Hashing ===*/
120
+ #define LZ4HC_HASHSIZE 4
121
+ #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
122
+ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
123
+
124
+ #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)
125
+ /* lie to the compiler about data alignment; use with caution */
126
+ static U64 LZ4_read64(const void* memPtr) { return *(const U64*) memPtr; }
127
+
128
+ #elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)
129
+ /* __pack instructions are safer, but compiler specific */
130
+ LZ4_PACK(typedef struct { U64 u64; }) LZ4_unalign64;
131
+ static U64 LZ4_read64(const void* ptr) { return ((const LZ4_unalign64*)ptr)->u64; }
132
+
133
+ #else /* safe and portable access using memcpy() */
134
+ static U64 LZ4_read64(const void* memPtr)
135
+ {
136
+ U64 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;
137
+ }
138
+
139
+ #endif /* LZ4_FORCE_MEMORY_ACCESS */
140
+
141
+ #define LZ4MID_HASHSIZE 8
142
+ #define LZ4MID_HASHLOG (LZ4HC_HASH_LOG-1)
143
+ #define LZ4MID_HASHTABLESIZE (1 << LZ4MID_HASHLOG)
144
+
145
+ static U32 LZ4MID_hash4(U32 v) { return (v * 2654435761U) >> (32-LZ4MID_HASHLOG); }
146
+ static U32 LZ4MID_hash4Ptr(const void* ptr) { return LZ4MID_hash4(LZ4_read32(ptr)); }
147
+ /* note: hash7 hashes the lower 56-bits.
148
+ * It presumes input was read using little endian.*/
149
+ static U32 LZ4MID_hash7(U64 v) { return (U32)(((v << (64-56)) * 58295818150454627ULL) >> (64-LZ4MID_HASHLOG)) ; }
150
+ static U64 LZ4_readLE64(const void* memPtr);
151
+ static U32 LZ4MID_hash8Ptr(const void* ptr) { return LZ4MID_hash7(LZ4_readLE64(ptr)); }
152
+
153
+ static U64 LZ4_readLE64(const void* memPtr)
154
+ {
155
+ if (LZ4_isLittleEndian()) {
156
+ return LZ4_read64(memPtr);
157
+ } else {
158
+ const BYTE* p = (const BYTE*)memPtr;
159
+ /* note: relies on the compiler to simplify this expression */
160
+ return (U64)p[0] | ((U64)p[1]<<8) | ((U64)p[2]<<16) | ((U64)p[3]<<24)
161
+ | ((U64)p[4]<<32) | ((U64)p[5]<<40) | ((U64)p[6]<<48) | ((U64)p[7]<<56);
162
+ }
163
+ }
164
+
165
+
166
+ /*=== Count match length ===*/
167
+ LZ4_FORCE_INLINE
168
+ unsigned LZ4HC_NbCommonBytes32(U32 val)
169
+ {
170
+ assert(val != 0);
171
+ if (LZ4_isLittleEndian()) {
172
+ # if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
173
+ unsigned long r;
174
+ _BitScanReverse(&r, val);
175
+ return (unsigned)((31 - r) >> 3);
176
+ # elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
177
+ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
178
+ !defined(LZ4_FORCE_SW_BITCOUNT)
179
+ return (unsigned)__builtin_clz(val) >> 3;
180
+ # else
181
+ val >>= 8;
182
+ val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |
183
+ (val + 0x00FF0000)) >> 24;
184
+ return (unsigned)val ^ 3;
185
+ # endif
186
+ } else {
187
+ # if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)
188
+ unsigned long r;
189
+ _BitScanForward(&r, val);
190
+ return (unsigned)(r >> 3);
191
+ # elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \
192
+ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \
193
+ !defined(LZ4_FORCE_SW_BITCOUNT)
194
+ return (unsigned)__builtin_ctz(val) >> 3;
195
+ # else
196
+ const U32 m = 0x01010101;
197
+ return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;
198
+ # endif
199
+ }
200
+ }
201
+
202
+ /** LZ4HC_countBack() :
203
+ * @return : negative value, nb of common bytes before ip/match */
204
+ LZ4_FORCE_INLINE
205
+ int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,
206
+ const BYTE* const iMin, const BYTE* const mMin)
207
+ {
208
+ int back = 0;
209
+ int const min = (int)MAX(iMin - ip, mMin - match);
210
+ assert(min <= 0);
211
+ assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));
212
+ assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));
213
+
214
+ while ((back - min) > 3) {
215
+ U32 const v = LZ4_read32(ip + back - 4) ^ LZ4_read32(match + back - 4);
216
+ if (v) {
217
+ return (back - (int)LZ4HC_NbCommonBytes32(v));
218
+ } else back -= 4; /* 4-byte step */
219
+ }
220
+ /* check remainder if any */
221
+ while ( (back > min)
222
+ && (ip[back-1] == match[back-1]) )
223
+ back--;
224
+ return back;
225
+ }
226
+
227
+ /*=== Chain table updates ===*/
84
228
  #define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
85
229
  /* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
86
230
  #define UPDATABLE(ip, op, anchor) &ip, &op, &anchor
87
231
 
88
- static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
89
-
90
232
 
91
233
  /**************************************
92
- * HC Compression
234
+ * Init
93
235
  **************************************/
94
236
  static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
95
237
  {
@@ -99,57 +241,564 @@ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
99
241
 
100
242
  static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
101
243
  {
102
- uptrval startingOffset = (uptrval)(hc4->end - hc4->base);
103
- if (startingOffset > 1 GB) {
244
+ size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);
245
+ size_t newStartingOffset = bufferSize + hc4->dictLimit;
246
+ DEBUGLOG(5, "LZ4HC_init_internal");
247
+ assert(newStartingOffset >= bufferSize); /* check overflow */
248
+ if (newStartingOffset > 1 GB) {
104
249
  LZ4HC_clearTables(hc4);
105
- startingOffset = 0;
250
+ newStartingOffset = 0;
106
251
  }
107
- startingOffset += 64 KB;
108
- hc4->nextToUpdate = (U32) startingOffset;
109
- hc4->base = start - startingOffset;
252
+ newStartingOffset += 64 KB;
253
+ hc4->nextToUpdate = (U32)newStartingOffset;
254
+ hc4->prefixStart = start;
110
255
  hc4->end = start;
111
- hc4->dictBase = start - startingOffset;
112
- hc4->dictLimit = (U32) startingOffset;
113
- hc4->lowLimit = (U32) startingOffset;
256
+ hc4->dictStart = start;
257
+ hc4->dictLimit = (U32)newStartingOffset;
258
+ hc4->lowLimit = (U32)newStartingOffset;
259
+ }
260
+
261
+
262
+ /**************************************
263
+ * Encode
264
+ **************************************/
265
+ /* LZ4HC_encodeSequence() :
266
+ * @return : 0 if ok,
267
+ * 1 if buffer issue detected */
268
+ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
269
+ const BYTE** _ip,
270
+ BYTE** _op,
271
+ const BYTE** _anchor,
272
+ int matchLength,
273
+ int offset,
274
+ limitedOutput_directive limit,
275
+ BYTE* oend)
276
+ {
277
+ #define ip (*_ip)
278
+ #define op (*_op)
279
+ #define anchor (*_anchor)
280
+
281
+ size_t length;
282
+ BYTE* const token = op++;
283
+
284
+ #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
285
+ static const BYTE* start = NULL;
286
+ static U32 totalCost = 0;
287
+ U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
288
+ U32 const ll = (U32)(ip - anchor);
289
+ U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
290
+ U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
291
+ U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
292
+ if (start==NULL) start = anchor; /* only works for single segment */
293
+ /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
294
+ DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5i, cost:%4u + %5u",
295
+ pos,
296
+ (U32)(ip - anchor), matchLength, offset,
297
+ cost, totalCost);
298
+ totalCost += cost;
299
+ #endif
300
+
301
+ /* Encode Literal length */
302
+ length = (size_t)(ip - anchor);
303
+ LZ4_STATIC_ASSERT(notLimited == 0);
304
+ /* Check output limit */
305
+ if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
306
+ DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
307
+ (int)length, (int)(oend - op));
308
+ return 1;
309
+ }
310
+ if (length >= RUN_MASK) {
311
+ size_t len = length - RUN_MASK;
312
+ *token = (RUN_MASK << ML_BITS);
313
+ for(; len >= 255 ; len -= 255) *op++ = 255;
314
+ *op++ = (BYTE)len;
315
+ } else {
316
+ *token = (BYTE)(length << ML_BITS);
317
+ }
318
+
319
+ /* Copy Literals */
320
+ LZ4_wildCopy8(op, anchor, op + length);
321
+ op += length;
322
+
323
+ /* Encode Offset */
324
+ assert(offset <= LZ4_DISTANCE_MAX );
325
+ assert(offset > 0);
326
+ LZ4_writeLE16(op, (U16)(offset)); op += 2;
327
+
328
+ /* Encode MatchLength */
329
+ assert(matchLength >= MINMATCH);
330
+ length = (size_t)matchLength - MINMATCH;
331
+ if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
332
+ DEBUGLOG(6, "Not enough room to write match length");
333
+ return 1; /* Check output limit */
334
+ }
335
+ if (length >= ML_MASK) {
336
+ *token += ML_MASK;
337
+ length -= ML_MASK;
338
+ for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
339
+ if (length >= 255) { length -= 255; *op++ = 255; }
340
+ *op++ = (BYTE)length;
341
+ } else {
342
+ *token += (BYTE)(length);
343
+ }
344
+
345
+ /* Prepare next loop */
346
+ ip += matchLength;
347
+ anchor = ip;
348
+
349
+ return 0;
350
+
351
+ #undef ip
352
+ #undef op
353
+ #undef anchor
114
354
  }
115
355
 
116
356
 
357
+ typedef struct {
358
+ int off;
359
+ int len;
360
+ int back; /* negative value */
361
+ } LZ4HC_match_t;
362
+
363
+ LZ4HC_match_t LZ4HC_searchExtDict(const BYTE* ip, U32 ipIndex,
364
+ const BYTE* const iLowLimit, const BYTE* const iHighLimit,
365
+ const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex,
366
+ int currentBestML, int nbAttempts)
367
+ {
368
+ size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
369
+ U32 lDictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
370
+ U32 matchIndex = lDictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
371
+ int offset = 0, sBack = 0;
372
+ assert(lDictEndIndex <= 1 GB);
373
+ if (lDictMatchIndex>0)
374
+ DEBUGLOG(7, "lDictEndIndex = %zu, lDictMatchIndex = %u", lDictEndIndex, lDictMatchIndex);
375
+ while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
376
+ const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + lDictMatchIndex;
377
+
378
+ if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
379
+ int mlt;
380
+ int back = 0;
381
+ const BYTE* vLimit = ip + (lDictEndIndex - lDictMatchIndex);
382
+ if (vLimit > iHighLimit) vLimit = iHighLimit;
383
+ mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
384
+ back = (ip > iLowLimit) ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
385
+ mlt -= back;
386
+ if (mlt > currentBestML) {
387
+ currentBestML = mlt;
388
+ offset = (int)(ipIndex - matchIndex);
389
+ sBack = back;
390
+ DEBUGLOG(7, "found match of length %i within extDictCtx", currentBestML);
391
+ } }
392
+
393
+ { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, lDictMatchIndex);
394
+ lDictMatchIndex -= nextOffset;
395
+ matchIndex -= nextOffset;
396
+ } }
397
+
398
+ { LZ4HC_match_t md;
399
+ md.len = currentBestML;
400
+ md.off = offset;
401
+ md.back = sBack;
402
+ return md;
403
+ }
404
+ }
405
+
406
+ typedef LZ4HC_match_t (*LZ4MID_searchIntoDict_f)(const BYTE* ip, U32 ipIndex,
407
+ const BYTE* const iHighLimit,
408
+ const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex);
409
+
410
+ static LZ4HC_match_t LZ4MID_searchHCDict(const BYTE* ip, U32 ipIndex,
411
+ const BYTE* const iHighLimit,
412
+ const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)
413
+ {
414
+ return LZ4HC_searchExtDict(ip,ipIndex,
415
+ ip, iHighLimit,
416
+ dictCtx, gDictEndIndex,
417
+ MINMATCH-1, 2);
418
+ }
419
+
420
+ static LZ4HC_match_t LZ4MID_searchExtDict(const BYTE* ip, U32 ipIndex,
421
+ const BYTE* const iHighLimit,
422
+ const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)
423
+ {
424
+ size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
425
+ const U32* const hash4Table = dictCtx->hashTable;
426
+ const U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
427
+ DEBUGLOG(7, "LZ4MID_searchExtDict (ipIdx=%u)", ipIndex);
428
+
429
+ /* search long match first */
430
+ { U32 l8DictMatchIndex = hash8Table[LZ4MID_hash8Ptr(ip)];
431
+ U32 m8Index = l8DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
432
+ assert(lDictEndIndex <= 1 GB);
433
+ if (ipIndex - m8Index <= LZ4_DISTANCE_MAX) {
434
+ const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l8DictMatchIndex;
435
+ const size_t safeLen = MIN(lDictEndIndex - l8DictMatchIndex, (size_t)(iHighLimit - ip));
436
+ int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
437
+ if (mlt >= MINMATCH) {
438
+ LZ4HC_match_t md;
439
+ DEBUGLOG(7, "Found long ExtDict match of len=%u", mlt);
440
+ md.len = mlt;
441
+ md.off = (int)(ipIndex - m8Index);
442
+ md.back = 0;
443
+ return md;
444
+ }
445
+ }
446
+ }
447
+
448
+ /* search for short match second */
449
+ { U32 l4DictMatchIndex = hash4Table[LZ4MID_hash4Ptr(ip)];
450
+ U32 m4Index = l4DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;
451
+ if (ipIndex - m4Index <= LZ4_DISTANCE_MAX) {
452
+ const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l4DictMatchIndex;
453
+ const size_t safeLen = MIN(lDictEndIndex - l4DictMatchIndex, (size_t)(iHighLimit - ip));
454
+ int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);
455
+ if (mlt >= MINMATCH) {
456
+ LZ4HC_match_t md;
457
+ DEBUGLOG(7, "Found short ExtDict match of len=%u", mlt);
458
+ md.len = mlt;
459
+ md.off = (int)(ipIndex - m4Index);
460
+ md.back = 0;
461
+ return md;
462
+ }
463
+ }
464
+ }
465
+
466
+ /* nothing found */
467
+ { LZ4HC_match_t const md = {0, 0, 0 };
468
+ return md;
469
+ }
470
+ }
471
+
472
+ /**************************************
473
+ * Mid Compression (level 2)
474
+ **************************************/
475
+
476
+ LZ4_FORCE_INLINE void
477
+ LZ4MID_addPosition(U32* hTable, U32 hValue, U32 index)
478
+ {
479
+ hTable[hValue] = index;
480
+ }
481
+
482
+ #define ADDPOS8(_p, _idx) LZ4MID_addPosition(hash8Table, LZ4MID_hash8Ptr(_p), _idx)
483
+ #define ADDPOS4(_p, _idx) LZ4MID_addPosition(hash4Table, LZ4MID_hash4Ptr(_p), _idx)
484
+
485
+ /* Fill hash tables with references into dictionary.
486
+ * The resulting table is only exploitable by LZ4MID (level 2) */
487
+ static void
488
+ LZ4MID_fillHTable (LZ4HC_CCtx_internal* cctx, const void* dict, size_t size)
489
+ {
490
+ U32* const hash4Table = cctx->hashTable;
491
+ U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
492
+ const BYTE* const prefixPtr = (const BYTE*)dict;
493
+ U32 const prefixIdx = cctx->dictLimit;
494
+ U32 const target = prefixIdx + (U32)size - LZ4MID_HASHSIZE;
495
+ U32 idx = cctx->nextToUpdate;
496
+ assert(dict == cctx->prefixStart);
497
+ DEBUGLOG(4, "LZ4MID_fillHTable (size:%zu)", size);
498
+ if (size <= LZ4MID_HASHSIZE)
499
+ return;
500
+
501
+ for (; idx < target; idx += 3) {
502
+ ADDPOS4(prefixPtr+idx-prefixIdx, idx);
503
+ ADDPOS8(prefixPtr+idx+1-prefixIdx, idx+1);
504
+ }
505
+
506
+ idx = (size > 32 KB + LZ4MID_HASHSIZE) ? target - 32 KB : cctx->nextToUpdate;
507
+ for (; idx < target; idx += 1) {
508
+ ADDPOS8(prefixPtr+idx-prefixIdx, idx);
509
+ }
510
+
511
+ cctx->nextToUpdate = target;
512
+ }
513
+
514
+ static LZ4MID_searchIntoDict_f select_searchDict_function(const LZ4HC_CCtx_internal* dictCtx)
515
+ {
516
+ if (dictCtx == NULL) return NULL;
517
+ if (LZ4HC_getCLevelParams(dictCtx->compressionLevel).strat == lz4mid)
518
+ return LZ4MID_searchExtDict;
519
+ return LZ4MID_searchHCDict;
520
+ }
521
+
522
+ static int LZ4MID_compress (
523
+ LZ4HC_CCtx_internal* const ctx,
524
+ const char* const src,
525
+ char* const dst,
526
+ int* srcSizePtr,
527
+ int const maxOutputSize,
528
+ const limitedOutput_directive limit,
529
+ const dictCtx_directive dict
530
+ )
531
+ {
532
+ U32* const hash4Table = ctx->hashTable;
533
+ U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;
534
+ const BYTE* ip = (const BYTE*)src;
535
+ const BYTE* anchor = ip;
536
+ const BYTE* const iend = ip + *srcSizePtr;
537
+ const BYTE* const mflimit = iend - MFLIMIT;
538
+ const BYTE* const matchlimit = (iend - LASTLITERALS);
539
+ const BYTE* const ilimit = (iend - LZ4MID_HASHSIZE);
540
+ BYTE* op = (BYTE*)dst;
541
+ BYTE* oend = op + maxOutputSize;
542
+
543
+ const BYTE* const prefixPtr = ctx->prefixStart;
544
+ const U32 prefixIdx = ctx->dictLimit;
545
+ const U32 ilimitIdx = (U32)(ilimit - prefixPtr) + prefixIdx;
546
+ const BYTE* const dictStart = ctx->dictStart;
547
+ const U32 dictIdx = ctx->lowLimit;
548
+ const U32 gDictEndIndex = ctx->lowLimit;
549
+ const LZ4MID_searchIntoDict_f searchIntoDict = (dict == usingDictCtxHc) ? select_searchDict_function(ctx->dictCtx) : NULL;
550
+ unsigned matchLength;
551
+ unsigned matchDistance;
552
+
553
+ /* input sanitization */
554
+ DEBUGLOG(5, "LZ4MID_compress (%i bytes)", *srcSizePtr);
555
+ if (dict == usingDictCtxHc) DEBUGLOG(5, "usingDictCtxHc");
556
+ assert(*srcSizePtr >= 0);
557
+ if (*srcSizePtr) assert(src != NULL);
558
+ if (maxOutputSize) assert(dst != NULL);
559
+ if (*srcSizePtr < 0) return 0; /* invalid */
560
+ if (maxOutputSize < 0) return 0; /* invalid */
561
+ if (*srcSizePtr > LZ4_MAX_INPUT_SIZE) {
562
+ /* forbidden: no input is allowed to be that large */
563
+ return 0;
564
+ }
565
+ if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
566
+ if (*srcSizePtr < LZ4_minLength)
567
+ goto _lz4mid_last_literals; /* Input too small, no compression (all literals) */
568
+
569
+ /* main loop */
570
+ while (ip <= mflimit) {
571
+ const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
572
+ /* search long match */
573
+ { U32 const h8 = LZ4MID_hash8Ptr(ip);
574
+ U32 const pos8 = hash8Table[h8];
575
+ assert(h8 < LZ4MID_HASHTABLESIZE);
576
+ assert(pos8 < ipIndex);
577
+ LZ4MID_addPosition(hash8Table, h8, ipIndex);
578
+ if (ipIndex - pos8 <= LZ4_DISTANCE_MAX) {
579
+ /* match candidate found */
580
+ if (pos8 >= prefixIdx) {
581
+ const BYTE* const matchPtr = prefixPtr + pos8 - prefixIdx;
582
+ assert(matchPtr < ip);
583
+ matchLength = LZ4_count(ip, matchPtr, matchlimit);
584
+ if (matchLength >= MINMATCH) {
585
+ DEBUGLOG(7, "found long match at pos %u (len=%u)", pos8, matchLength);
586
+ matchDistance = ipIndex - pos8;
587
+ goto _lz4mid_encode_sequence;
588
+ }
589
+ } else {
590
+ if (pos8 >= dictIdx) {
591
+ /* extDict match candidate */
592
+ const BYTE* const matchPtr = dictStart + (pos8 - dictIdx);
593
+ const size_t safeLen = MIN(prefixIdx - pos8, (size_t)(matchlimit - ip));
594
+ matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
595
+ if (matchLength >= MINMATCH) {
596
+ DEBUGLOG(7, "found long match at ExtDict pos %u (len=%u)", pos8, matchLength);
597
+ matchDistance = ipIndex - pos8;
598
+ goto _lz4mid_encode_sequence;
599
+ }
600
+ }
601
+ }
602
+ } }
603
+ /* search short match */
604
+ { U32 const h4 = LZ4MID_hash4Ptr(ip);
605
+ U32 const pos4 = hash4Table[h4];
606
+ assert(h4 < LZ4MID_HASHTABLESIZE);
607
+ assert(pos4 < ipIndex);
608
+ LZ4MID_addPosition(hash4Table, h4, ipIndex);
609
+ if (ipIndex - pos4 <= LZ4_DISTANCE_MAX) {
610
+ /* match candidate found */
611
+ if (pos4 >= prefixIdx) {
612
+ /* only search within prefix */
613
+ const BYTE* const matchPtr = prefixPtr + (pos4 - prefixIdx);
614
+ assert(matchPtr < ip);
615
+ assert(matchPtr >= prefixPtr);
616
+ matchLength = LZ4_count(ip, matchPtr, matchlimit);
617
+ if (matchLength >= MINMATCH) {
618
+ /* short match found, let's just check ip+1 for longer */
619
+ U32 const h8 = LZ4MID_hash8Ptr(ip+1);
620
+ U32 const pos8 = hash8Table[h8];
621
+ U32 const m2Distance = ipIndex + 1 - pos8;
622
+ matchDistance = ipIndex - pos4;
623
+ if ( m2Distance <= LZ4_DISTANCE_MAX
624
+ && pos8 >= prefixIdx /* only search within prefix */
625
+ && likely(ip < mflimit)
626
+ ) {
627
+ const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx);
628
+ unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit);
629
+ if (ml2 > matchLength) {
630
+ LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
631
+ ip++;
632
+ matchLength = ml2;
633
+ matchDistance = m2Distance;
634
+ } }
635
+ goto _lz4mid_encode_sequence;
636
+ }
637
+ } else {
638
+ if (pos4 >= dictIdx) {
639
+ /* extDict match candidate */
640
+ const BYTE* const matchPtr = dictStart + (pos4 - dictIdx);
641
+ const size_t safeLen = MIN(prefixIdx - pos4, (size_t)(matchlimit - ip));
642
+ matchLength = LZ4_count(ip, matchPtr, ip + safeLen);
643
+ if (matchLength >= MINMATCH) {
644
+ DEBUGLOG(7, "found match at ExtDict pos %u (len=%u)", pos4, matchLength);
645
+ matchDistance = ipIndex - pos4;
646
+ goto _lz4mid_encode_sequence;
647
+ }
648
+ }
649
+ }
650
+ } }
651
+ /* no match found in prefix */
652
+ if ( (dict == usingDictCtxHc)
653
+ && (ipIndex - gDictEndIndex < LZ4_DISTANCE_MAX - 8) ) {
654
+ /* search a match into external dictionary */
655
+ LZ4HC_match_t dMatch = searchIntoDict(ip, ipIndex,
656
+ matchlimit,
657
+ ctx->dictCtx, gDictEndIndex);
658
+ if (dMatch.len >= MINMATCH) {
659
+ DEBUGLOG(7, "found Dictionary match (offset=%i)", dMatch.off);
660
+ assert(dMatch.back == 0);
661
+ matchLength = (unsigned)dMatch.len;
662
+ matchDistance = (unsigned)dMatch.off;
663
+ goto _lz4mid_encode_sequence;
664
+ }
665
+ }
666
+ /* no match found */
667
+ ip += 1 + ((ip-anchor) >> 9); /* skip faster over incompressible data */
668
+ continue;
669
+
670
+ _lz4mid_encode_sequence:
671
+ /* catch back */
672
+ while (((ip > anchor) & ((U32)(ip-prefixPtr) > matchDistance)) && (unlikely(ip[-1] == ip[-(int)matchDistance-1]))) {
673
+ ip--; matchLength++;
674
+ };
675
+
676
+ /* fill table with beginning of match */
677
+ ADDPOS8(ip+1, ipIndex+1);
678
+ ADDPOS8(ip+2, ipIndex+2);
679
+ ADDPOS4(ip+1, ipIndex+1);
680
+
681
+ /* encode */
682
+ { BYTE* const saved_op = op;
683
+ /* LZ4HC_encodeSequence always updates @op; on success, it updates @ip and @anchor */
684
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
685
+ (int)matchLength, (int)matchDistance,
686
+ limit, oend) ) {
687
+ op = saved_op; /* restore @op value before failed LZ4HC_encodeSequence */
688
+ goto _lz4mid_dest_overflow;
689
+ }
690
+ }
691
+
692
+ /* fill table with end of match */
693
+ { U32 endMatchIdx = (U32)(ip-prefixPtr) + prefixIdx;
694
+ U32 pos_m2 = endMatchIdx - 2;
695
+ if (pos_m2 < ilimitIdx) {
696
+ if (likely(ip - prefixPtr > 5)) {
697
+ ADDPOS8(ip-5, endMatchIdx - 5);
698
+ }
699
+ ADDPOS8(ip-3, endMatchIdx - 3);
700
+ ADDPOS8(ip-2, endMatchIdx - 2);
701
+ ADDPOS4(ip-2, endMatchIdx - 2);
702
+ ADDPOS4(ip-1, endMatchIdx - 1);
703
+ }
704
+ }
705
+ }
706
+
707
+ _lz4mid_last_literals:
708
+ /* Encode Last Literals */
709
+ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */
710
+ size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
711
+ size_t const totalSize = 1 + llAdd + lastRunSize;
712
+ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
713
+ if (limit && (op + totalSize > oend)) {
714
+ if (limit == limitedOutput) return 0; /* not enough space in @dst */
715
+ /* adapt lastRunSize to fill 'dest' */
716
+ lastRunSize = (size_t)(oend - op) - 1 /*token*/;
717
+ llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
718
+ lastRunSize -= llAdd;
719
+ }
720
+ DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
721
+ ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
722
+
723
+ if (lastRunSize >= RUN_MASK) {
724
+ size_t accumulator = lastRunSize - RUN_MASK;
725
+ *op++ = (RUN_MASK << ML_BITS);
726
+ for(; accumulator >= 255 ; accumulator -= 255)
727
+ *op++ = 255;
728
+ *op++ = (BYTE) accumulator;
729
+ } else {
730
+ *op++ = (BYTE)(lastRunSize << ML_BITS);
731
+ }
732
+ assert(lastRunSize <= (size_t)(oend - op));
733
+ LZ4_memcpy(op, anchor, lastRunSize);
734
+ op += lastRunSize;
735
+ }
736
+
737
+ /* End */
738
+ DEBUGLOG(5, "compressed %i bytes into %i bytes", *srcSizePtr, (int)((char*)op - dst));
739
+ assert(ip >= (const BYTE*)src);
740
+ assert(ip <= iend);
741
+ *srcSizePtr = (int)(ip - (const BYTE*)src);
742
+ assert((char*)op >= dst);
743
+ assert(op <= oend);
744
+ assert((char*)op - dst < INT_MAX);
745
+ return (int)((char*)op - dst);
746
+
747
+ _lz4mid_dest_overflow:
748
+ if (limit == fillOutput) {
749
+ /* Assumption : @ip, @anchor, @optr and @matchLength must be set correctly */
750
+ size_t const ll = (size_t)(ip - anchor);
751
+ size_t const ll_addbytes = (ll + 240) / 255;
752
+ size_t const ll_totalCost = 1 + ll_addbytes + ll;
753
+ BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
754
+ DEBUGLOG(6, "Last sequence is overflowing : %u literals, %u remaining space",
755
+ (unsigned)ll, (unsigned)(oend-op));
756
+ if (op + ll_totalCost <= maxLitPos) {
757
+ /* ll validated; now adjust match length */
758
+ size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
759
+ size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);
760
+ assert(maxMlSize < INT_MAX);
761
+ if ((size_t)matchLength > maxMlSize) matchLength= (unsigned)maxMlSize;
762
+ if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + matchLength >= MFLIMIT) {
763
+ DEBUGLOG(6, "Let's encode a last sequence (ll=%u, ml=%u)", (unsigned)ll, matchLength);
764
+ LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
765
+ (int)matchLength, (int)matchDistance,
766
+ notLimited, oend);
767
+ } }
768
+ DEBUGLOG(6, "Let's finish with a run of literals (%u bytes left)", (unsigned)(oend-op));
769
+ goto _lz4mid_last_literals;
770
+ }
771
+ /* compression failed */
772
+ return 0;
773
+ }
774
+
775
+
776
+ /**************************************
777
+ * HC Compression - Search
778
+ **************************************/
779
+
117
780
  /* Update chains up to ip (excluded) */
118
781
  LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
119
782
  {
120
783
  U16* const chainTable = hc4->chainTable;
121
784
  U32* const hashTable = hc4->hashTable;
122
- const BYTE* const base = hc4->base;
123
- U32 const target = (U32)(ip - base);
785
+ const BYTE* const prefixPtr = hc4->prefixStart;
786
+ U32 const prefixIdx = hc4->dictLimit;
787
+ U32 const target = (U32)(ip - prefixPtr) + prefixIdx;
124
788
  U32 idx = hc4->nextToUpdate;
789
+ assert(ip >= prefixPtr);
790
+ assert(target >= prefixIdx);
125
791
 
126
792
  while (idx < target) {
127
- U32 const h = LZ4HC_hashPtr(base+idx);
793
+ U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);
128
794
  size_t delta = idx - hashTable[h];
129
795
  if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;
130
796
  DELTANEXTU16(chainTable, idx) = (U16)delta;
131
797
  hashTable[h] = idx;
132
798
  idx++;
133
- }
134
-
135
- hc4->nextToUpdate = target;
136
- }
137
-
138
- /** LZ4HC_countBack() :
139
- * @return : negative value, nb of common bytes before ip/match */
140
- LZ4_FORCE_INLINE
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;
799
+ }
800
+
801
+ hc4->nextToUpdate = target;
153
802
  }
154
803
 
155
804
  #if defined(_MSC_VER)
@@ -193,15 +842,14 @@ LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)
193
842
  BYTE const byte = (BYTE)(pattern >> bitOffset);
194
843
  if (*ip != byte) break;
195
844
  ip ++; bitOffset -= 8;
196
- }
197
- }
845
+ } }
198
846
 
199
847
  return (unsigned)(ip - iStart);
200
848
  }
201
849
 
202
850
  /* LZ4HC_reverseCountPattern() :
203
851
  * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
204
- * read using natural platform endianess */
852
+ * read using natural platform endianness */
205
853
  static unsigned
206
854
  LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
207
855
  {
@@ -211,7 +859,7 @@ LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
211
859
  if (LZ4_read32(ip-4) != pattern) break;
212
860
  ip -= 4;
213
861
  }
214
- { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */
862
+ { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
215
863
  while (likely(ip>iLow)) {
216
864
  if (ip[-1] != *bytePtr) break;
217
865
  ip--; bytePtr--;
@@ -232,30 +880,29 @@ static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)
232
880
  typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
233
881
  typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
234
882
 
235
- LZ4_FORCE_INLINE int
883
+
884
+ LZ4_FORCE_INLINE LZ4HC_match_t
236
885
  LZ4HC_InsertAndGetWiderMatch (
237
- LZ4HC_CCtx_internal* hc4,
238
- const BYTE* const ip,
239
- const BYTE* const iLowLimit,
240
- const BYTE* const iHighLimit,
241
- int longest,
242
- const BYTE** matchpos,
243
- const BYTE** startpos,
244
- const int maxNbAttempts,
245
- const int patternAnalysis,
246
- const int chainSwap,
247
- const dictCtx_directive dict,
248
- const HCfavor_e favorDecSpeed)
886
+ LZ4HC_CCtx_internal* const hc4,
887
+ const BYTE* const ip,
888
+ const BYTE* const iLowLimit, const BYTE* const iHighLimit,
889
+ int longest,
890
+ const int maxNbAttempts,
891
+ const int patternAnalysis, const int chainSwap,
892
+ const dictCtx_directive dict,
893
+ const HCfavor_e favorDecSpeed)
249
894
  {
250
895
  U16* const chainTable = hc4->chainTable;
251
- U32* const HashTable = hc4->hashTable;
252
- const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;
253
- const BYTE* const base = hc4->base;
254
- const U32 dictLimit = hc4->dictLimit;
255
- const BYTE* const lowPrefixPtr = base + dictLimit;
256
- const U32 ipIndex = (U32)(ip - base);
257
- const U32 lowestMatchIndex = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
258
- const BYTE* const dictBase = hc4->dictBase;
896
+ U32* const hashTable = hc4->hashTable;
897
+ const LZ4HC_CCtx_internal* const dictCtx = hc4->dictCtx;
898
+ const BYTE* const prefixPtr = hc4->prefixStart;
899
+ const U32 prefixIdx = hc4->dictLimit;
900
+ const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;
901
+ const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);
902
+ const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;
903
+ const BYTE* const dictStart = hc4->dictStart;
904
+ const U32 dictIdx = hc4->lowLimit;
905
+ const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;
259
906
  int const lookBackLength = (int)(ip-iLowLimit);
260
907
  int nbAttempts = maxNbAttempts;
261
908
  U32 matchChainPos = 0;
@@ -263,54 +910,58 @@ LZ4HC_InsertAndGetWiderMatch (
263
910
  U32 matchIndex;
264
911
  repeat_state_e repeat = rep_untested;
265
912
  size_t srcPatternLength = 0;
913
+ int offset = 0, sBack = 0;
266
914
 
267
915
  DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");
268
916
  /* First Match */
269
- LZ4HC_Insert(hc4, ip);
270
- matchIndex = HashTable[LZ4HC_hashPtr(ip)];
271
- DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
272
- matchIndex, lowestMatchIndex);
917
+ LZ4HC_Insert(hc4, ip); /* insert all prior positions up to ip (excluded) */
918
+ matchIndex = hashTable[LZ4HC_hashPtr(ip)];
919
+ DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)",
920
+ ipIndex, matchIndex, lowestMatchIndex);
273
921
 
274
922
  while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {
275
923
  int matchLength=0;
276
924
  nbAttempts--;
277
925
  assert(matchIndex < ipIndex);
278
926
  if (favorDecSpeed && (ipIndex - matchIndex < 8)) {
279
- /* do nothing */
280
- } else if (matchIndex >= dictLimit) { /* within current Prefix */
281
- const BYTE* const matchPtr = base + matchIndex;
282
- assert(matchPtr >= lowPrefixPtr);
927
+ /* do nothing:
928
+ * favorDecSpeed intentionally skips matches with offset < 8 */
929
+ } else if (matchIndex >= prefixIdx) { /* within current Prefix */
930
+ const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);
283
931
  assert(matchPtr < ip);
284
932
  assert(longest >= 1);
285
933
  if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {
286
934
  if (LZ4_read32(matchPtr) == pattern) {
287
- int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, lowPrefixPtr) : 0;
935
+ int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;
288
936
  matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
289
937
  matchLength -= back;
290
938
  if (matchLength > longest) {
291
939
  longest = matchLength;
292
- *matchpos = matchPtr + back;
293
- *startpos = ip + back;
940
+ offset = (int)(ipIndex - matchIndex);
941
+ sBack = back;
942
+ DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back);
294
943
  } } }
295
- } else { /* lowestMatchIndex <= matchIndex < dictLimit */
296
- const BYTE* const matchPtr = dictBase + matchIndex;
297
- if (LZ4_read32(matchPtr) == pattern) {
298
- const BYTE* const dictStart = dictBase + hc4->lowLimit;
944
+ } else { /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */
945
+ const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);
946
+ assert(matchIndex >= dictIdx);
947
+ if ( likely(matchIndex <= prefixIdx - 4)
948
+ && (LZ4_read32(matchPtr) == pattern) ) {
299
949
  int back = 0;
300
- const BYTE* vLimit = ip + (dictLimit - matchIndex);
950
+ const BYTE* vLimit = ip + (prefixIdx - matchIndex);
301
951
  if (vLimit > iHighLimit) vLimit = iHighLimit;
302
952
  matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
303
953
  if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
304
- matchLength += LZ4_count(ip+matchLength, lowPrefixPtr, iHighLimit);
954
+ matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);
305
955
  back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;
306
956
  matchLength -= back;
307
957
  if (matchLength > longest) {
308
958
  longest = matchLength;
309
- *matchpos = base + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */
310
- *startpos = ip + back;
959
+ offset = (int)(ipIndex - matchIndex);
960
+ sBack = back;
961
+ DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back);
311
962
  } } }
312
963
 
313
- if (chainSwap && matchLength==longest) { /* better match => select a better chain */
964
+ if (chainSwap && matchLength==longest) { /* better match => select a better chain */
314
965
  assert(lookBackLength==0); /* search forward only */
315
966
  if (matchIndex + (U32)longest <= ipIndex) {
316
967
  int const kTrigger = 4;
@@ -326,8 +977,7 @@ LZ4HC_InsertAndGetWiderMatch (
326
977
  distanceToNextMatch = candidateDist;
327
978
  matchChainPos = (U32)pos;
328
979
  accel = 1 << kTrigger;
329
- }
330
- }
980
+ } }
331
981
  if (distanceToNextMatch > 1) {
332
982
  if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
333
983
  matchIndex -= distanceToNextMatch;
@@ -341,29 +991,31 @@ LZ4HC_InsertAndGetWiderMatch (
341
991
  if (repeat == rep_untested) {
342
992
  if ( ((pattern & 0xFFFF) == (pattern >> 16))
343
993
  & ((pattern & 0xFF) == (pattern >> 24)) ) {
994
+ DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24);
344
995
  repeat = rep_confirmed;
345
996
  srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
346
997
  } else {
347
998
  repeat = rep_not;
348
999
  } }
349
1000
  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;
1001
+ && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {
1002
+ const int extDict = matchCandidateIdx < prefixIdx;
1003
+ const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx);
353
1004
  if (LZ4_read32(matchPtr) == pattern) { /* good candidate */
354
- const BYTE* const dictStart = dictBase + hc4->lowLimit;
355
- const BYTE* const iLimit = extDict ? dictBase + dictLimit : iHighLimit;
1005
+ const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;
356
1006
  size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);
357
1007
  if (extDict && matchPtr + forwardPatternLength == iLimit) {
358
1008
  U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);
359
- forwardPatternLength += LZ4HC_countPattern(lowPrefixPtr, iHighLimit, rotatedPattern);
1009
+ forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);
360
1010
  }
361
- { const BYTE* const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr;
1011
+ { const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;
362
1012
  size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);
363
1013
  size_t currentSegmentLength;
364
- if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) {
1014
+ if (!extDict
1015
+ && matchPtr - backLength == prefixPtr
1016
+ && dictIdx < prefixIdx) {
365
1017
  U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);
366
- backLength += LZ4HC_reverseCountPattern(dictBase + dictLimit, dictStart, rotatedPattern);
1018
+ backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);
367
1019
  }
368
1020
  /* Limit backLength not go further than lowestMatchIndex */
369
1021
  backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);
@@ -373,29 +1025,30 @@ LZ4HC_InsertAndGetWiderMatch (
373
1025
  if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
374
1026
  && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
375
1027
  U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
376
- if (LZ4HC_protectDictEnd(dictLimit, newMatchIndex))
1028
+ if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))
377
1029
  matchIndex = newMatchIndex;
378
1030
  else {
379
1031
  /* Can only happen if started in the prefix */
380
- assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);
381
- matchIndex = dictLimit;
1032
+ assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
1033
+ matchIndex = prefixIdx;
382
1034
  }
383
1035
  } else {
384
1036
  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;
1037
+ if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {
1038
+ assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);
1039
+ matchIndex = prefixIdx;
388
1040
  } else {
389
1041
  matchIndex = newMatchIndex;
390
1042
  if (lookBackLength==0) { /* no back possible */
391
1043
  size_t const maxML = MIN(currentSegmentLength, srcPatternLength);
392
1044
  if ((size_t)longest < maxML) {
393
- assert(base + matchIndex != ip);
394
- if ((size_t)(ip - base) - matchIndex > LZ4_DISTANCE_MAX) break;
1045
+ assert(prefixPtr - prefixIdx + matchIndex != ip);
1046
+ if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;
395
1047
  assert(maxML < 2 GB);
396
1048
  longest = (int)maxML;
397
- *matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */
398
- *startpos = ip;
1049
+ offset = (int)(ipIndex - matchIndex);
1050
+ assert(sBack == 0);
1051
+ DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset);
399
1052
  }
400
1053
  { U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);
401
1054
  if (distToNextPattern > matchIndex) break; /* avoid overflow */
@@ -412,13 +1065,14 @@ LZ4HC_InsertAndGetWiderMatch (
412
1065
 
413
1066
  if ( dict == usingDictCtxHc
414
1067
  && nbAttempts > 0
415
- && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
416
- size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);
1068
+ && withinStartDistance) {
1069
+ size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;
417
1070
  U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
418
1071
  assert(dictEndOffset <= 1 GB);
419
1072
  matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;
1073
+ if (dictMatchIndex>0) DEBUGLOG(7, "dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset);
420
1074
  while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {
421
- const BYTE* const matchPtr = dictCtx->base + dictMatchIndex;
1075
+ const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;
422
1076
 
423
1077
  if (LZ4_read32(matchPtr) == pattern) {
424
1078
  int mlt;
@@ -426,12 +1080,13 @@ LZ4HC_InsertAndGetWiderMatch (
426
1080
  const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
427
1081
  if (vLimit > iHighLimit) vLimit = iHighLimit;
428
1082
  mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
429
- back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->base + dictCtx->dictLimit) : 0;
1083
+ back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;
430
1084
  mlt -= back;
431
1085
  if (mlt > longest) {
432
1086
  longest = mlt;
433
- *matchpos = base + matchIndex + back;
434
- *startpos = ip + back;
1087
+ offset = (int)(ipIndex - matchIndex);
1088
+ sBack = back;
1089
+ DEBUGLOG(7, "found match of length %i within extDictCtx", longest);
435
1090
  } }
436
1091
 
437
1092
  { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
@@ -439,112 +1094,29 @@ LZ4HC_InsertAndGetWiderMatch (
439
1094
  matchIndex -= nextOffset;
440
1095
  } } }
441
1096
 
442
- return longest;
1097
+ { LZ4HC_match_t md;
1098
+ assert(longest >= 0);
1099
+ md.len = longest;
1100
+ md.off = offset;
1101
+ md.back = sBack;
1102
+ return md;
1103
+ }
443
1104
  }
444
1105
 
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)
1106
+ LZ4_FORCE_INLINE LZ4HC_match_t
1107
+ LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
1108
+ const BYTE* const ip, const BYTE* const iLimit,
1109
+ const int maxNbAttempts,
1110
+ const int patternAnalysis,
1111
+ const dictCtx_directive dict)
452
1112
  {
453
- const BYTE* uselessPtr = ip;
1113
+ DEBUGLOG(7, "LZ4HC_InsertAndFindBestMatch");
454
1114
  /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
455
1115
  * but this won't be the case here, as we define iLowLimit==ip,
456
1116
  * 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);
1117
+ return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
458
1118
  }
459
1119
 
460
- /* LZ4HC_encodeSequence() :
461
- * @return : 0 if ok,
462
- * 1 if buffer issue detected */
463
- LZ4_FORCE_INLINE int LZ4HC_encodeSequence (
464
- const BYTE** _ip,
465
- BYTE** _op,
466
- const BYTE** _anchor,
467
- int matchLength,
468
- const BYTE* const match,
469
- limitedOutput_directive limit,
470
- BYTE* oend)
471
- {
472
- #define ip (*_ip)
473
- #define op (*_op)
474
- #define anchor (*_anchor)
475
-
476
- size_t length;
477
- BYTE* const token = op++;
478
-
479
- #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)
480
- static const BYTE* start = NULL;
481
- static U32 totalCost = 0;
482
- U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);
483
- U32 const ll = (U32)(ip - anchor);
484
- U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;
485
- U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;
486
- U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
487
- if (start==NULL) start = anchor; /* only works for single segment */
488
- /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
489
- DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
490
- pos,
491
- (U32)(ip - anchor), matchLength, (U32)(ip-match),
492
- cost, totalCost);
493
- totalCost += cost;
494
- #endif
495
-
496
- /* Encode Literal length */
497
- length = (size_t)(ip - anchor);
498
- LZ4_STATIC_ASSERT(notLimited == 0);
499
- /* Check output limit */
500
- if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
501
- DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
502
- (int)length, (int)(oend - op));
503
- return 1;
504
- }
505
- if (length >= RUN_MASK) {
506
- size_t len = length - RUN_MASK;
507
- *token = (RUN_MASK << ML_BITS);
508
- for(; len >= 255 ; len -= 255) *op++ = 255;
509
- *op++ = (BYTE)len;
510
- } else {
511
- *token = (BYTE)(length << ML_BITS);
512
- }
513
-
514
- /* Copy Literals */
515
- LZ4_wildCopy8(op, anchor, op + length);
516
- op += length;
517
-
518
- /* Encode Offset */
519
- assert( (ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */
520
- LZ4_writeLE16(op, (U16)(ip - match)); op += 2;
521
-
522
- /* Encode MatchLength */
523
- assert(matchLength >= MINMATCH);
524
- length = (size_t)matchLength - MINMATCH;
525
- if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {
526
- DEBUGLOG(6, "Not enough room to write match length");
527
- return 1; /* Check output limit */
528
- }
529
- if (length >= ML_MASK) {
530
- *token += ML_MASK;
531
- length -= ML_MASK;
532
- for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }
533
- if (length >= 255) { length -= 255; *op++ = 255; }
534
- *op++ = (BYTE)length;
535
- } else {
536
- *token += (BYTE)(length);
537
- }
538
-
539
- /* Prepare next loop */
540
- ip += matchLength;
541
- anchor = ip;
542
-
543
- return 0;
544
- }
545
- #undef ip
546
- #undef op
547
- #undef anchor
548
1120
 
549
1121
  LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
550
1122
  LZ4HC_CCtx_internal* const ctx,
@@ -570,127 +1142,130 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (
570
1142
  BYTE* op = (BYTE*) dest;
571
1143
  BYTE* oend = op + maxOutputSize;
572
1144
 
573
- int ml0, ml, ml2, ml3;
574
1145
  const BYTE* start0;
575
- const BYTE* ref0;
576
- const BYTE* ref = NULL;
577
1146
  const BYTE* start2 = NULL;
578
- const BYTE* ref2 = NULL;
579
1147
  const BYTE* start3 = NULL;
580
- const BYTE* ref3 = NULL;
1148
+ LZ4HC_match_t m0, m1, m2, m3;
1149
+ const LZ4HC_match_t nomatch = {0, 0, 0};
581
1150
 
582
1151
  /* init */
1152
+ DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict);
583
1153
  *srcSizePtr = 0;
584
1154
  if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
585
1155
  if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
586
1156
 
587
1157
  /* Main Loop */
588
1158
  while (ip <= mflimit) {
589
- ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);
590
- if (ml<MINMATCH) { ip++; continue; }
1159
+ m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict);
1160
+ if (m1.len<MINMATCH) { ip++; continue; }
591
1161
 
592
1162
  /* saved, in case we would skip too much */
593
- start0 = ip; ref0 = ref; ml0 = ml;
1163
+ start0 = ip; m0 = m1;
594
1164
 
595
1165
  _Search2:
596
- if (ip+ml <= mflimit) {
597
- ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,
598
- ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,
1166
+ DEBUGLOG(7, "_Search2 (currently found match of size %i)", m1.len);
1167
+ if (ip+m1.len <= mflimit) {
1168
+ start2 = ip + m1.len - 2;
1169
+ m2 = LZ4HC_InsertAndGetWiderMatch(ctx,
1170
+ start2, ip + 0, matchlimit, m1.len,
599
1171
  maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
1172
+ start2 += m2.back;
600
1173
  } else {
601
- ml2 = ml;
1174
+ m2 = nomatch; /* do not search further */
602
1175
  }
603
1176
 
604
- if (ml2 == ml) { /* No better match => encode ML1 */
1177
+ if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */
605
1178
  optr = op;
606
- if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
1179
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1180
+ m1.len, m1.off,
1181
+ limit, oend) )
1182
+ goto _dest_overflow;
607
1183
  continue;
608
1184
  }
609
1185
 
610
1186
  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 */
1187
+ if (start2 < ip + m0.len) { /* squeezing ML1 between ML0(original ML1) and ML2 */
1188
+ ip = start0; m1 = m0; /* restore initial Match1 */
613
1189
  } }
614
1190
 
615
1191
  /* Here, start0==ip */
616
1192
  if ((start2 - ip) < 3) { /* First Match too small : removed */
617
- ml = ml2;
618
1193
  ip = start2;
619
- ref =ref2;
1194
+ m1 = m2;
620
1195
  goto _Search2;
621
1196
  }
622
1197
 
623
1198
  _Search3:
624
- /* At this stage, we have :
625
- * ml2 > ml1, and
626
- * ip1+3 <= ip2 (usually < ip1+ml1) */
627
1199
  if ((start2 - ip) < OPTIMAL_ML) {
628
1200
  int correction;
629
- int new_ml = ml;
1201
+ int new_ml = m1.len;
630
1202
  if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
631
- if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
1203
+ if (ip+new_ml > start2 + m2.len - MINMATCH)
1204
+ new_ml = (int)(start2 - ip) + m2.len - MINMATCH;
632
1205
  correction = new_ml - (int)(start2 - ip);
633
1206
  if (correction > 0) {
634
1207
  start2 += correction;
635
- ref2 += correction;
636
- ml2 -= correction;
1208
+ m2.len -= correction;
637
1209
  }
638
1210
  }
639
- /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
640
1211
 
641
- if (start2 + ml2 <= mflimit) {
642
- ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,
643
- start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,
1212
+ if (start2 + m2.len <= mflimit) {
1213
+ start3 = start2 + m2.len - 3;
1214
+ m3 = LZ4HC_InsertAndGetWiderMatch(ctx,
1215
+ start3, start2, matchlimit, m2.len,
644
1216
  maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);
1217
+ start3 += m3.back;
645
1218
  } else {
646
- ml3 = ml2;
1219
+ m3 = nomatch; /* do not search further */
647
1220
  }
648
1221
 
649
- if (ml3 == ml2) { /* No better match => encode ML1 and ML2 */
1222
+ if (m3.len <= m2.len) { /* No better match => encode ML1 and ML2 */
650
1223
  /* ip & ref are known; Now for ml */
651
- if (start2 < ip+ml) ml = (int)(start2 - ip);
1224
+ if (start2 < ip+m1.len) m1.len = (int)(start2 - ip);
652
1225
  /* Now, encode 2 sequences */
653
1226
  optr = op;
654
- if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
1227
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1228
+ m1.len, m1.off,
1229
+ limit, oend) )
1230
+ goto _dest_overflow;
655
1231
  ip = start2;
656
1232
  optr = op;
657
- if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {
658
- ml = ml2;
659
- ref = ref2;
1233
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1234
+ m2.len, m2.off,
1235
+ limit, oend) ) {
1236
+ m1 = m2;
660
1237
  goto _dest_overflow;
661
1238
  }
662
1239
  continue;
663
1240
  }
664
1241
 
665
- if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */
666
- if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
667
- if (start2 < ip+ml) {
668
- int correction = (int)(ip+ml - start2);
1242
+ if (start3 < ip+m1.len+3) { /* Not enough space for match 2 : remove it */
1243
+ if (start3 >= (ip+m1.len)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
1244
+ if (start2 < ip+m1.len) {
1245
+ int correction = (int)(ip+m1.len - start2);
669
1246
  start2 += correction;
670
- ref2 += correction;
671
- ml2 -= correction;
672
- if (ml2 < MINMATCH) {
1247
+ m2.len -= correction;
1248
+ if (m2.len < MINMATCH) {
673
1249
  start2 = start3;
674
- ref2 = ref3;
675
- ml2 = ml3;
1250
+ m2 = m3;
676
1251
  }
677
1252
  }
678
1253
 
679
1254
  optr = op;
680
- if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
1255
+ if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1256
+ m1.len, m1.off,
1257
+ limit, oend) )
1258
+ goto _dest_overflow;
681
1259
  ip = start3;
682
- ref = ref3;
683
- ml = ml3;
1260
+ m1 = m3;
684
1261
 
685
1262
  start0 = start2;
686
- ref0 = ref2;
687
- ml0 = ml2;
1263
+ m0 = m2;
688
1264
  goto _Search2;
689
1265
  }
690
1266
 
691
1267
  start2 = start3;
692
- ref2 = ref3;
693
- ml2 = ml3;
1268
+ m2 = m3;
694
1269
  goto _Search3;
695
1270
  }
696
1271
 
@@ -699,29 +1274,32 @@ _Search3:
699
1274
  * let's write the first one ML1.
700
1275
  * ip & ref are known; Now decide ml.
701
1276
  */
702
- if (start2 < ip+ml) {
1277
+ if (start2 < ip+m1.len) {
703
1278
  if ((start2 - ip) < OPTIMAL_ML) {
704
1279
  int correction;
705
- if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
706
- if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
707
- correction = ml - (int)(start2 - ip);
1280
+ if (m1.len > OPTIMAL_ML) m1.len = OPTIMAL_ML;
1281
+ if (ip + m1.len > start2 + m2.len - MINMATCH)
1282
+ m1.len = (int)(start2 - ip) + m2.len - MINMATCH;
1283
+ correction = m1.len - (int)(start2 - ip);
708
1284
  if (correction > 0) {
709
1285
  start2 += correction;
710
- ref2 += correction;
711
- ml2 -= correction;
1286
+ m2.len -= correction;
712
1287
  }
713
1288
  } else {
714
- ml = (int)(start2 - ip);
1289
+ m1.len = (int)(start2 - ip);
715
1290
  }
716
1291
  }
717
1292
  optr = op;
718
- if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
1293
+ if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),
1294
+ m1.len, m1.off,
1295
+ limit, oend) )
1296
+ goto _dest_overflow;
719
1297
 
720
1298
  /* ML2 becomes ML1 */
721
- ip = start2; ref = ref2; ml = ml2;
1299
+ ip = start2; m1 = m2;
722
1300
 
723
1301
  /* ML3 becomes ML2 */
724
- start2 = start3; ref2 = ref3; ml2 = ml3;
1302
+ start2 = start3; m2 = m3;
725
1303
 
726
1304
  /* let's find a new ML3 */
727
1305
  goto _Search3;
@@ -751,7 +1329,7 @@ _last_literals:
751
1329
  } else {
752
1330
  *op++ = (BYTE)(lastRunSize << ML_BITS);
753
1331
  }
754
- memcpy(op, anchor, lastRunSize);
1332
+ LZ4_memcpy(op, anchor, lastRunSize);
755
1333
  op += lastRunSize;
756
1334
  }
757
1335
 
@@ -761,7 +1339,7 @@ _last_literals:
761
1339
 
762
1340
  _dest_overflow:
763
1341
  if (limit == fillOutput) {
764
- /* Assumption : ip, anchor, ml and ref must be set correctly */
1342
+ /* Assumption : @ip, @anchor, @optr and @m1 must be set correctly */
765
1343
  size_t const ll = (size_t)(ip - anchor);
766
1344
  size_t const ll_addbytes = (ll + 240) / 255;
767
1345
  size_t const ll_totalCost = 1 + ll_addbytes + ll;
@@ -772,10 +1350,10 @@ _dest_overflow:
772
1350
  /* ll validated; now adjust match length */
773
1351
  size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));
774
1352
  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);
1353
+ assert(maxMlSize < INT_MAX); assert(m1.len >= 0);
1354
+ if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize;
1355
+ if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) {
1356
+ LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend);
779
1357
  } }
780
1358
  goto _last_literals;
781
1359
  }
@@ -792,54 +1370,34 @@ static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,
792
1370
  const dictCtx_directive dict,
793
1371
  const HCfavor_e favorDecSpeed);
794
1372
 
795
-
796
- LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
797
- LZ4HC_CCtx_internal* const ctx,
798
- const char* const src,
799
- char* const dst,
800
- int* const srcSizePtr,
801
- int const dstCapacity,
802
- int cLevel,
803
- const limitedOutput_directive limit,
804
- const dictCtx_directive dict
805
- )
1373
+ LZ4_FORCE_INLINE int
1374
+ LZ4HC_compress_generic_internal (
1375
+ LZ4HC_CCtx_internal* const ctx,
1376
+ const char* const src,
1377
+ char* const dst,
1378
+ int* const srcSizePtr,
1379
+ int const dstCapacity,
1380
+ int cLevel,
1381
+ const limitedOutput_directive limit,
1382
+ const dictCtx_directive dict
1383
+ )
806
1384
  {
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);
1385
+ DEBUGLOG(5, "LZ4HC_compress_generic_internal(src=%p, srcSize=%d)",
1386
+ src, *srcSizePtr);
831
1387
 
832
1388
  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) */
1389
+ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
834
1390
 
835
1391
  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];
1392
+ { cParams_t const cParam = LZ4HC_getCLevelParams(cLevel);
839
1393
  HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;
840
1394
  int result;
841
1395
 
842
- if (cParam.strat == lz4hc) {
1396
+ if (cParam.strat == lz4mid) {
1397
+ result = LZ4MID_compress(ctx,
1398
+ src, dst, srcSizePtr, dstCapacity,
1399
+ limit, dict);
1400
+ } else if (cParam.strat == lz4hc) {
843
1401
  result = LZ4HC_compress_hashChain(ctx,
844
1402
  src, dst, srcSizePtr, dstCapacity,
845
1403
  cParam.nbSearches, limit, dict);
@@ -848,7 +1406,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (
848
1406
  result = LZ4HC_compress_optimal(ctx,
849
1407
  src, dst, srcSizePtr, dstCapacity,
850
1408
  cParam.nbSearches, cParam.targetLength, limit,
851
- cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */
1409
+ cLevel >= LZ4HC_CLEVEL_MAX, /* ultra mode */
852
1410
  dict, favor);
853
1411
  }
854
1412
  if (result <= 0) ctx->dirty = 1;
@@ -873,6 +1431,13 @@ LZ4HC_compress_generic_noDictCtx (
873
1431
  return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);
874
1432
  }
875
1433
 
1434
+ static int isStateCompatible(const LZ4HC_CCtx_internal* ctx1, const LZ4HC_CCtx_internal* ctx2)
1435
+ {
1436
+ int const isMid1 = LZ4HC_getCLevelParams(ctx1->compressionLevel).strat == lz4mid;
1437
+ int const isMid2 = LZ4HC_getCLevelParams(ctx2->compressionLevel).strat == lz4mid;
1438
+ return !(isMid1 ^ isMid2);
1439
+ }
1440
+
876
1441
  static int
877
1442
  LZ4HC_compress_generic_dictCtx (
878
1443
  LZ4HC_CCtx_internal* const ctx,
@@ -884,13 +1449,13 @@ LZ4HC_compress_generic_dictCtx (
884
1449
  limitedOutput_directive limit
885
1450
  )
886
1451
  {
887
- const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit;
1452
+ const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);
888
1453
  assert(ctx->dictCtx != NULL);
889
1454
  if (position >= 64 KB) {
890
1455
  ctx->dictCtx = NULL;
891
1456
  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));
1457
+ } else if (position == 0 && *srcSizePtr > 4 KB && isStateCompatible(ctx, ctx->dictCtx)) {
1458
+ LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));
894
1459
  LZ4HC_setExternalDict(ctx, (const BYTE *)src);
895
1460
  ctx->compressionLevel = (short)cLevel;
896
1461
  return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);
@@ -953,13 +1518,16 @@ int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int src
953
1518
 
954
1519
  int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
955
1520
  {
1521
+ int cSize;
956
1522
  #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
957
1523
  LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
1524
+ if (statePtr==NULL) return 0;
958
1525
  #else
959
1526
  LZ4_streamHC_t state;
960
1527
  LZ4_streamHC_t* const statePtr = &state;
961
1528
  #endif
962
- int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
1529
+ DEBUGLOG(5, "LZ4_compress_HC")
1530
+ cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);
963
1531
  #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
964
1532
  FREEMEM(statePtr);
965
1533
  #endif
@@ -982,6 +1550,7 @@ int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* s
982
1550
  * Streaming Functions
983
1551
  **************************************/
984
1552
  /* allocation */
1553
+ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
985
1554
  LZ4_streamHC_t* LZ4_createStreamHC(void)
986
1555
  {
987
1556
  LZ4_streamHC_t* const state =
@@ -998,13 +1567,12 @@ int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
998
1567
  FREEMEM(LZ4_streamHCPtr);
999
1568
  return 0;
1000
1569
  }
1570
+ #endif
1001
1571
 
1002
1572
 
1003
1573
  LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
1004
1574
  {
1005
1575
  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
1576
  DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
1009
1577
  /* check conditions */
1010
1578
  if (buffer == NULL) return NULL;
@@ -1026,14 +1594,16 @@ void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1026
1594
 
1027
1595
  void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
1028
1596
  {
1029
- DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1030
- if (LZ4_streamHCPtr->internal_donotuse.dirty) {
1597
+ LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse;
1598
+ DEBUGLOG(5, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
1599
+ if (s->dirty) {
1031
1600
  LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1032
1601
  } 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;
1602
+ assert(s->end >= s->prefixStart);
1603
+ s->dictLimit += (U32)(s->end - s->prefixStart);
1604
+ s->prefixStart = NULL;
1605
+ s->end = NULL;
1606
+ s->dictCtx = NULL;
1037
1607
  }
1038
1608
  LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
1039
1609
  }
@@ -1057,7 +1627,9 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
1057
1627
  const char* dictionary, int dictSize)
1058
1628
  {
1059
1629
  LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
1060
- DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);
1630
+ cParams_t cp;
1631
+ DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d, clevel=%d)", LZ4_streamHCPtr, dictionary, dictSize, ctxPtr->compressionLevel);
1632
+ assert(dictSize >= 0);
1061
1633
  assert(LZ4_streamHCPtr != NULL);
1062
1634
  if (dictSize > 64 KB) {
1063
1635
  dictionary += (size_t)dictSize - 64 KB;
@@ -1067,10 +1639,15 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,
1067
1639
  { int const cLevel = ctxPtr->compressionLevel;
1068
1640
  LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
1069
1641
  LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);
1642
+ cp = LZ4HC_getCLevelParams(cLevel);
1070
1643
  }
1071
1644
  LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);
1072
1645
  ctxPtr->end = (const BYTE*)dictionary + dictSize;
1073
- if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
1646
+ if (cp.strat == lz4mid) {
1647
+ LZ4MID_fillHTable (ctxPtr, dictionary, (size_t)dictSize);
1648
+ } else {
1649
+ if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
1650
+ }
1074
1651
  return dictSize;
1075
1652
  }
1076
1653
 
@@ -1083,14 +1660,16 @@ void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC
1083
1660
  static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
1084
1661
  {
1085
1662
  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 */
1663
+ if ( (ctxPtr->end >= ctxPtr->prefixStart + 4)
1664
+ && (LZ4HC_getCLevelParams(ctxPtr->compressionLevel).strat != lz4mid) ) {
1665
+ LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
1666
+ }
1088
1667
 
1089
1668
  /* Only one memory segment for extDict, so any previous extDict is lost at this stage */
1090
1669
  ctxPtr->lowLimit = ctxPtr->dictLimit;
1091
- ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
1092
- ctxPtr->dictBase = ctxPtr->base;
1093
- ctxPtr->base = newBlock - ctxPtr->dictLimit;
1670
+ ctxPtr->dictStart = ctxPtr->prefixStart;
1671
+ ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);
1672
+ ctxPtr->prefixStart = newBlock;
1094
1673
  ctxPtr->end = newBlock;
1095
1674
  ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
1096
1675
 
@@ -1109,11 +1688,12 @@ LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
1109
1688
  LZ4_streamHCPtr, src, *srcSizePtr, limit);
1110
1689
  assert(ctxPtr != NULL);
1111
1690
  /* auto-init if forgotten */
1112
- if (ctxPtr->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
1691
+ if (ctxPtr->prefixStart == NULL)
1692
+ LZ4HC_init_internal (ctxPtr, (const BYTE*) src);
1113
1693
 
1114
1694
  /* Check overflow */
1115
- if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
1116
- size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
1695
+ if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {
1696
+ size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);
1117
1697
  if (dictSize > 64 KB) dictSize = 64 KB;
1118
1698
  LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
1119
1699
  }
@@ -1124,19 +1704,24 @@ LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
1124
1704
 
1125
1705
  /* Check overlapping input/dictionary space */
1126
1706
  { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
1127
- const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
1128
- const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
1707
+ const BYTE* const dictBegin = ctxPtr->dictStart;
1708
+ const BYTE* const dictEnd = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);
1129
1709
  if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {
1130
1710
  if (sourceEnd > dictEnd) sourceEnd = dictEnd;
1131
- ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
1132
- if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
1133
- } }
1711
+ ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);
1712
+ ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);
1713
+ /* invalidate dictionary is it's too small */
1714
+ if (ctxPtr->dictLimit - ctxPtr->lowLimit < LZ4HC_HASHSIZE) {
1715
+ ctxPtr->lowLimit = ctxPtr->dictLimit;
1716
+ ctxPtr->dictStart = ctxPtr->prefixStart;
1717
+ } } }
1134
1718
 
1135
1719
  return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
1136
1720
  }
1137
1721
 
1138
1722
  int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
1139
1723
  {
1724
+ DEBUGLOG(5, "LZ4_compress_HC_continue");
1140
1725
  if (dstCapacity < LZ4_compressBound(srcSize))
1141
1726
  return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
1142
1727
  else
@@ -1149,7 +1734,6 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch
1149
1734
  }
1150
1735
 
1151
1736
 
1152
-
1153
1737
  /* LZ4_saveDictHC :
1154
1738
  * save history content
1155
1739
  * into a user-provided buffer
@@ -1158,7 +1742,7 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch
1158
1742
  int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
1159
1743
  {
1160
1744
  LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
1161
- int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
1745
+ int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
1162
1746
  DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
1163
1747
  assert(prefixSize >= 0);
1164
1748
  if (dictSize > 64 KB) dictSize = 64 KB;
@@ -1166,12 +1750,13 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
1166
1750
  if (dictSize > prefixSize) dictSize = prefixSize;
1167
1751
  if (safeBuffer == NULL) assert(dictSize == 0);
1168
1752
  if (dictSize > 0)
1169
- memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
1170
- { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
1171
- streamPtr->end = (const BYTE*)safeBuffer + dictSize;
1172
- streamPtr->base = streamPtr->end - endIndex;
1753
+ LZ4_memmove(safeBuffer, streamPtr->end - dictSize, (size_t)dictSize);
1754
+ { U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;
1755
+ streamPtr->end = (safeBuffer == NULL) ? NULL : (const BYTE*)safeBuffer + dictSize;
1756
+ streamPtr->prefixStart = (const BYTE*)safeBuffer;
1173
1757
  streamPtr->dictLimit = endIndex - (U32)dictSize;
1174
1758
  streamPtr->lowLimit = endIndex - (U32)dictSize;
1759
+ streamPtr->dictStart = streamPtr->prefixStart;
1175
1760
  if (streamPtr->nextToUpdate < streamPtr->dictLimit)
1176
1761
  streamPtr->nextToUpdate = streamPtr->dictLimit;
1177
1762
  }
@@ -1179,73 +1764,6 @@ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictS
1179
1764
  }
1180
1765
 
1181
1766
 
1182
- /***************************************************
1183
- * Deprecated Functions
1184
- ***************************************************/
1185
-
1186
- /* These functions currently generate deprecation warnings */
1187
-
1188
- /* Wrappers for deprecated compression functions */
1189
- int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
1190
- int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
1191
- int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
1192
- int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
1193
- int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
1194
- int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
1195
- int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
1196
- int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
1197
- int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
1198
- int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
1199
-
1200
-
1201
- /* Deprecated streaming functions */
1202
- int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
1203
-
1204
- /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
1205
- * @return : 0 on success, !=0 if error */
1206
- int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
1207
- {
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);
1211
- return 0;
1212
- }
1213
-
1214
- void* LZ4_createHC (const char* inputBuffer)
1215
- {
1216
- LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
1217
- if (hc4 == NULL) return NULL; /* not enough memory */
1218
- LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
1219
- return hc4;
1220
- }
1221
-
1222
- int LZ4_freeHC (void* LZ4HC_Data)
1223
- {
1224
- if (!LZ4HC_Data) return 0; /* support free on NULL */
1225
- FREEMEM(LZ4HC_Data);
1226
- return 0;
1227
- }
1228
-
1229
- int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
1230
- {
1231
- return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
1232
- }
1233
-
1234
- int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
1235
- {
1236
- return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
1237
- }
1238
-
1239
- char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
1240
- {
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
1767
  /* ================================================
1250
1768
  * LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
1251
1769
  * ===============================================*/
@@ -1266,7 +1784,6 @@ LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)
1266
1784
  return price;
1267
1785
  }
1268
1786
 
1269
-
1270
1787
  /* requires mlen >= MINMATCH */
1271
1788
  LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
1272
1789
  {
@@ -1282,12 +1799,6 @@ LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)
1282
1799
  return price;
1283
1800
  }
1284
1801
 
1285
-
1286
- typedef struct {
1287
- int off;
1288
- int len;
1289
- } LZ4HC_match_t;
1290
-
1291
1802
  LZ4_FORCE_INLINE LZ4HC_match_t
1292
1803
  LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
1293
1804
  const BYTE* ip, const BYTE* const iHighLimit,
@@ -1295,19 +1806,17 @@ LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,
1295
1806
  const dictCtx_directive dict,
1296
1807
  const HCfavor_e favorDecSpeed)
1297
1808
  {
1298
- LZ4HC_match_t match = { 0 , 0 };
1299
- const BYTE* matchPtr = NULL;
1809
+ LZ4HC_match_t const match0 = { 0 , 0, 0 };
1300
1810
  /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
1301
1811
  * 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;
1812
+ ** so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
1813
+ LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);
1814
+ assert(md.back == 0);
1815
+ if (md.len <= minLen) return match0;
1305
1816
  if (favorDecSpeed) {
1306
- if ((matchLength>18) & (matchLength<=36)) matchLength=18; /* favor shortcut */
1817
+ if ((md.len>18) & (md.len<=36)) md.len=18; /* favor dec.speed (shortcut) */
1307
1818
  }
1308
- match.len = matchLength;
1309
- match.off = (int)(ip-matchPtr);
1310
- return match;
1819
+ return md;
1311
1820
  }
1312
1821
 
1313
1822
 
@@ -1325,7 +1834,7 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
1325
1834
  {
1326
1835
  int retval = 0;
1327
1836
  #define TRAILING_LITERALS 3
1328
- #ifdef LZ4HC_HEAPMODE
1837
+ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1329
1838
  LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
1330
1839
  #else
1331
1840
  LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */
@@ -1340,10 +1849,10 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
1340
1849
  BYTE* opSaved = (BYTE*) dst;
1341
1850
  BYTE* oend = op + dstCapacity;
1342
1851
  int ovml = MINMATCH; /* overflow - last sequence */
1343
- const BYTE* ovref = NULL;
1852
+ int ovoff = 0;
1344
1853
 
1345
1854
  /* init */
1346
- #ifdef LZ4HC_HEAPMODE
1855
+ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
1347
1856
  if (opt == NULL) goto _return_label;
1348
1857
  #endif
1349
1858
  DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);
@@ -1363,11 +1872,10 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
1363
1872
  if ((size_t)firstMatch.len > sufficient_len) {
1364
1873
  /* good enough solution : immediate encoding */
1365
1874
  int const firstML = firstMatch.len;
1366
- const BYTE* const matchPos = ip - firstMatch.off;
1367
1875
  opSaved = op;
1368
- if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) { /* updates ip, op and anchor */
1876
+ if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) { /* updates ip, op and anchor */
1369
1877
  ovml = firstML;
1370
- ovref = matchPos;
1878
+ ovoff = firstMatch.off;
1371
1879
  goto _dest_overflow;
1372
1880
  }
1373
1881
  continue;
@@ -1385,11 +1893,11 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,
1385
1893
  rPos, cost, opt[rPos].litlen);
1386
1894
  } }
1387
1895
  /* set prices using initial match */
1388
- { int mlen = MINMATCH;
1389
- int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
1896
+ { int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */
1390
1897
  int const offset = firstMatch.off;
1898
+ int mlen;
1391
1899
  assert(matchML < LZ4_OPT_NUM);
1392
- for ( ; mlen <= matchML ; mlen++) {
1900
+ for (mlen = MINMATCH ; mlen <= matchML ; mlen++) {
1393
1901
  int const cost = LZ4HC_sequencePrice(llen, mlen);
1394
1902
  opt[mlen].mlen = mlen;
1395
1903
  opt[mlen].off = offset;
@@ -1541,9 +2049,9 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
1541
2049
  assert(ml >= MINMATCH);
1542
2050
  assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
1543
2051
  opSaved = op;
1544
- if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) { /* updates ip, op and anchor */
2052
+ if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) { /* updates ip, op and anchor */
1545
2053
  ovml = ml;
1546
- ovref = ip - offset;
2054
+ ovoff = offset;
1547
2055
  goto _dest_overflow;
1548
2056
  } } }
1549
2057
  } /* while (ip <= mflimit) */
@@ -1575,7 +2083,7 @@ _last_literals:
1575
2083
  } else {
1576
2084
  *op++ = (BYTE)(lastRunSize << ML_BITS);
1577
2085
  }
1578
- memcpy(op, anchor, lastRunSize);
2086
+ LZ4_memcpy(op, anchor, lastRunSize);
1579
2087
  op += lastRunSize;
1580
2088
  }
1581
2089
 
@@ -1602,14 +2110,83 @@ if (limit == fillOutput) {
1602
2110
  if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
1603
2111
  DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
1604
2112
  DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
1605
- LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);
2113
+ LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend);
1606
2114
  DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
1607
2115
  } }
1608
2116
  goto _last_literals;
1609
2117
  }
1610
2118
  _return_label:
1611
- #ifdef LZ4HC_HEAPMODE
1612
- FREEMEM(opt);
2119
+ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
2120
+ if (opt) FREEMEM(opt);
1613
2121
  #endif
1614
2122
  return retval;
1615
2123
  }
2124
+
2125
+
2126
+ /***************************************************
2127
+ * Deprecated Functions
2128
+ ***************************************************/
2129
+
2130
+ /* These functions currently generate deprecation warnings */
2131
+
2132
+ /* Wrappers for deprecated compression functions */
2133
+ int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
2134
+ int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
2135
+ int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
2136
+ int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
2137
+ int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
2138
+ int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
2139
+ int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
2140
+ int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
2141
+ int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
2142
+ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
2143
+
2144
+
2145
+ /* Deprecated streaming functions */
2146
+ int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }
2147
+
2148
+ /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
2149
+ * @return : 0 on success, !=0 if error */
2150
+ int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
2151
+ {
2152
+ LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
2153
+ if (hc4 == NULL) return 1; /* init failed */
2154
+ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
2155
+ return 0;
2156
+ }
2157
+
2158
+ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
2159
+ void* LZ4_createHC (const char* inputBuffer)
2160
+ {
2161
+ LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
2162
+ if (hc4 == NULL) return NULL; /* not enough memory */
2163
+ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
2164
+ return hc4;
2165
+ }
2166
+
2167
+ int LZ4_freeHC (void* LZ4HC_Data)
2168
+ {
2169
+ if (!LZ4HC_Data) return 0; /* support free on NULL */
2170
+ FREEMEM(LZ4HC_Data);
2171
+ return 0;
2172
+ }
2173
+ #endif
2174
+
2175
+ int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
2176
+ {
2177
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
2178
+ }
2179
+
2180
+ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
2181
+ {
2182
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
2183
+ }
2184
+
2185
+ char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
2186
+ {
2187
+ LZ4HC_CCtx_internal* const s = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
2188
+ const BYTE* const bufferStart = s->prefixStart - s->dictLimit + s->lowLimit;
2189
+ LZ4_resetStreamHC_fast((LZ4_streamHC_t*)LZ4HC_Data, s->compressionLevel);
2190
+ /* ugly conversion trick, required to evade (const char*) -> (char*) cast-qual warning :( */
2191
+ return (char*)(uptrval)bufferStart;
2192
+ }