zstd-ruby 1.3.4.0 → 1.3.5.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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/zstdruby/libzstd/Makefile +56 -10
  4. data/ext/zstdruby/libzstd/README.md +4 -0
  5. data/ext/zstdruby/libzstd/common/bitstream.h +6 -19
  6. data/ext/zstdruby/libzstd/common/compiler.h +3 -3
  7. data/ext/zstdruby/libzstd/common/cpu.h +1 -2
  8. data/ext/zstdruby/libzstd/common/debug.c +44 -0
  9. data/ext/zstdruby/libzstd/common/debug.h +123 -0
  10. data/ext/zstdruby/libzstd/common/entropy_common.c +16 -1
  11. data/ext/zstdruby/libzstd/common/fse.h +45 -41
  12. data/ext/zstdruby/libzstd/common/fse_decompress.c +1 -1
  13. data/ext/zstdruby/libzstd/common/huf.h +34 -27
  14. data/ext/zstdruby/libzstd/common/pool.c +89 -32
  15. data/ext/zstdruby/libzstd/common/pool.h +29 -19
  16. data/ext/zstdruby/libzstd/common/zstd_common.c +0 -5
  17. data/ext/zstdruby/libzstd/common/zstd_internal.h +3 -37
  18. data/ext/zstdruby/libzstd/compress/fse_compress.c +28 -163
  19. data/ext/zstdruby/libzstd/compress/hist.c +195 -0
  20. data/ext/zstdruby/libzstd/compress/hist.h +92 -0
  21. data/ext/zstdruby/libzstd/compress/huf_compress.c +14 -6
  22. data/ext/zstdruby/libzstd/compress/zstd_compress.c +798 -350
  23. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +120 -34
  24. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +247 -87
  25. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +4 -1
  26. data/ext/zstdruby/libzstd/compress/zstd_fast.c +177 -56
  27. data/ext/zstdruby/libzstd/compress/zstd_fast.h +4 -1
  28. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +331 -65
  29. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +13 -0
  30. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +15 -20
  31. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +1 -2
  32. data/ext/zstdruby/libzstd/compress/zstd_opt.c +503 -300
  33. data/ext/zstdruby/libzstd/compress/zstd_opt.h +7 -0
  34. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +122 -47
  35. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +5 -5
  36. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +325 -325
  37. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +80 -43
  38. data/ext/zstdruby/libzstd/dictBuilder/cover.c +9 -2
  39. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +5 -5
  40. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +12 -61
  41. data/ext/zstdruby/libzstd/zstd.h +137 -69
  42. data/lib/zstd-ruby/version.rb +1 -1
  43. metadata +7 -3
