zstd-ruby 1.4.0.0 → 1.4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/zstdruby/libzstd/Makefile +5 -0
  4. data/ext/zstdruby/libzstd/common/compiler.h +7 -0
  5. data/ext/zstdruby/libzstd/common/zstd_internal.h +58 -6
  6. data/ext/zstdruby/libzstd/compress/zstd_compress.c +175 -117
  7. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +74 -30
  8. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +56 -36
  9. data/ext/zstdruby/libzstd/compress/zstd_fast.c +35 -14
  10. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +10 -5
  11. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +1 -1
  12. data/ext/zstdruby/libzstd/compress/zstd_opt.c +45 -32
  13. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +18 -7
  14. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +1 -0
  15. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +12 -9
  16. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +20 -9
  17. data/ext/zstdruby/libzstd/dictBuilder/cover.c +154 -43
  18. data/ext/zstdruby/libzstd/dictBuilder/cover.h +38 -3
  19. data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +46 -39
  20. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +9 -9
  21. data/ext/zstdruby/libzstd/dictBuilder/zdict.h +5 -0
  22. data/ext/zstdruby/libzstd/legacy/zstd_legacy.h +4 -0
  23. data/ext/zstdruby/libzstd/legacy/zstd_v01.c +95 -101
  24. data/ext/zstdruby/libzstd/legacy/zstd_v02.c +11 -6
  25. data/ext/zstdruby/libzstd/legacy/zstd_v03.c +11 -6
  26. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +11 -8
  27. data/ext/zstdruby/libzstd/legacy/zstd_v05.c +88 -84
  28. data/ext/zstdruby/libzstd/legacy/zstd_v06.c +2 -4
  29. data/ext/zstdruby/libzstd/legacy/zstd_v07.c +2 -4
  30. data/ext/zstdruby/libzstd/zstd.h +53 -21
  31. data/lib/zstd-ruby/version.rb +1 -1
  32. metadata +3 -4
@@ -33,13 +33,13 @@ extern "C" {
33
33
  ***************************************/
34
34
  #define kSearchStrength 8
35
35
  #define HASH_READ_SIZE 8
36
- #define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index 1 now means "unsorted".
36
+ #define ZSTD_DUBT_UNSORTED_MARK 1 /* For btlazy2 strategy, index ZSTD_DUBT_UNSORTED_MARK==1 means "unsorted".
37
37
  It could be confused for a real successor at index "1", if sorted as larger than its predecessor.
38
38
  It's not a big deal though : candidate will just be sorted again.
39
39
  Additionally, candidate position 1 will be lost.
40
40
  But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
41
- The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy
42
- Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
41
+ The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy.
42
+ This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
43
43
 
44
44
 
45
45
  /*-*************************************
@@ -128,21 +128,20 @@ typedef struct {
128
128
  BYTE const* base; /* All regular indexes relative to this position */
129
129
  BYTE const* dictBase; /* extDict indexes relative to this position */
130
130
  U32 dictLimit; /* below that point, need extDict */
131
- U32 lowLimit; /* below that point, no more data */
131
+ U32 lowLimit; /* below that point, no more valid data */
132
132
  } ZSTD_window_t;
133
133
 
134
134
  typedef struct ZSTD_matchState_t ZSTD_matchState_t;
135
135
  struct ZSTD_matchState_t {
136
136
  ZSTD_window_t window; /* State for window round buffer management */
137
- U32 loadedDictEnd; /* index of end of dictionary */
137
+ U32 loadedDictEnd; /* index of end of dictionary, within context's referential. When dict referential is copied into active context (i.e. not attached), effectively same value as dictSize, since referential starts from zero */
138
138
  U32 nextToUpdate; /* index from which to continue table update */
139
- U32 nextToUpdate3; /* index from which to continue table update */
140
139
  U32 hashLog3; /* dispatch table : larger == faster, more memory */
141
140
  U32* hashTable;
142
141
  U32* hashTable3;
143
142
  U32* chainTable;
144
143
  optState_t opt; /* optimal parser state */
145
- const ZSTD_matchState_t * dictMatchState;
144
+ const ZSTD_matchState_t* dictMatchState;
146
145
  ZSTD_compressionParameters cParams;
147
146
  };
148
147
 
