zstd-ruby 1.4.0.0 → 1.4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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