@@ -27,6 +27,7 @@
27
27
  extern "C" {
28
28
  #endif
29
29
 
30
+
30
31
  /*-*************************************
31
32
  * Constants
32
33
  ***************************************/
@@ -37,7 +38,8 @@ extern "C" {
37
38
  It's not a big deal though : candidate will just be sorted again.
38
39
  Additionnally, candidate position 1 will be lost.
39
40
  But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
40
- The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy */
41
+ The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy
42
+ Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
41
43
 
42
44
 
43
45
  /*-*************************************
@@ -46,6 +48,12 @@ extern "C" {
46
48
  typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
47
49
  typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
48
50
 
51
+ typedef enum {
52
+ ZSTD_dictDefaultAttach = 0,
53
+ ZSTD_dictForceAttach = 1,
54
+ ZSTD_dictForceCopy = -1,
55
+ } ZSTD_dictAttachPref_e;
56
+
49
57
  typedef struct ZSTD_prefixDict_s {
50
58
  const void* dict;
51
59
  size_t dictSize;
@@ -53,14 +61,22 @@ typedef struct ZSTD_prefixDict_s {
53
61
  } ZSTD_prefixDict;
54
62
 
55
63
  typedef struct {
56
- U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
64
+ U32 CTable[HUF_CTABLE_SIZE_U32(255)];
65
+ HUF_repeat repeatMode;
66
+ } ZSTD_hufCTables_t;
67
+
68
+ typedef struct {
57
69
  FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
58
70
  FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
59
71
  FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
60
- HUF_repeat hufCTable_repeatMode;
61
72
  FSE_repeat offcode_repeatMode;
62
73
  FSE_repeat matchlength_repeatMode;
63
74
  FSE_repeat litlength_repeatMode;
75
+ } ZSTD_fseCTables_t;
76
+
77
+ typedef struct {
78
+ ZSTD_hufCTables_t huf;
79
+ ZSTD_fseCTables_t fse;
64
80
  } ZSTD_entropyCTables_t;
65
81
 
66
82
  typedef struct {
@@ -76,26 +92,27 @@ typedef struct {
76
92
  U32 rep[ZSTD_REP_NUM];
77
93
  } ZSTD_optimal_t;
78
94
 
95
+ typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
96
+
79
97
  typedef struct {
80
98
  /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
81
- U32* litFreq; /* table of literals statistics, of size 256 */
82
- U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
83
- U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
84
- U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
85
- ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
86
- ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
99
+ U32* litFreq; /* table of literals statistics, of size 256 */
100
+ U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
101
+ U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
102
+ U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
103
+ ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
104
+ ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
87
105
 
88
106
  U32 litSum; /* nb of literals */
89
107
  U32 litLengthSum; /* nb of litLength codes */
90
108
  U32 matchLengthSum; /* nb of matchLength codes */
91
109
  U32 offCodeSum; /* nb of offset codes */
92
- /* begin updated by ZSTD_setLog2Prices */
93
- U32 log2litSum; /* pow2 to compare log2(litfreq) to */
94
- U32 log2litLengthSum; /* pow2 to compare log2(llfreq) to */
95
- U32 log2matchLengthSum; /* pow2 to compare log2(mlfreq) to */
96
- U32 log2offCodeSum; /* pow2 to compare log2(offreq) to */
97
- /* end : updated by ZSTD_setLog2Prices */
98
- U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
110
+ U32 litSumBasePrice; /* to compare to log2(litfreq) */
111
+ U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */
112
+ U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */
113
+ U32 offCodeSumBasePrice; /* to compare to log2(offreq) */
114
+ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */
115
+ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */
99
116
  } optState_t;
100
117
 
101
118
  typedef struct {
@@ -111,17 +128,19 @@ typedef struct {
111
128
  U32 lowLimit; /* below that point, no more data */
112
129
  } ZSTD_window_t;
113
130
 
114
- typedef struct {
115
- ZSTD_window_t window; /* State for window round buffer management */
116
- U32 loadedDictEnd; /* index of end of dictionary */
117
- U32 nextToUpdate; /* index from which to continue table update */
118
- U32 nextToUpdate3; /* index from which to continue table update */
119
- U32 hashLog3; /* dispatch table : larger == faster, more memory */
131
+ typedef struct ZSTD_matchState_t ZSTD_matchState_t;
132
+ struct ZSTD_matchState_t {
133
+ ZSTD_window_t window; /* State for window round buffer management */
134
+ U32 loadedDictEnd; /* index of end of dictionary */
135
+ U32 nextToUpdate; /* index from which to continue table update */
136
+ U32 nextToUpdate3; /* index from which to continue table update */
137
+ U32 hashLog3; /* dispatch table : larger == faster, more memory */
120
138
  U32* hashTable;
121
139
  U32* hashTable3;
122
140
  U32* chainTable;
123
141
  optState_t opt; /* optimal parser state */
124
- } ZSTD_matchState_t;
142
+ const ZSTD_matchState_t *dictMatchState;
143
+ };
125
144
 
126
145
  typedef struct {
127
146
  ZSTD_compressedBlockState_t* prevCBlock;
@@ -161,7 +180,7 @@ typedef struct {
161
180
  rawSeq* seq; /* The start of the sequences */
162
181
  size_t pos; /* The position where reading stopped. <= size. */
163
182
  size_t size; /* The number of sequences. <= capacity. */
164
- size_t capacity; /* The capacity of the `seq` pointer */
183
+ size_t capacity; /* The capacity starting from `seq` pointer */
165
184
  } rawSeqStore_t;
166
185
 
167
186
  struct ZSTD_CCtx_params_s {
@@ -170,10 +189,11 @@ struct ZSTD_CCtx_params_s {
170
189
  ZSTD_frameParameters fParams;
171
190
 
172
191
  int compressionLevel;
173
- int disableLiteralCompression;
174
192
  int forceWindow; /* force back-references to respect limit of
175
193
  * 1<<wLog, even for dictionary */
176
194
 
195
+ ZSTD_dictAttachPref_e attachDictPref;
196
+
177
197
  /* Multithreading: used to pass parameters to mtctx */
178
198
  unsigned nbWorkers;
179
199
  unsigned jobSize;
@@ -193,6 +213,8 @@ struct ZSTD_CCtx_s {
193
213
  ZSTD_CCtx_params requestedParams;
194
214
  ZSTD_CCtx_params appliedParams;
195
215
  U32 dictID;
216
+
217
+ int workSpaceOversizedDuration;
196
218
  void* workSpace;
197
219
  size_t workSpaceSize;
198
220
  size_t blockSize;
@@ -235,11 +257,15 @@ struct ZSTD_CCtx_s {
235
257
  #endif
236
258
  };
237
259
 
260
+ typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
261
+
262
+ typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
263
+
238
264
 
239
265
  typedef size_t (*ZSTD_blockCompressor) (
240
266
  ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
241
267
  ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
242
- ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
268
+ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
243
269
 
244
270
 
245
271
  MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
@@ -280,11 +306,11 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
280
306
  */
281
307
  MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase)
282
308
  {
283
- #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
309
+ #if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
284
310
  static const BYTE* g_start = NULL;
285
311
  if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */
286
312
  { U32 const pos = (U32)((const BYTE*)literals - g_start);
287
- DEBUGLOG(6, "Cpos%7u :%3u literals, match%3u bytes at dist.code%7u",
313
+ DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
288
314
  pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode);
289
315
  }
290
316
  #endif
@@ -420,6 +446,11 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
420
446
  const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
421
447
  size_t const matchLength = ZSTD_count(ip, match, vEnd);
422
448
  if (match + matchLength != mEnd) return matchLength;
449
+ DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
450
+ DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
451
+ DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
452
+ DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
453
+ DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
423
454
  return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
424
455
  }
425
456
 
@@ -496,6 +527,20 @@ MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
496
527
  return window.lowLimit < window.dictLimit;
497
528
  }
498
529
 
530
+ /**
531
+ * ZSTD_matchState_dictMode():
532
+ * Inspects the provided matchState and figures out what dictMode should be
533
+ * passed to the compressor.
534
+ */
535
+ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
536
+ {
537
+ return ZSTD_window_hasExtDict(ms->window) ?
538
+ ZSTD_extDict :
539
+ ms->dictMatchState != NULL ?
540
+ ZSTD_dictMatchState :
541
+ ZSTD_noDict;
542
+ }
543
+
499
544
  /**
500
545
  * ZSTD_window_needOverflowCorrection():
501
546
  * Returns non-zero if the indices are getting too large and need overflow
@@ -563,31 +608,41 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
563
608
  * ZSTD_window_enforceMaxDist():
564
609
  * Updates lowLimit so that:
565
610
  * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
611
+ *
566
612
  * This allows a simple check that index >= lowLimit to see if index is valid.
567
613
  * This must be called before a block compression call, with srcEnd as the block
568
614
  * source end.
615
+ *
569
616
  * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit.
570
617
  * This is because dictionaries are allowed to be referenced as long as the last
571
618
  * byte of the dictionary is in the window, but once they are out of range,
572
619
  * they cannot be referenced. If loadedDictEndPtr is NULL, we use
573
620
  * loadedDictEnd == 0.
621
+ *
622
+ * In normal dict mode, the dict is between lowLimit and dictLimit. In
623
+ * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary
624
+ * is below them. forceWindow and dictMatchState are therefore incompatible.
574
625
  */
575
626
  MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
576
627
  void const* srcEnd, U32 maxDist,
577
- U32* loadedDictEndPtr)
628
+ U32* loadedDictEndPtr,
629
+ const ZSTD_matchState_t** dictMatchStatePtr)
578
630
  {
579
631
  U32 const current = (U32)((BYTE const*)srcEnd - window->base);
580
632
  U32 loadedDictEnd = loadedDictEndPtr != NULL ? *loadedDictEndPtr : 0;
633
+ DEBUGLOG(5, "ZSTD_window_enforceMaxDist: current=%u, maxDist=%u", current, maxDist);
581
634
  if (current > maxDist + loadedDictEnd) {
582
635
  U32 const newLowLimit = current - maxDist;
583
636
  if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
584
637
  if (window->dictLimit < window->lowLimit) {
585
- DEBUGLOG(5, "Update dictLimit from %u to %u", window->dictLimit,
586
- window->lowLimit);
638
+ DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
639
+ window->dictLimit, window->lowLimit);
587
640
  window->dictLimit = window->lowLimit;
588
641
  }
589
642
  if (loadedDictEndPtr)
590
643
  *loadedDictEndPtr = 0;
644
+ if (dictMatchStatePtr)
645
+ *dictMatchStatePtr = NULL;
591
646
  }
592
647
  }
593
648
 
@@ -603,12 +658,12 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
603
658
  {
604
659
  BYTE const* const ip = (BYTE const*)src;
605
660
  U32 contiguous = 1;
661
+ DEBUGLOG(5, "ZSTD_window_update");
606
662
  /* Check if blocks follow each other */
607
663
  if (src != window->nextSrc) {
608
664
  /* not contiguous */
609
665
  size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
610
- DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u",
611
- window->dictLimit);
666
+ DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
612
667
  window->lowLimit = window->dictLimit;
613
668
  assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
614
669
  window->dictLimit = (U32)distanceFromBase;
@@ -625,10 +680,38 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
625
680
  ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
626
681
  U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
627
682
  window->lowLimit = lowLimitMax;
683
+ DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
628
684
  }
629
685
  return contiguous;
630
686
  }
631
687
 
688
+
689
+ /* debug functions */
690
+
691
+ MEM_STATIC double ZSTD_fWeight(U32 rawStat)
692
+ {
693
+ U32 const fp_accuracy = 8;
694
+ U32 const fp_multiplier = (1 << fp_accuracy);
695
+ U32 const stat = rawStat + 1;
696
+ U32 const hb = ZSTD_highbit32(stat);
697
+ U32 const BWeight = hb * fp_multiplier;
698
+ U32 const FWeight = (stat << fp_accuracy) >> hb;
699
+ U32 const weight = BWeight + FWeight;
700
+ assert(hb + fp_accuracy < 31);
701
+ return (double)weight / fp_multiplier;
702
+ }
703
+
704
+ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
705
+ {
706
+ unsigned u, sum;
707
+ for (u=0, sum=0; u<=max; u++) sum += table[u];
708
+ DEBUGLOG(2, "total nb elts: %u", sum);
709
+ for (u=0; u<=max; u++) {
710
+ DEBUGLOG(2, "%2u: %5u (%.2f)",
711
+ u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
712
+ }
713
+ }
714
+
632
715
  #if defined (__cplusplus)
633
716
  }
634
717
  #endif
@@ -640,7 +723,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
640
723
  * ============================================================== */
641
724
 
642
725
  /* ZSTD_getCParamsFromCCtxParams() :
643
- * cParams are built depending on compressionLevel, src size hints,
726
+ * cParams are built depending on compressionLevel, src size hints,
644
727
  * LDM and manually set compression parameters.
645
728
  */
646
729
  ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
@@ -656,6 +739,8 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
656
739
  const ZSTD_CDict* cdict,
657
740
  ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
658
741
 
742
+ void ZSTD_resetSeqStore(seqStore_t* ssPtr);
743
+
659
744
  /*! ZSTD_compressStream_generic() :
660
745
  * Private use only. To be called from zstdmt_compress.c in single-thread mode. */
661
746
  size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
@@ -672,6 +757,7 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
672
757
  size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
673
758
  const void* dict, size_t dictSize,
674
759
  ZSTD_dictContentType_e dictContentType,
760
+ ZSTD_dictTableLoadMethod_e dtlm,
675
761
  const ZSTD_CDict* cdict,
676
762
  ZSTD_CCtx_params params,
677
763
  unsigned long long pledgedSrcSize);