@@ -195,6 +194,9 @@ struct ZSTD_CCtx_params_s {
195
194
  int compressionLevel;
196
195
  int forceWindow; /* force back-references to respect limit of
197
196
  * 1<<wLog, even for dictionary */
197
+ size_t targetCBlockSize; /* Tries to fit compressed block size to be around targetCBlockSize.
198
+ * No target when targetCBlockSize == 0.
199
+ * There is no guarantee on compressed block size */
198
200
 
199
201
  ZSTD_dictAttachPref_e attachDictPref;
200
202
  ZSTD_literalCompressionMode_e literalCompressionMode;
@@ -324,7 +326,7 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v
324
326
  /* copy Literals */
325
327
  assert(seqStorePtr->maxNbLit <= 128 KB);
326
328
  assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
327
- ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
329
+ ZSTD_wildcopy(seqStorePtr->lit, literals, litLength, ZSTD_no_overlap);
328
330
  seqStorePtr->lit += litLength;
329
331
 
330
332
  /* literal Length */
@@ -564,6 +566,9 @@ MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64
564
566
  /*-*************************************
565
567
  * Round buffer management
566
568
  ***************************************/
569
+ #if (ZSTD_WINDOWLOG_MAX_64 > 31)
570
+ # error "ZSTD_WINDOWLOG_MAX is too large : would overflow ZSTD_CURRENT_MAX"
571
+ #endif
567
572
  /* Max current allowed */
568
573
  #define ZSTD_CURRENT_MAX ((3U << 29) + (1U << ZSTD_WINDOWLOG_MAX))
569
574
  /* Maximum chunk size before overflow correction needs to be called again */
@@ -675,31 +680,49 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
675
680
  * Updates lowLimit so that:
676
681
  * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
677
682
  *
678
- * This allows a simple check that index >= lowLimit to see if index is valid.
679
- * This must be called before a block compression call, with srcEnd as the block
680
- * source end.
683
+ * It ensures index is valid as long as index >= lowLimit.
684
+ * This must be called before a block compression call.
685
+ *
686
+ * loadedDictEnd is only defined if a dictionary is in use for current compression.
687
+ * As the name implies, loadedDictEnd represents the index at end of dictionary.
688
+ * The value lies within context's referential, it can be directly compared to blockEndIdx.
681
689
  *
682
- * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit.
683
- * This is because dictionaries are allowed to be referenced as long as the last
684
- * byte of the dictionary is in the window, but once they are out of range,
685
- * they cannot be referenced. If loadedDictEndPtr is NULL, we use
686
- * loadedDictEnd == 0.
690
+ * If loadedDictEndPtr is NULL, no dictionary is in use, and we use loadedDictEnd == 0.
691
+ * If loadedDictEndPtr is not NULL, we set it to zero after updating lowLimit.
692
+ * This is because dictionaries are allowed to be referenced fully
693
+ * as long as the last byte of the dictionary is in the window.
694
+ * Once input has progressed beyond window size, dictionary cannot be referenced anymore.
687
695
  *
688
- * In normal dict mode, the dict is between lowLimit and dictLimit. In
689
- * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary
690
- * is below them. forceWindow and dictMatchState are therefore incompatible.
696
+ * In normal dict mode, the dictionary lies between lowLimit and dictLimit.
697
+ * In dictMatchState mode, lowLimit and dictLimit are the same,
698
+ * and the dictionary is below them.
699
+ * forceWindow and dictMatchState are therefore incompatible.
691
700
  */
692
701
  MEM_STATIC void
693
702
  ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
694
- void const* srcEnd,
695
- U32 maxDist,
696
- U32* loadedDictEndPtr,
703
+ const void* blockEnd,
704
+ U32 maxDist,
705
+ U32* loadedDictEndPtr,
697
706
  const ZSTD_matchState_t** dictMatchStatePtr)
