extlz4 0.2.4.2 → 0.3.2

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