@@ -14,7 +14,7 @@
14
14
 
15
15
  void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
16
16
  ZSTD_compressionParameters const* cParams,
17
- void const* end)
17
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm)
18
18
  {
19
19
  U32* const hashLarge = ms->hashTable;
20
20
  U32 const hBitsL = cParams->hashLog;
@@ -40,6 +40,9 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
40
40
  hashSmall[smHash] = current + i;
41
41
  if (i == 0 || hashLarge[lgHash] == 0)
42
42
  hashLarge[lgHash] = current + i;
43
+ /* Only load extra positions for ZSTD_dtlm_full */
44
+ if (dtlm == ZSTD_dtlm_fast)
45
+ break;
43
46
  }
44
47
  }
45
48
  }
@@ -49,7 +52,7 @@ FORCE_INLINE_TEMPLATE
49
52
  size_t ZSTD_compressBlock_doubleFast_generic(
50
53
  ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
51
54
  ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
52
- U32 const mls /* template */)
55
+ U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
53
56
  {
54
57
  U32* const hashLong = ms->hashTable;
55
58
  const U32 hBitsL = cParams->hashLog;
@@ -59,70 +62,178 @@ size_t ZSTD_compressBlock_doubleFast_generic(
59
62
  const BYTE* const istart = (const BYTE*)src;
60
63
  const BYTE* ip = istart;
61
64
  const BYTE* anchor = istart;
62
- const U32 lowestIndex = ms->window.dictLimit;
63
- const BYTE* const lowest = base + lowestIndex;
65
+ const U32 prefixLowestIndex = ms->window.dictLimit;
66
+ const BYTE* const prefixLowest = base + prefixLowestIndex;
64
67
  const BYTE* const iend = istart + srcSize;
65
68
  const BYTE* const ilimit = iend - HASH_READ_SIZE;
66
69
  U32 offset_1=rep[0], offset_2=rep[1];
67
70
  U32 offsetSaved = 0;
68
71
 
72
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
73
+ const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ?
74
+ dms->hashTable : NULL;
75
+ const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
76
+ dms->chainTable : NULL;
77
+ const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
78
+ dms->window.dictLimit : 0;
79
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
80
+ dms->window.base : NULL;
81
+ const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
82
+ dictBase + dictStartIndex : NULL;
83
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
84
+ dms->window.nextSrc : NULL;
85
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
86
+ prefixLowestIndex - (U32)(dictEnd - dictBase) :
87
+ 0;
88
+ const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart);
89
+
90
+ assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
91
+
69
92
  /* init */
70
- ip += (ip==lowest);
71
- { U32 const maxRep = (U32)(ip-lowest);
93
+ ip += (dictAndPrefixLength == 0);
94
+ if (dictMode == ZSTD_noDict) {
95
+ U32 const maxRep = (U32)(ip - prefixLowest);
72
96
  if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
73
97
  if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
74
98
  }
99
+ if (dictMode == ZSTD_dictMatchState) {
100
+ /* dictMatchState repCode checks don't currently handle repCode == 0
101
+ * disabling. */
102
+ assert(offset_1 <= dictAndPrefixLength);
103
+ assert(offset_2 <= dictAndPrefixLength);
104
+ }
75
105
 
76
106
  /* Main Search Loop */
77
107
  while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
78
108
  size_t mLength;
109
+ U32 offset;
79
110
  size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
80
111
  size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
81
112
  U32 const current = (U32)(ip-base);
82
113
  U32 const matchIndexL = hashLong[h2];
83
- U32 const matchIndexS = hashSmall[h];
114
+ U32 matchIndexS = hashSmall[h];
84
115
  const BYTE* matchLong = base + matchIndexL;
85
116
  const BYTE* match = base + matchIndexS;
117
+ const U32 repIndex = current + 1 - offset_1;
118
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
119
+ && repIndex < prefixLowestIndex) ?
120
+ dictBase + (repIndex - dictIndexDelta) :
121
+ base + repIndex;
86
122
  hashLong[h2] = hashSmall[h] = current; /* update hash tables */
87
123
 
88
- assert(offset_1 <= current); /* supposed guaranteed by construction */
89
- if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
90
- /* favor repcode */
124
+ /* check dictMatchState repcode */
125
+ if (dictMode == ZSTD_dictMatchState
126
+ && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
127
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
128
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
129
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
130
+ ip++;
131
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
132
+ goto _match_stored;
133
+ }
134
+
135
+ /* check noDict repcode */
136
+ if ( dictMode == ZSTD_noDict
137
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
91
138
  mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
92
139
  ip++;
93
140
  ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
94
- } else {
95
- U32 offset;
96
- if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
97
- mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
98
- offset = (U32)(ip-matchLong);
99
- while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
100
- } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
101
- size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
102
- U32 const matchIndexL3 = hashLong[hl3];
103
- const BYTE* matchL3 = base + matchIndexL3;
104
- hashLong[hl3] = current + 1;
105
- if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
106
- mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
141
+ goto _match_stored;
142
+ }
143
+
144
+ /* check prefix long match */
145
+ if ( (matchIndexL > prefixLowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
146
+ mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
147
+ offset = (U32)(ip-matchLong);
148
+ while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
149
+ goto _match_found;
150
+ }
151
+
152
+ /* check dictMatchState long match */
153
+ if (dictMode == ZSTD_dictMatchState) {
154
+ U32 const dictMatchIndexL = dictHashLong[h2];
155
+ const BYTE* dictMatchL = dictBase + dictMatchIndexL;
156
+ assert(dictMatchL < dictEnd);
157
+
158
+ if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
159
+ mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
160
+ offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
161
+ while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
162
+ goto _match_found;
163
+ }
164
+ }
165
+
166
+ /* check prefix short match */
167
+ if ( (matchIndexS > prefixLowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
168
+ goto _search_next_long;
169
+ }
170
+
171
+ /* check dictMatchState short match */
172
+ if (dictMode == ZSTD_dictMatchState) {
173
+ U32 const dictMatchIndexS = dictHashSmall[h];
174
+ match = dictBase + dictMatchIndexS;
175
+ matchIndexS = dictMatchIndexS + dictIndexDelta;
176
+
177
+ if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
178
+ goto _search_next_long;
179
+ }
180
+ }
181
+
182
+ ip += ((ip-anchor) >> kSearchStrength) + 1;
183
+ continue;
184
+
185
+ _search_next_long:
186
+
187
+ {
188
+ size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
189
+ U32 const matchIndexL3 = hashLong[hl3];
190
+ const BYTE* matchL3 = base + matchIndexL3;
191
+ hashLong[hl3] = current + 1;
192
+
193
+ /* check prefix long +1 match */
194
+ if ( (matchIndexL3 > prefixLowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
195
+ mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
196
+ ip++;
197
+ offset = (U32)(ip-matchL3);
198
+ while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
199
+ goto _match_found;
200
+ }
201
+
202
+ /* check dict long +1 match */
203
+ if (dictMode == ZSTD_dictMatchState) {
204
+ U32 const dictMatchIndexL3 = dictHashLong[hl3];
205
+ const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
206
+ assert(dictMatchL3 < dictEnd);
207
+ if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
208
+ mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
107
209
  ip++;
108
- offset = (U32)(ip-matchL3);
109
- while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
110
- } else {
111
- mLength = ZSTD_count(ip+4, match+4, iend) + 4;
112
- offset = (U32)(ip-match);
113
- while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
210
+ offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
211
+ while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
212
+ goto _match_found;
114
213
  }
115
- } else {
116
- ip += ((ip-anchor) >> kSearchStrength) + 1;
117
- continue;
118
214
  }
215
+ }
119
216
 