698
707
  {
699
- U32 const blockEndIdx = (U32)((BYTE const*)srcEnd - window->base);
700
- U32 loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
701
- DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u",
702
- (unsigned)blockEndIdx, (unsigned)maxDist);
708
+ U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
709
+ U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
710
+ DEBUGLOG(5, "ZSTD_window_enforceMaxDist: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
711
+ (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
712
+
713
+ /* - When there is no dictionary : loadedDictEnd == 0.
714
+ In which case, the test (blockEndIdx > maxDist) is merely to avoid
715
+ overflowing next operation `newLowLimit = blockEndIdx - maxDist`.
716
+ - When there is a standard dictionary :
717
+ Index referential is copied from the dictionary,
718
+ which means it starts from 0.
719
+ In which case, loadedDictEnd == dictSize,
720
+ and it makes sense to compare `blockEndIdx > maxDist + dictSize`
721
+ since `blockEndIdx` also starts from zero.
722
+ - When there is an attached dictionary :
723
+ loadedDictEnd is expressed within the referential of the context,
724
+ so it can be directly compared against blockEndIdx.
725
+ */
703
726
  if (blockEndIdx > maxDist + loadedDictEnd) {
704
727
  U32 const newLowLimit = blockEndIdx - maxDist;
705
728
  if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
@@ -708,10 +731,31 @@ ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
708
731
  (unsigned)window->dictLimit, (unsigned)window->lowLimit);
709
732
  window->dictLimit = window->lowLimit;
710
733
  }
711
- if (loadedDictEndPtr)
712
- *loadedDictEndPtr = 0;
713
- if (dictMatchStatePtr)
714
- *dictMatchStatePtr = NULL;
734
+ /* On reaching window size, dictionaries are invalidated */
735
+ if (loadedDictEndPtr) *loadedDictEndPtr = 0;
736
+ if (dictMatchStatePtr) *dictMatchStatePtr = NULL;
737
+ }
738
+ }
739
+
740
+ /* Similar to ZSTD_window_enforceMaxDist(),
741
+ * but only invalidates dictionary
742
+ * when input progresses beyond window size. */
743
+ MEM_STATIC void
744
+ ZSTD_checkDictValidity(ZSTD_window_t* window,
745
+ const void* blockEnd,
746
+ U32 maxDist,
747
+ U32* loadedDictEndPtr,
748
+ const ZSTD_matchState_t** dictMatchStatePtr)
749
+ {
750
+ U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
751
+ U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
752
+ DEBUGLOG(5, "ZSTD_checkDictValidity: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
753
+ (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
754
+
755
+ if (loadedDictEnd && (blockEndIdx > maxDist + loadedDictEnd)) {
756
+ /* On reaching window size, dictionaries are invalidated */
757
+ if (loadedDictEndPtr) *loadedDictEndPtr = 0;
758
+ if (dictMatchStatePtr) *dictMatchStatePtr = NULL;
715
759
  }
716
760
  }
717
761
 
@@ -43,8 +43,7 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
43
43
  /* Only load extra positions for ZSTD_dtlm_full */
44
44
  if (dtlm == ZSTD_dtlm_fast)
45
45
  break;
46
- }
47
- }
46
+ } }
48
47
  }
49
48
 
50
49
 
@@ -63,7 +62,10 @@ size_t ZSTD_compressBlock_doubleFast_generic(
63
62
  const BYTE* const istart = (const BYTE*)src;
64
63
  const BYTE* ip = istart;
65
64
  const BYTE* anchor = istart;
66
- const U32 prefixLowestIndex = ms->window.dictLimit;
65
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
66
+ const U32 lowestValid = ms->window.dictLimit;
67
+ const U32 maxDistance = 1U << cParams->windowLog;
68
+ const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid;
67
69
  const BYTE* const prefixLowest = base + prefixLowestIndex;
68
70
  const BYTE* const iend = istart + srcSize;
69
71
  const BYTE* const ilimit = iend - HASH_READ_SIZE;
@@ -95,8 +97,15 @@ size_t ZSTD_compressBlock_doubleFast_generic(
95
97
  dictCParams->chainLog : hBitsS;
96
98
  const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart);
97
99
 
100
+ DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic");
101
+
98
102
  assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
99
103
 
104
+ /* if a dictionary is attached, it must be within window range */
105
+ if (dictMode == ZSTD_dictMatchState) {
106
+ assert(lowestValid + maxDistance >= endIndex);
107
+ }
108
+
100
109
  /* init */
101
110
  ip += (dictAndPrefixLength == 0);
102
111
  if (dictMode == ZSTD_noDict) {
@@ -138,7 +147,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(
138
147
  const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
139
148
  mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
140
149
  ip++;
141
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
150
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
142
151
  goto _match_stored;
143
152
  }
144
153
 
@@ -147,7 +156,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(
147
156
  && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
148
157
  mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
149
158
  ip++;
150
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
159
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
151
160
  goto _match_stored;
152
161
  }
153
162
 
@@ -170,8 +179,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(
170
179
  offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
171
180
  while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
172
181
  goto _match_found;
173
- }
174
- }
182
+ } }
175
183
 
