extlz4 0.2.5 → 0.3.4

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