120
- offset_2 = offset_1;
121
- offset_1 = offset;
122
-
123
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
217
+ /* if no long +1 match, explore the short match we found */
218
+ if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
219
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
220
+ offset = (U32)(current - matchIndexS);
221
+ while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
222
+ } else {
223
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
224
+ offset = (U32)(ip - match);
225
+ while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
124
226
  }
125
227
 
228
+ /* fall-through */
229
+
230
+ _match_found:
231
+ offset_2 = offset_1;
232
+ offset_1 = offset;
233
+
234
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
235
+
236
+ _match_stored:
126
237
  /* match found */
127
238
  ip += mLength;
128
239
  anchor = ip;
@@ -135,19 +246,44 @@ size_t ZSTD_compressBlock_doubleFast_generic(
135
246
  hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
136
247
 
137
248
  /* check immediate repcode */
138
- while ( (ip <= ilimit)
139
- && ( (offset_2>0)
140
- & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
141
- /* store sequence */
142
- size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
143
- { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
144
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
145
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
146
- ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
147
- ip += rLength;
148
- anchor = ip;
149
- continue; /* faster when present ... (?) */
150
- } } }
249
+ if (dictMode == ZSTD_dictMatchState) {
250
+ while (ip <= ilimit) {
251
+ U32 const current2 = (U32)(ip-base);
252
+ U32 const repIndex2 = current2 - offset_2;
253
+ const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
254
+ && repIndex2 < prefixLowestIndex ?
255
+ dictBase - dictIndexDelta + repIndex2 :
256
+ base + repIndex2;
257
+ if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
258
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
259
+ const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
260
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
261
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
262
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
263
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
264
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
265
+ ip += repLength2;
266
+ anchor = ip;
267
+ continue;
268
+ }
269
+ break;
270
+ }
271
+ }
272
+
273
+ if (dictMode == ZSTD_noDict) {
274
+ while ( (ip <= ilimit)
275
+ && ( (offset_2>0)
276
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
277
+ /* store sequence */
278
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
279
+ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
280
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
281
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
282
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
283
+ ip += rLength;
284
+ anchor = ip;
285
+ continue; /* faster when present ... (?) */
286
+ } } } }
151
287
 