176
184
  if (matchIndexS > prefixLowestIndex) {
177
185
  /* check prefix short match */
@@ -186,16 +194,14 @@ size_t ZSTD_compressBlock_doubleFast_generic(
186
194
 
187
195
  if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
188
196
  goto _search_next_long;
189
- }
190
- }
197
+ } }
191
198
 
192
199
  ip += ((ip-anchor) >> kSearchStrength) + 1;
193
200
  continue;
194
201
 
195
202
  _search_next_long:
196
203
 
197
- {
198
- size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
204
+ { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
199
205
  size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
200
206
  U32 const matchIndexL3 = hashLong[hl3];
201
207
  const BYTE* matchL3 = base + matchIndexL3;
@@ -221,9 +227,7 @@ _search_next_long:
221
227
  offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
222
228
  while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
223
229
  goto _match_found;
224
- }
225
- }
226
- }
230
+ } } }
227
231
 
228
232
  /* if no long +1 match, explore the short match we found */
229
233
  if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
@@ -242,7 +246,7 @@ _match_found:
242
246
  offset_2 = offset_1;
243
247
  offset_1 = offset;
244
248
 
245
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
249
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
246
250
 
247
251
  _match_stored:
248
252
  /* match found */
@@ -250,11 +254,14 @@ _match_stored:
250
254
  anchor = ip;
251
255
 
252
256
  if (ip <= ilimit) {
253
- /* Fill Table */
254
- hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
255
- hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
256
- hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
257
- hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
257
+ /* Complementary insertion */
258
+ /* done after iLimit test, as candidates could be > iend-8 */
259
+ { U32 const indexToInsert = current+2;
260
+ hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
261
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
262
+ hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
263
+ hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
264
+ }
258
265
 
259
266
  /* check immediate repcode */
260
267
  if (dictMode == ZSTD_dictMatchState) {
@@ -278,8 +285,7 @@ _match_stored:
278
285
  continue;
279
286
  }
280
287
  break;
281
- }
282
- }
288
+ } }
283
289
 
284
290
  if (dictMode == ZSTD_noDict) {
285
291
  while ( (ip <= ilimit)
@@ -294,14 +300,15 @@ _match_stored:
294
300
  ip += rLength;
295
301
  anchor = ip;
296
302
  continue; /* faster when present ... (?) */
297
- } } } }
303
+ } } }
304
+ } /* while (ip < ilimit) */
298
305
 
299
306
  /* save reps for next block */
300
307
  rep[0] = offset_1 ? offset_1 : offsetSaved;
301
308
  rep[1] = offset_2 ? offset_2 : offsetSaved;
302
309
 
303
310
  /* Return the last literals size */
304
- return iend - anchor;
311
+ return (size_t)(iend - anchor);
305
312
  }
306
313
 
307
314
 
@@ -360,10 +367,15 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
360
367
  const BYTE* anchor = istart;
361
368
  const BYTE* const iend = istart + srcSize;
362
369
  const BYTE* const ilimit = iend - 8;
363
- const U32 prefixStartIndex = ms->window.dictLimit;
364
370
  const BYTE* const base = ms->window.base;
371
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
372
+ const U32 maxDistance = 1U << cParams->windowLog;
373
+ const U32 lowestValid = ms->window.lowLimit;
374
+ const U32 lowLimit = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid;
375
+ const U32 dictStartIndex = lowLimit;
376
+ const U32 dictLimit = ms->window.dictLimit;
377
+ const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit;
365
378
  const BYTE* const prefixStart = base + prefixStartIndex;
366
- const U32 dictStartIndex = ms->window.lowLimit;
367
379
  const BYTE* const dictBase = ms->window.dictBase;
368
380
  const BYTE* const dictStart = dictBase + dictStartIndex;