152
288
  /* save reps for next block */
153
289
  rep[0] = offset_1 ? offset_1 : offsetSaved;
@@ -167,13 +303,33 @@ size_t ZSTD_compressBlock_doubleFast(
167
303
  {
168
304
  default: /* includes case 3 */
169
305
  case 4 :
170
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4);
306
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4, ZSTD_noDict);
171
307
  case 5 :
172
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5);
308
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5, ZSTD_noDict);
173
309
  case 6 :
174
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6);
310
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6, ZSTD_noDict);
175
311
  case 7 :
176
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7);
312
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7, ZSTD_noDict);
313
+ }
314
+ }
315
+
316
+
317
+ size_t ZSTD_compressBlock_doubleFast_dictMatchState(
318
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
319
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
320
+ {
321
+ const U32 mls = cParams->searchLength;
322
+ switch(mls)
323
+ {
324
+ default: /* includes case 3 */
325
+ case 4 :
326
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4, ZSTD_dictMatchState);
327
+ case 5 :
328
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5, ZSTD_dictMatchState);
329
+ case 6 :
330
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6, ZSTD_dictMatchState);
331
+ case 7 :
332
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7, ZSTD_dictMatchState);
177
333
  }
178
334
  }
179
335
 
@@ -187,75 +343,78 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
187
343
  U32 const hBitsL = cParams->hashLog;
188
344
  U32* const hashSmall = ms->chainTable;
189
345
  U32 const hBitsS = cParams->chainLog;
190
- const BYTE* const base = ms->window.base;
191
- const BYTE* const dictBase = ms->window.dictBase;
192
346
  const BYTE* const istart = (const BYTE*)src;
193
347
  const BYTE* ip = istart;
194
348
  const BYTE* anchor = istart;
195
- const U32 lowestIndex = ms->window.lowLimit;
196
- const BYTE* const dictStart = dictBase + lowestIndex;
197
- const U32 dictLimit = ms->window.dictLimit;
198
- const BYTE* const lowPrefixPtr = base + dictLimit;
199
- const BYTE* const dictEnd = dictBase + dictLimit;
200
349
  const BYTE* const iend = istart + srcSize;
201
350
  const BYTE* const ilimit = iend - 8;
351
+ const U32 prefixStartIndex = ms->window.dictLimit;
352
+ const BYTE* const base = ms->window.base;
353
+ const BYTE* const prefixStart = base + prefixStartIndex;
354
+ const U32 dictStartIndex = ms->window.lowLimit;
355
+ const BYTE* const dictBase = ms->window.dictBase;
356
+ const BYTE* const dictStart = dictBase + dictStartIndex;
357
+ const BYTE* const dictEnd = dictBase + prefixStartIndex;
202
358
  U32 offset_1=rep[0], offset_2=rep[1];