369
381
  const BYTE* const dictEnd = dictBase + prefixStartIndex;
@@ -371,6 +383,10 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
371
383
 
372
384
  DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
373
385
 
386
+ /* if extDict is invalidated due to maxDistance, switch to "regular" variant */
387
+ if (prefixStartIndex == dictStartIndex)
388
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict);
389
+
374
390
  /* Search Loop */
375
391
  while (ip < ilimit) { /* < instead of <=, because (ip+1) */
376
392
  const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
@@ -396,7 +412,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
396
412
  const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
397
413
  mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
398
414
  ip++;
399
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
415
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
400
416
  } else {
401
417
  if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
402
418
  const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
@@ -407,7 +423,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
407
423
  while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
408
424
  offset_2 = offset_1;
409
425
  offset_1 = offset;
410
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
426
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
411
427
 
412
428
  } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
413
429
  size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
@@ -432,23 +448,27 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
432
448
  }
433
449
  offset_2 = offset_1;
434
450
  offset_1 = offset;
435
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
451
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
436
452
 
437
453
  } else {
438
454
  ip += ((ip-anchor) >> kSearchStrength) + 1;
439
455
  continue;
440
456
  } }
441
457
 
442
- /* found a match : store it */
458
+ /* move to next sequence start */
443
459
  ip += mLength;
444
460
  anchor = ip;
445
461
 
446
462
  if (ip <= ilimit) {
447
- /* Fill Table */
448
- hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
449
- hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
450
- hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
451
- hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
463
+ /* Complementary insertion */
464
+ /* done after iLimit test, as candidates could be > iend-8 */
465
+ { U32 const indexToInsert = current+2;
466
+ hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
467
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
468
+ hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
469
+ hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
470
+ }
471
+
452
472
  /* check immediate repcode */
453
473
  while (ip <= ilimit) {
454
474
  U32 const current2 = (U32)(ip-base);
@@ -475,7 +495,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
475
495
  rep[1] = offset_2;
476
496
 
477
497
  /* Return the last literals size */
478
- return iend - anchor;
498
+ return (size_t)(iend - anchor);
479
499
  }
480
500
 
481
501
 
@@ -13,7 +13,8 @@
13
13
 
14
14
 
15
15
  void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
16
- void const* end, ZSTD_dictTableLoadMethod_e dtlm)
16
+ const void* const end,
17
+ ZSTD_dictTableLoadMethod_e dtlm)
17
18
  {
18
19
  const ZSTD_compressionParameters* const cParams = &ms->cParams;
19
20
  U32* const hashTable = ms->hashTable;
@@ -41,6 +42,7 @@ void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
41
42
  } } } }
42
43
  }
43
44
 
45
+
44
46
  FORCE_INLINE_TEMPLATE
45
47
  size_t ZSTD_compressBlock_fast_generic(
46
48
  ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
@@ -58,7 +60,10 @@ size_t ZSTD_compressBlock_fast_generic(
58
60
  const BYTE* ip0 = istart;
59
61
  const BYTE* ip1;
60
62
  const BYTE* anchor = istart;
61
- const U32 prefixStartIndex = ms->window.dictLimit;
63
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
64
+ const U32 maxDistance = 1U << cParams->windowLog;
65
+ const U32 validStartIndex = ms->window.dictLimit;
66
+ const U32 prefixStartIndex = (endIndex - validStartIndex > maxDistance) ? endIndex - maxDistance : validStartIndex;
62
67
  const BYTE* const prefixStart = base + prefixStartIndex;
63
68
  const BYTE* const iend = istart + srcSize;
64
69
  const BYTE* const ilimit = iend - HASH_READ_SIZE;
@@ -165,7 +170,7 @@ _match: /* Requires: ip0, match0, offcode */
165
170
  rep[1] = offset_2 ? offset_2 : offsetSaved;
166
171
 
167
172
  /* Return the last literals size */
168
- return iend - anchor;
173
+ return (size_t)(iend - anchor);
169
174
  }
170
175
 
171
176
 
@@ -222,8 +227,15 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
222
227
  const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart);
223
228
  const U32 dictHLog = dictCParams->hashLog;
224
229
 
225
- /* otherwise, we would get index underflow when translating a dict index
226
- * into a local index */
230
+ /* if a dictionary is still attached, it necessarily means that
231
+ * it is within window size. So we just check it. */
232
+ const U32 maxDistance = 1U << cParams->windowLog;
233
+ const U32 endIndex = (U32)((size_t)(ip - base) + srcSize);
234
+ assert(endIndex - prefixStartIndex <= maxDistance);
235
+ (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */
236
+
237
+ /* ensure there will be no no underflow
238
+ * when translating a dict index into a local index */
227
239
  assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
228
240
 
229
241
  /* init */
@@ -251,7 +263,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
251
263
  const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
252
264
  mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
253
265
  ip++;
254
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
266
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
255
267
  } else if ( (matchIndex <= prefixStartIndex) ) {
256
268
  size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls);
257
269
  U32 const dictMatchIndex = dictHashTable[dictHash];
@@ -271,7 +283,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
271
283
  } /* catch up */
272
284
  offset_2 = offset_1;
273
285
  offset_1 = offset;
274
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
286
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
275
287
  }
276
288
  } else if (MEM_read32(match) != MEM_read32(ip)) {
277
289
  /* it's not a match, and we're not going to check the dictionary */
@@ -286,7 +298,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
286
298
  && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
287
299
  offset_2 = offset_1;
288
300
  offset_1 = offset;
289
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
301
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
290
302
  }
291
303
 
292
304
  /* match found */
@@ -327,7 +339,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
327
339
  rep[1] = offset_2 ? offset_2 : offsetSaved;
328
340
 
329
341
  /* Return the last literals size */
330
- return iend - anchor;
342
+ return (size_t)(iend - anchor);
331
343
  }
332
344
 
333
345
  size_t ZSTD_compressBlock_fast_dictMatchState(
@@ -366,15 +378,24 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
366
378
  const BYTE* const istart = (const BYTE*)src;
367
379
  const BYTE* ip = istart;
368
380
  const BYTE* anchor = istart;
369
- const U32 dictStartIndex = ms->window.lowLimit;
381
+ const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
382
+ const U32 maxDistance = 1U << cParams->windowLog;
383
+ const U32 validLow = ms->window.lowLimit;
384
+ const U32 lowLimit = (endIndex - validLow > maxDistance) ? endIndex - maxDistance : validLow;
385
+ const U32 dictStartIndex = lowLimit;
370
386
  const BYTE* const dictStart = dictBase + dictStartIndex;
371
- const U32 prefixStartIndex = ms->window.dictLimit;
387
+ const U32 dictLimit = ms->window.dictLimit;
388
+ const U32 prefixStartIndex = dictLimit < lowLimit ? lowLimit : dictLimit;
372
389
  const BYTE* const prefixStart = base + prefixStartIndex;
373
390
  const BYTE* const dictEnd = dictBase + prefixStartIndex;
374
391
  const BYTE* const iend = istart + srcSize;
375
392
  const BYTE* const ilimit = iend - 8;
376
393
  U32 offset_1=rep[0], offset_2=rep[1];
377
394
 
395
+ /* switch to "regular" variant if extDict is invalidated due to maxDistance */
396
+ if (prefixStartIndex == dictStartIndex)
397
+ return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls);
398
+
378
399
  /* Search Loop */
379
400
  while (ip < ilimit) { /* < instead of <=, because (ip+1) */
380
401
  const size_t h = ZSTD_hashPtr(ip, hlog, mls);
@@ -394,7 +415,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
394
415
  const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
395
416
  mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
396
417
  ip++;
397
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
418
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
398
419
  } else {
399
420
  if ( (matchIndex < dictStartIndex) ||
400
421
  (MEM_read32(match) != MEM_read32(ip)) ) {
@@ -410,7 +431,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
410
431
  offset = current - matchIndex;
411
432
  offset_2 = offset_1;
412
433
  offset_1 = offset;
413
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
434
+ ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
414
435
  } }
415
436
 
416
437
  /* found a match : store it */
@@ -445,7 +466,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
445
466
  rep[1] = offset_2;
446
467
 
447
468
  /* Return the last literals size */
448
- return iend - anchor;
469
+ return (size_t)(iend - anchor);
449
470
  }
450
471
 
451
472