203
359
 
360
+ DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
361
+
204
362
  /* Search Loop */
205
363
  while (ip < ilimit) { /* < instead of <=, because (ip+1) */
206
364
  const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
207
365
  const U32 matchIndex = hashSmall[hSmall];
208
- const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
366
+ const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
209
367
  const BYTE* match = matchBase + matchIndex;
210
368
 
211
369
  const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
212
370
  const U32 matchLongIndex = hashLong[hLong];
213
- const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
371
+ const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
214
372
  const BYTE* matchLong = matchLongBase + matchLongIndex;
215
373
 
216
374
  const U32 current = (U32)(ip-base);
217
375
  const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
218
- const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
219
- const BYTE* repMatch = repBase + repIndex;
376
+ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
377
+ const BYTE* const repMatch = repBase + repIndex;
220
378
  size_t mLength;
221
379
  hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
222
380
 
223
- if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
224
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
225
- const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
226
- mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
381
+ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
382
+ & (repIndex > dictStartIndex))
383
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
384
+ const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
385
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
227
386
  ip++;
228
387
  ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
229
388
  } else {
230
- if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
231
- const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
232
- const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
389
+ if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
390
+ const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
391
+ const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
233
392
  U32 offset;
234
- mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
393
+ mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
235
394
  offset = current - matchLongIndex;
236
395
  while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
237
396
  offset_2 = offset_1;
238
397
  offset_1 = offset;
239
398
  ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
240
399
 
241
- } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
400
+ } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
242
401
  size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
243
402
  U32 const matchIndex3 = hashLong[h3];
244
- const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
403
+ const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
245
404
  const BYTE* match3 = match3Base + matchIndex3;
246
405
  U32 offset;
247
406
  hashLong[h3] = current + 1;
248
- if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
249
- const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
250
- const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
251
- mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
407
+ if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
408
+ const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
409
+ const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
410
+ mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
252
411
  ip++;
253
412
  offset = current+1 - matchIndex3;
254
413
  while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
255
414
  } else {
256
- const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
257
- const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
258
- mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
415
+ const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
416
+ const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
417
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
259
418
  offset = current - matchIndex;
260
419
  while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
261
420
  }
@@ -282,12 +441,13 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
282
441
  while (ip <= ilimit) {
283
442
  U32 const current2 = (U32)(ip-base);
284
443
  U32 const repIndex2 = current2 - offset_2;
285
- const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
286
- if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
287
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
288
- const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
289
- size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
290
- U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
444
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
445
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
446
+ & (repIndex2 > dictStartIndex))
447
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
448
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
449
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
450
+ U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
291
451
  ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
292
452
  hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
293
453
  hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;