extzstd 0.0.2.CONCEPT → 0.0.3.CONCEPT

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +72 -22
  3. data/Rakefile +73 -19
  4. data/contrib/zstd/README.md +68 -0
  5. data/contrib/zstd/common/bitstream.h +414 -0
  6. data/contrib/zstd/common/entropy_common.c +231 -0
  7. data/contrib/zstd/common/error_private.h +125 -0
  8. data/contrib/zstd/common/error_public.h +77 -0
  9. data/contrib/zstd/common/fse.h +628 -0
  10. data/contrib/zstd/common/fse_decompress.c +331 -0
  11. data/contrib/zstd/common/huf.h +228 -0
  12. data/contrib/zstd/common/mem.h +377 -0
  13. data/contrib/zstd/common/xxhash.c +854 -0
  14. data/contrib/zstd/common/xxhash.h +273 -0
  15. data/contrib/zstd/common/zbuff.h +197 -0
  16. data/contrib/zstd/common/zstd.h +475 -0
  17. data/contrib/zstd/common/zstd_common.c +91 -0
  18. data/contrib/zstd/common/zstd_internal.h +238 -0
  19. data/contrib/zstd/compress/fse_compress.c +807 -0
  20. data/contrib/zstd/compress/huf_compress.c +577 -0
  21. data/contrib/zstd/compress/zbuff_compress.c +327 -0
  22. data/contrib/zstd/compress/zstd_compress.c +3074 -0
  23. data/contrib/zstd/compress/zstd_opt.h +1046 -0
  24. data/contrib/zstd/decompress/huf_decompress.c +894 -0
  25. data/contrib/zstd/decompress/zbuff_decompress.c +294 -0
  26. data/contrib/zstd/decompress/zstd_decompress.c +1362 -0
  27. data/contrib/zstd/dictBuilder/divsufsort.c +1913 -0
  28. data/contrib/zstd/dictBuilder/divsufsort.h +67 -0
  29. data/contrib/zstd/dictBuilder/zdict.c +1045 -0
  30. data/contrib/zstd/dictBuilder/zdict.h +113 -0
  31. data/contrib/zstd/legacy/zstd_legacy.h +140 -0
  32. data/contrib/zstd/legacy/zstd_v01.c +2178 -0
  33. data/contrib/zstd/{zstd.h → legacy/zstd_v01.h} +46 -39
  34. data/contrib/zstd/legacy/zstd_v02.c +3748 -0
  35. data/contrib/zstd/legacy/zstd_v02.h +99 -0
  36. data/contrib/zstd/legacy/zstd_v03.c +3389 -0
  37. data/contrib/zstd/legacy/zstd_v03.h +99 -0
  38. data/contrib/zstd/legacy/zstd_v04.c +4056 -0
  39. data/contrib/zstd/legacy/zstd_v04.h +148 -0
  40. data/contrib/zstd/legacy/zstd_v05.c +4325 -0
  41. data/contrib/zstd/legacy/zstd_v05.h +171 -0
  42. data/contrib/zstd/legacy/zstd_v06.c +4581 -0
  43. data/contrib/zstd/legacy/zstd_v06.h +185 -0
  44. data/ext/extconf.rb +10 -12
  45. data/ext/extzstd.c +497 -144
  46. data/ext/extzstd.h +127 -22
  47. data/ext/extzstd_buffered.c +265 -0
  48. data/ext/extzstd_nogvls.h +174 -0
  49. data/ext/zstd_amalgam.c +18 -0
  50. data/ext/zstd_legacy_v01.c +1 -0
  51. data/ext/zstd_legacy_v02.c +1 -0
  52. data/ext/zstd_legacy_v03.c +1 -0
  53. data/ext/zstd_legacy_v04.c +1 -0
  54. data/ext/zstd_legacy_v05.c +1 -0
  55. data/ext/zstd_legacy_v06.c +1 -0
  56. data/gemstub.rb +17 -1
  57. data/lib/extzstd.rb +197 -77
  58. data/lib/extzstd/version.rb +1 -1
  59. data/test/test_basic.rb +41 -0
  60. metadata +70 -20
  61. data/contrib/zstd/Makefile +0 -115
  62. data/contrib/zstd/fse.c +0 -2466
  63. data/contrib/zstd/fse.h +0 -320
  64. data/contrib/zstd/fse_static.h +0 -282
  65. data/contrib/zstd/libzstd.pc.in +0 -14
  66. data/contrib/zstd/zstd.c +0 -1768
  67. data/contrib/zstd/zstd_static.h +0 -89
  68. data/ext/extzstd-stream.c +0 -398
@@ -0,0 +1,327 @@
1
+ /*
2
+ Buffered version of Zstd compression library
3
+ Copyright (C) 2015-2016, Yann Collet.
4
+
5
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are
9
+ met:
10
+ * Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+ * Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following disclaimer
14
+ in the documentation and/or other materials provided with the
15
+ distribution.
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ You can contact the author at :
29
+ - zstd homepage : http://www.zstd.net/
30
+ */
31
+
32
+
33
+ /* *************************************
34
+ * Dependencies
35
+ ***************************************/
36
+ #include <stdlib.h>
37
+ #include "error_private.h"
38
+ #include "zstd_internal.h" /* MIN, ZSTD_BLOCKHEADERSIZE, defaultCustomMem */
39
+ #define ZBUFF_STATIC_LINKING_ONLY
40
+ #include "zbuff.h"
41
+
42
+
43
+ /* *************************************
44
+ * Constants
45
+ ***************************************/
46
+ static size_t const ZBUFF_endFrameSize = ZSTD_BLOCKHEADERSIZE;
47
+
48
+
49
+ /*_**************************************************
50
+ * Streaming compression
51
+ *
52
+ * A ZBUFF_CCtx object is required to track streaming operation.
53
+ * Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources.
54
+ * Use ZBUFF_compressInit() to start a new compression operation.
55
+ * ZBUFF_CCtx objects can be reused multiple times.
56
+ *
57
+ * Use ZBUFF_compressContinue() repetitively to consume your input.
58
+ * *srcSizePtr and *dstCapacityPtr can be any size.
59
+ * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
60
+ * Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input.
61
+ * The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst .
62
+ * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency)
63
+ * or an error code, which can be tested using ZBUFF_isError().
64
+ *
65
+ * ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer.
66
+ * Note that it will not output more than *dstCapacityPtr.
67
+ * Therefore, some content might still be left into its internal buffer if dst buffer is too small.
68
+ * @return : nb of bytes still present into internal buffer (0 if it's empty)
69
+ * or an error code, which can be tested using ZBUFF_isError().
70
+ *
71
+ * ZBUFF_compressEnd() instructs to finish a frame.
72
+ * It will perform a flush and write frame epilogue.
73
+ * Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small.
74
+ * @return : nb of bytes still present into internal buffer (0 if it's empty)
75
+ * or an error code, which can be tested using ZBUFF_isError().
76
+ *
77
+ * Hint : recommended buffer sizes (not compulsory)
78
+ * input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value.
79
+ * output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed.
80
+ * **************************************************/
81
+
82
+ typedef enum { ZBUFFcs_init, ZBUFFcs_load, ZBUFFcs_flush, ZBUFFcs_final } ZBUFF_cStage;
83
+
84
+ /* *** Resources *** */
85
+ struct ZBUFF_CCtx_s {
86
+ ZSTD_CCtx* zc;
87
+ char* inBuff;
88
+ size_t inBuffSize;
89
+ size_t inToCompress;
90
+ size_t inBuffPos;
91
+ size_t inBuffTarget;
92
+ size_t blockSize;
93
+ char* outBuff;
94
+ size_t outBuffSize;
95
+ size_t outBuffContentSize;
96
+ size_t outBuffFlushedSize;
97
+ ZBUFF_cStage stage;
98
+ ZSTD_customMem customMem;
99
+ }; /* typedef'd tp ZBUFF_CCtx within "zstd_buffered.h" */
100
+
101
+ ZBUFF_CCtx* ZBUFF_createCCtx(void)
102
+ {
103
+ return ZBUFF_createCCtx_advanced(defaultCustomMem);
104
+ }
105
+
106
+ ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem)
107
+ {
108
+ ZBUFF_CCtx* zbc;
109
+
110
+ if (!customMem.customAlloc && !customMem.customFree)
111
+ customMem = defaultCustomMem;
112
+
113
+ if (!customMem.customAlloc || !customMem.customFree)
114
+ return NULL;
115
+
116
+ zbc = (ZBUFF_CCtx*)customMem.customAlloc(customMem.opaque, sizeof(ZBUFF_CCtx));
117
+ if (zbc==NULL) return NULL;
118
+ memset(zbc, 0, sizeof(ZBUFF_CCtx));
119
+ memcpy(&zbc->customMem, &customMem, sizeof(ZSTD_customMem));
120
+ zbc->zc = ZSTD_createCCtx_advanced(customMem);
121
+ if (zbc->zc == NULL) { ZBUFF_freeCCtx(zbc); return NULL; }
122
+ return zbc;
123
+ }
124
+
125
+ size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc)
126
+ {
127
+ if (zbc==NULL) return 0; /* support free on NULL */
128
+ ZSTD_freeCCtx(zbc->zc);
129
+ if (zbc->inBuff) zbc->customMem.customFree(zbc->customMem.opaque, zbc->inBuff);
130
+ if (zbc->outBuff) zbc->customMem.customFree(zbc->customMem.opaque, zbc->outBuff);
131
+ zbc->customMem.customFree(zbc->customMem.opaque, zbc);
132
+ return 0;
133
+ }
134
+
135
+
136
+ /* *** Initialization *** */
137
+
138
+ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc,
139
+ const void* dict, size_t dictSize,
140
+ ZSTD_parameters params, unsigned long long pledgedSrcSize)
141
+ {
142
+ /* allocate buffers */
143
+ { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
144
+ if (zbc->inBuffSize < neededInBuffSize) {
145
+ zbc->inBuffSize = neededInBuffSize;
146
+ zbc->customMem.customFree(zbc->customMem.opaque, zbc->inBuff); /* should not be necessary */
147
+ zbc->inBuff = (char*)zbc->customMem.customAlloc(zbc->customMem.opaque, neededInBuffSize);
148
+ if (zbc->inBuff == NULL) return ERROR(memory_allocation);
149
+ }
150
+ zbc->blockSize = MIN(ZSTD_BLOCKSIZE_MAX, neededInBuffSize);
151
+ }
152
+ if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) {
153
+ zbc->outBuffSize = ZSTD_compressBound(zbc->blockSize)+1;
154
+ zbc->customMem.customFree(zbc->customMem.opaque, zbc->outBuff); /* should not be necessary */
155
+ zbc->outBuff = (char*)zbc->customMem.customAlloc(zbc->customMem.opaque, zbc->outBuffSize);
156
+ if (zbc->outBuff == NULL) return ERROR(memory_allocation);
157
+ }
158
+
159
+ { size_t const errorCode = ZSTD_compressBegin_advanced(zbc->zc, dict, dictSize, params, pledgedSrcSize);
160
+ if (ZSTD_isError(errorCode)) return errorCode; }
161
+
162
+ zbc->inToCompress = 0;
163
+ zbc->inBuffPos = 0;
164
+ zbc->inBuffTarget = zbc->blockSize;
165
+ zbc->outBuffContentSize = zbc->outBuffFlushedSize = 0;
166
+ zbc->stage = ZBUFFcs_load;
167
+ return 0; /* ready to go */
168
+ }
169
+
170
+
171
+ size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel)
172
+ {
173
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
174
+ return ZBUFF_compressInit_advanced(zbc, dict, dictSize, params, 0);
175
+ }
176
+
177
+ size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel)
178
+ {
179
+ return ZBUFF_compressInitDictionary(zbc, NULL, 0, compressionLevel);
180
+ }
181
+
182
+
183
+ /* internal util function */
184
+ MEM_STATIC size_t ZBUFF_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
185
+ {
186
+ size_t const length = MIN(dstCapacity, srcSize);
187
+ memcpy(dst, src, length);
188
+ return length;
189
+ }
190
+
191
+
192
+ /* *** Compression *** */
193
+
194
+ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc,
195
+ void* dst, size_t* dstCapacityPtr,
196
+ const void* src, size_t* srcSizePtr,
197
+ int flush)
198
+ {
199
+ U32 notDone = 1;
200
+ const char* const istart = (const char*)src;
201
+ const char* const iend = istart + *srcSizePtr;
202
+ const char* ip = istart;
203
+ char* const ostart = (char*)dst;
204
+ char* const oend = ostart + *dstCapacityPtr;
205
+ char* op = ostart;
206
+
207
+ while (notDone) {
208
+ switch(zbc->stage)
209
+ {
210
+ case ZBUFFcs_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
211
+
212
+ case ZBUFFcs_load:
213
+ /* complete inBuffer */
214
+ { size_t const toLoad = zbc->inBuffTarget - zbc->inBuffPos;
215
+ size_t const loaded = ZBUFF_limitCopy(zbc->inBuff + zbc->inBuffPos, toLoad, ip, iend-ip);
216
+ zbc->inBuffPos += loaded;
217
+ ip += loaded;
218
+ if ( (zbc->inBuffPos==zbc->inToCompress) || (!flush && (toLoad != loaded)) ) {
219
+ notDone = 0; break; /* not enough input to get a full block : stop there, wait for more */
220
+ } }
221
+ /* compress current block (note : this stage cannot be stopped in the middle) */
222
+ { void* cDst;
223
+ size_t cSize;
224
+ size_t const iSize = zbc->inBuffPos - zbc->inToCompress;
225
+ size_t oSize = oend-op;
226
+ if (oSize >= ZSTD_compressBound(iSize))
227
+ cDst = op; /* compress directly into output buffer (avoid flush stage) */
228
+ else
229
+ cDst = zbc->outBuff, oSize = zbc->outBuffSize;
230
+ cSize = ZSTD_compressContinue(zbc->zc, cDst, oSize, zbc->inBuff + zbc->inToCompress, iSize);
231
+ if (ZSTD_isError(cSize)) return cSize;
232
+ /* prepare next block */
233
+ zbc->inBuffTarget = zbc->inBuffPos + zbc->blockSize;
234
+ if (zbc->inBuffTarget > zbc->inBuffSize)
235
+ zbc->inBuffPos = 0, zbc->inBuffTarget = zbc->blockSize; /* note : inBuffSize >= blockSize */
236
+ zbc->inToCompress = zbc->inBuffPos;
237
+ if (cDst == op) { op += cSize; break; } /* no need to flush */
238
+ zbc->outBuffContentSize = cSize;
239
+ zbc->outBuffFlushedSize = 0;
240
+ zbc->stage = ZBUFFcs_flush; /* continue to flush stage */
241
+ }
242
+
243
+ case ZBUFFcs_flush:
244
+ { size_t const toFlush = zbc->outBuffContentSize - zbc->outBuffFlushedSize;
245
+ size_t const flushed = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outBuffFlushedSize, toFlush);
246
+ op += flushed;
247
+ zbc->outBuffFlushedSize += flushed;
248
+ if (toFlush!=flushed) { notDone = 0; break; } /* dst too small to store flushed data : stop there */
249
+ zbc->outBuffContentSize = zbc->outBuffFlushedSize = 0;
250
+ zbc->stage = ZBUFFcs_load;
251
+ break;
252
+ }
253
+
254
+ case ZBUFFcs_final:
255
+ notDone = 0; /* do nothing */
256
+ break;
257
+
258
+ default:
259
+ return ERROR(GENERIC); /* impossible */
260
+ }
261
+ }
262
+
263
+ *srcSizePtr = ip - istart;
264
+ *dstCapacityPtr = op - ostart;
265
+ { size_t hintInSize = zbc->inBuffTarget - zbc->inBuffPos;
266
+ if (hintInSize==0) hintInSize = zbc->blockSize;
267
+ return hintInSize;
268
+ }
269
+ }
270
+
271
+ size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc,
272
+ void* dst, size_t* dstCapacityPtr,
273
+ const void* src, size_t* srcSizePtr)
274
+ {
275
+ return ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, src, srcSizePtr, 0);
276
+ }
277
+
278
+
279
+
280
+ /* *** Finalize *** */
281
+
282
+ size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
283
+ {
284
+ size_t srcSize = 0;
285
+ ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, &srcSize, &srcSize, 1); /* use a valid src address instead of NULL */
286
+ return zbc->outBuffContentSize - zbc->outBuffFlushedSize;
287
+ }
288
+
289
+
290
+ size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr)
291
+ {
292
+ BYTE* const ostart = (BYTE*)dst;
293
+ BYTE* const oend = ostart + *dstCapacityPtr;
294
+ BYTE* op = ostart;
295
+
296
+ if (zbc->stage != ZBUFFcs_final) {
297
+ /* flush whatever remains */
298
+ size_t outSize = *dstCapacityPtr;
299
+ size_t const remainingToFlush = ZBUFF_compressFlush(zbc, dst, &outSize);
300
+ op += outSize;
301
+ if (remainingToFlush) {
302
+ *dstCapacityPtr = op-ostart;
303
+ return remainingToFlush + ZBUFF_endFrameSize;
304
+ }
305
+ /* create epilogue */
306
+ zbc->stage = ZBUFFcs_final;
307
+ zbc->outBuffContentSize = ZSTD_compressEnd(zbc->zc, zbc->outBuff, zbc->outBuffSize); /* epilogue into outBuff */
308
+ }
309
+
310
+ /* flush epilogue */
311
+ { size_t const toFlush = zbc->outBuffContentSize - zbc->outBuffFlushedSize;
312
+ size_t const flushed = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outBuffFlushedSize, toFlush);
313
+ op += flushed;
314
+ zbc->outBuffFlushedSize += flushed;
315
+ *dstCapacityPtr = op-ostart;
316
+ if (toFlush==flushed) zbc->stage = ZBUFFcs_init; /* end reached */
317
+ return toFlush - flushed;
318
+ }
319
+ }
320
+
321
+
322
+
323
+ /* *************************************
324
+ * Tool functions
325
+ ***************************************/
326
+ size_t ZBUFF_recommendedCInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
327
+ size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize; }
@@ -0,0 +1,3074 @@
1
+ /*
2
+ ZSTD HC - High Compression Mode of Zstandard
3
+ Copyright (C) 2015-2016, Yann Collet.
4
+
5
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are
9
+ met:
10
+
11
+ * Redistributions of source code must retain the above copyright
12
+ notice, this list of conditions and the following disclaimer.
13
+ * Redistributions in binary form must reproduce the above
14
+ copyright notice, this list of conditions and the following disclaimer
15
+ in the documentation and/or other materials provided with the
16
+ distribution.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ You can contact the author at :
31
+ - Zstd source repository : https://www.zstd.net
32
+ */
33
+
34
+
35
+ /* *******************************************************
36
+ * Compiler specifics
37
+ *********************************************************/
38
+ #ifdef _MSC_VER /* Visual Studio */
39
+ # define FORCE_INLINE static __forceinline
40
+ # include <intrin.h> /* For Visual 2005 */
41
+ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
42
+ #else
43
+ # ifdef __GNUC__
44
+ # define FORCE_INLINE static inline __attribute__((always_inline))
45
+ # else
46
+ # define FORCE_INLINE static inline
47
+ # endif
48
+ #endif
49
+
50
+
51
+ /*-*************************************
52
+ * Dependencies
53
+ ***************************************/
54
+ #include <string.h> /* memset */
55
+ #include "mem.h"
56
+ #define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
57
+ #include "xxhash.h" /* XXH_reset, update, digest */
58
+ #define FSE_STATIC_LINKING_ONLY
59
+ #include "fse.h"
60
+ #define HUF_STATIC_LINKING_ONLY
61
+ #include "huf.h"
62
+ #include "zstd_internal.h" /* includes zstd.h */
63
+
64
+
65
+ /*-*************************************
66
+ * Constants
67
+ ***************************************/
68
+ static const U32 g_searchStrength = 8; /* control skip over incompressible data */
69
+
70
+
71
+ /*-*************************************
72
+ * Helper functions
73
+ ***************************************/
74
+ size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
75
+
76
+ static U32 ZSTD_highbit32(U32 val)
77
+ {
78
+ # if defined(_MSC_VER) /* Visual */
79
+ unsigned long r=0;
80
+ _BitScanReverse(&r, val);
81
+ return (unsigned)r;
82
+ # elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
83
+ return 31 - __builtin_clz(val);
84
+ # else /* Software version */
85
+ static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
86
+ U32 v = val;
87
+ int r;
88
+ v |= v >> 1;
89
+ v |= v >> 2;
90
+ v |= v >> 4;
91
+ v |= v >> 8;
92
+ v |= v >> 16;
93
+ r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
94
+ return r;
95
+ # endif
96
+ }
97
+
98
+ /*-*************************************
99
+ * Sequence storage
100
+ ***************************************/
101
+ static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
102
+ {
103
+ ssPtr->offset = ssPtr->offsetStart;
104
+ ssPtr->lit = ssPtr->litStart;
105
+ ssPtr->litLength = ssPtr->litLengthStart;
106
+ ssPtr->matchLength = ssPtr->matchLengthStart;
107
+ ssPtr->longLengthID = 0;
108
+ }
109
+
110
+
111
+ /*-*************************************
112
+ * Context memory management
113
+ ***************************************/
114
+ struct ZSTD_CCtx_s
115
+ {
116
+ const BYTE* nextSrc; /* next block here to continue on current prefix */
117
+ const BYTE* base; /* All regular indexes relative to this position */
118
+ const BYTE* dictBase; /* extDict indexes relative to this position */
119
+ U32 dictLimit; /* below that point, need extDict */
120
+ U32 lowLimit; /* below that point, no more data */
121
+ U32 nextToUpdate; /* index from which to continue dictionary update */
122
+ U32 nextToUpdate3; /* index from which to continue dictionary update */
123
+ U32 hashLog3; /* dispatch table : larger == faster, more memory */
124
+ U32 loadedDictEnd;
125
+ U32 stage; /* 0: created; 1: init,dictLoad; 2:started */
126
+ U32 rep[ZSTD_REP_NUM];
127
+ U32 savedRep[ZSTD_REP_NUM];
128
+ U32 dictID;
129
+ ZSTD_parameters params;
130
+ void* workSpace;
131
+ size_t workSpaceSize;
132
+ size_t blockSize;
133
+ U64 frameContentSize;
134
+ XXH64_state_t xxhState;
135
+ ZSTD_customMem customMem;
136
+
137
+ seqStore_t seqStore; /* sequences storage ptrs */
138
+ U32* hashTable;
139
+ U32* hashTable3;
140
+ U32* chainTable;
141
+ HUF_CElt* hufTable;
142
+ U32 flagStaticTables;
143
+ FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
144
+ FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
145
+ FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
146
+ };
147
+
148
+ ZSTD_CCtx* ZSTD_createCCtx(void)
149
+ {
150
+ return ZSTD_createCCtx_advanced(defaultCustomMem);
151
+ }
152
+
153
+ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
154
+ {
155
+ ZSTD_CCtx* cctx;
156
+
157
+ if (!customMem.customAlloc && !customMem.customFree)
158
+ customMem = defaultCustomMem;
159
+
160
+ if (!customMem.customAlloc || !customMem.customFree)
161
+ return NULL;
162
+
163
+ cctx = (ZSTD_CCtx*) customMem.customAlloc(customMem.opaque, sizeof(ZSTD_CCtx));
164
+ if (!cctx) return NULL;
165
+ memset(cctx, 0, sizeof(ZSTD_CCtx));
166
+ memcpy(&(cctx->customMem), &customMem, sizeof(ZSTD_customMem));
167
+ return cctx;
168
+ }
169
+
170
+ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
171
+ {
172
+ if (cctx==NULL) return 0; /* support free on NULL */
173
+ if (cctx->workSpace) cctx->customMem.customFree(cctx->customMem.opaque, cctx->workSpace);
174
+ cctx->customMem.customFree(cctx->customMem.opaque, cctx);
175
+ return 0; /* reserved as a potential error code in the future */
176
+ }
177
+
178
+ size_t ZSTD_sizeofCCtx(const ZSTD_CCtx* cctx)
179
+ {
180
+ return sizeof(*cctx) + cctx->workSpaceSize;
181
+ }
182
+
183
+ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
184
+ {
185
+ return &(ctx->seqStore);
186
+ }
187
+
188
+
189
+ #define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
190
+ #define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
191
+
192
+ /** ZSTD_checkParams() :
193
+ ensure param values remain within authorized range.
194
+ @return : 0, or an error code if one value is beyond authorized range */
195
+ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
196
+ {
197
+ CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
198
+ CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
199
+ CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
200
+ CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
201
+ { U32 const searchLengthMin = (cParams.strategy == ZSTD_fast || cParams.strategy == ZSTD_greedy) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
202
+ U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
203
+ CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
204
+ CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
205
+ if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
206
+ return 0;
207
+ }
208
+
209
+
210
+ /** ZSTD_checkCParams_advanced() :
211
+ temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
212
+ size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
213
+ {
214
+ if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
215
+ if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
216
+ if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
217
+ if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
218
+ if ((srcSize <= (1ULL << cParams.hashLog)) && ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */
219
+ return ZSTD_checkCParams(cParams);
220
+ }
221
+
222
+
223
+ /** ZSTD_adjustCParams() :
224
+ optimize cPar for a given input (`srcSize` and `dictSize`).
225
+ mostly downsizing to reduce memory consumption and initialization.
226
+ Both `srcSize` and `dictSize` are optional (use 0 if unknown),
227
+ but if both are 0, no optimization can be done.
228
+ Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
229
+ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
230
+ {
231
+ if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
232
+
233
+ /* resize params, to use less memory when necessary */
234
+ { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
235
+ U64 const rSize = srcSize + dictSize + minSrcSize;
236
+ if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
237
+ U32 const srcLog = ZSTD_highbit32((U32)(rSize)-1) + 1;
238
+ if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
239
+ } }
240
+ if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
241
+ { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) || (cPar.strategy == ZSTD_btopt);
242
+ U32 const maxChainLog = cPar.windowLog+btPlus;
243
+ if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
244
+
245
+ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
246
+ if ((cPar.hashLog < ZSTD_HASHLOG_MIN) && ( (U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
247
+
248
+ return cPar;
249
+ }
250
+
251
+
252
+ size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
253
+ {
254
+ const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
255
+ const U32 divider = (cParams.searchLength==3) ? 3 : 4;
256
+ const size_t maxNbSeq = blockSize / divider;
257
+ const size_t tokenSpace = blockSize + 11*maxNbSeq;
258
+
259
+ const size_t chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
260
+ const size_t hSize = ((size_t)1) << cParams.hashLog;
261
+ const U32 hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
262
+ const size_t h3Size = ((size_t)1) << hashLog3;
263
+ const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
264
+
265
+ size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
266
+ + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
267
+ size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
268
+ + ((cParams.strategy == ZSTD_btopt) ? optSpace : 0);
269
+
270
+ return sizeof(ZSTD_CCtx) + neededSpace;
271
+ }
272
+
273
+ /*! ZSTD_resetCCtx_advanced() :
274
+ note : 'params' is expected to be validated */
275
+ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
276
+ ZSTD_parameters params, U64 frameContentSize,
277
+ U32 reset)
278
+ { /* note : params considered validated here */
279
+ const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
280
+ const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
281
+ const size_t maxNbSeq = blockSize / divider;
282
+ const size_t tokenSpace = blockSize + 11*maxNbSeq;
283
+ const size_t chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
284
+ const size_t hSize = ((size_t)1) << params.cParams.hashLog;
285
+ const U32 hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
286
+ const size_t h3Size = ((size_t)1) << hashLog3;
287
+ const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
288
+
289
+ /* Check if workSpace is large enough, alloc a new one if needed */
290
+ { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
291
+ + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
292
+ size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
293
+ + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
294
+ if (zc->workSpaceSize < neededSpace) {
295
+ zc->customMem.customFree(zc->customMem.opaque, zc->workSpace);
296
+ zc->workSpace = zc->customMem.customAlloc(zc->customMem.opaque, neededSpace);
297
+ if (zc->workSpace == NULL) return ERROR(memory_allocation);
298
+ zc->workSpaceSize = neededSpace;
299
+ } }
300
+
301
+ if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
302
+ XXH64_reset(&zc->xxhState, 0);
303
+ zc->hashLog3 = hashLog3;
304
+ zc->hashTable = (U32*)(zc->workSpace);
305
+ zc->chainTable = zc->hashTable + hSize;
306
+ zc->hashTable3 = zc->chainTable + chainSize;
307
+ zc->seqStore.buffer = zc->hashTable3 + h3Size;
308
+ zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
309
+ zc->flagStaticTables = 0;
310
+ zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
311
+
312
+ zc->nextToUpdate = 1;
313
+ zc->nextSrc = NULL;
314
+ zc->base = NULL;
315
+ zc->dictBase = NULL;
316
+ zc->dictLimit = 0;
317
+ zc->lowLimit = 0;
318
+ zc->params = params;
319
+ zc->blockSize = blockSize;
320
+ zc->frameContentSize = frameContentSize;
321
+ { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
322
+
323
+ if (params.cParams.strategy == ZSTD_btopt) {
324
+ zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
325
+ zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
326
+ zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
327
+ zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
328
+ zc->seqStore.buffer = zc->seqStore.offCodeFreq + (MaxOff+1);
329
+ zc->seqStore.matchTable = (ZSTD_match_t*)zc->seqStore.buffer;
330
+ zc->seqStore.buffer = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
331
+ zc->seqStore.priceTable = (ZSTD_optimal_t*)zc->seqStore.buffer;
332
+ zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
333
+ zc->seqStore.litLengthSum = 0;
334
+ }
335
+ zc->seqStore.offsetStart = (U32*)(zc->seqStore.buffer);
336
+ zc->seqStore.buffer = zc->seqStore.offsetStart + maxNbSeq;
337
+ zc->seqStore.litLengthStart = (U16*)zc->seqStore.buffer;
338
+ zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + maxNbSeq;
339
+ zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
340
+ zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
341
+ zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
342
+ zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
343
+
344
+ zc->stage = 1;
345
+ zc->dictID = 0;
346
+ zc->loadedDictEnd = 0;
347
+
348
+ return 0;
349
+ }
350
+
351
+
352
+ /*! ZSTD_copyCCtx() :
353
+ * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
354
+ * Only works during stage 1 (i.e. after creation, but before first call to ZSTD_compressContinue()).
355
+ * @return : 0, or an error code */
356
+ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
357
+ {
358
+ if (srcCCtx->stage!=1) return ERROR(stage_wrong);
359
+
360
+ memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
361
+ ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, 0);
362
+ dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
363
+
364
+ /* copy tables */
365
+ { const size_t chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
366
+ const size_t hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
367
+ const size_t h3Size = (size_t)1 << srcCCtx->hashLog3;
368
+ const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
369
+ memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
370
+ }
371
+
372
+ /* copy dictionary offsets */
373
+ dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
374
+ dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
375
+ dstCCtx->nextSrc = srcCCtx->nextSrc;
376
+ dstCCtx->base = srcCCtx->base;
377
+ dstCCtx->dictBase = srcCCtx->dictBase;
378
+ dstCCtx->dictLimit = srcCCtx->dictLimit;
379
+ dstCCtx->lowLimit = srcCCtx->lowLimit;
380
+ dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
381
+ dstCCtx->dictID = srcCCtx->dictID;
382
+
383
+ /* copy entropy tables */
384
+ dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
385
+ if (srcCCtx->flagStaticTables) {
386
+ memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
387
+ memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
388
+ memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
389
+ memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
390
+ }
391
+
392
+ return 0;
393
+ }
394
+
395
+
396
+ /*! ZSTD_reduceTable() :
397
+ * reduce table indexes by `reducerValue` */
398
+ static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
399
+ {
400
+ U32 u;
401
+ for (u=0 ; u < size ; u++) {
402
+ if (table[u] < reducerValue) table[u] = 0;
403
+ else table[u] -= reducerValue;
404
+ }
405
+ }
406
+
407
+ /*! ZSTD_reduceIndex() :
408
+ * rescale all indexes to avoid future overflow (indexes are U32) */
409
+ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
410
+ {
411
+ { const U32 hSize = 1 << zc->params.cParams.hashLog;
412
+ ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
413
+
414
+ { const U32 chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
415
+ ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
416
+
417
+ { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
418
+ ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
419
+ }
420
+
421
+
422
+ /*-*******************************************************
423
+ * Block entropic compression
424
+ *********************************************************/
425
+
426
+ /* Frame format description
427
+ Frame Header - [ Block Header - Block ] - Frame End
428
+ 1) Frame Header
429
+ - 4 bytes : Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
430
+ - 1 byte : Frame Header Descriptor
431
+ - 1-13 bytes : Optional fields
432
+ 2) Block Header
433
+ - 3 bytes, starting with a 2-bits descriptor
434
+ Uncompressed, Compressed, Frame End, unused
435
+ 3) Block
436
+ See Block Format Description
437
+ 4) Frame End
438
+ - 3 bytes, compatible with Block Header
439
+ */
440
+
441
+
442
+ /* Frame header :
443
+
444
+ 1 byte - FrameHeaderDescription :
445
+ bit 0-1 : dictID (0, 1, 2 or 4 bytes)
446
+ bit 2-4 : reserved (must be zero)
447
+ bit 5 : SkippedWindowLog (if 1, WindowLog byte is not present)
448
+ bit 6-7 : FrameContentFieldsize (0, 2, 4, or 8)
449
+ if (SkippedWindowLog && !FrameContentFieldsize) FrameContentFieldsize=1;
450
+
451
+ Optional : WindowLog (0 or 1 byte)
452
+ bit 0-2 : octal Fractional (1/8th)
453
+ bit 3-7 : Power of 2, with 0 = 1 KB (up to 2 TB)
454
+
455
+ Optional : content size (0, 1, 2, 4 or 8 bytes)
456
+ 0 : unknown
457
+ 1 : 0-255 bytes
458
+ 2 : 256 - 65535+256
459
+ 8 : up to 16 exa
460
+
461
+ Optional : dictID (0, 1, 2 or 4 bytes)
462
+ Automatic adaptation
463
+ 0 : no dictID
464
+ 1 : 1 - 255
465
+ 2 : 256 - 65535
466
+ 4 : all other values
467
+ */
468
+
469
+
470
+ /* Block format description
471
+
472
+ Block = Literals Section - Sequences Section
473
+ Prerequisite : size of (compressed) block, maximum size of regenerated data
474
+
475
+ 1) Literal Section
476
+
477
+ 1.1) Header : 1-5 bytes
478
+ flags: 2 bits
479
+ 00 compressed by Huff0
480
+ 01 repeat
481
+ 10 is Raw (uncompressed)
482
+ 11 is Rle
483
+ Note : using 01 => Huff0 with precomputed table ?
484
+ Note : delta map ? => compressed ?
485
+
486
+ 1.1.1) Huff0-compressed literal block : 3-5 bytes
487
+ srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
488
+ srcSize < 1 KB => 3 bytes (2-2-10-10)
489
+ srcSize < 16KB => 4 bytes (2-2-14-14)
490
+ else => 5 bytes (2-2-18-18)
491
+ big endian convention
492
+
493
+ 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
494
+ size : 5 bits: (IS_RAW<<6) + (0<<4) + size
495
+ 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
496
+ size&255
497
+ 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
498
+ size>>8&255
499
+ size&255
500
+
501
+ 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
502
+ size : 5 bits: (IS_RLE<<6) + (0<<4) + size
503
+ 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
504
+ size&255
505
+ 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
506
+ size>>8&255
507
+ size&255
508
+
509
+ 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
510
+ srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
511
+ srcSize < 1 KB => 3 bytes (2-2-10-10)
512
+ srcSize < 16KB => 4 bytes (2-2-14-14)
513
+ else => 5 bytes (2-2-18-18)
514
+ big endian convention
515
+
516
+ 1- CTable available (stored into workspace)
517
+ 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
518
+
519
+
520
+ 1.2) Literal block content
521
+
522
+ 1.2.1) Huff0 block, using sizes from header
523
+ See Huff0 format
524
+
525
+ 1.2.2) Huff0 block, using prepared table
526
+
527
+ 1.2.3) Raw content
528
+
529
+ 1.2.4) single byte
530
+
531
+
532
+ 2) Sequences section
533
+
534
+ - Nb Sequences : 2 bytes, little endian
535
+ - Control Token : 1 byte (see below)
536
+ - Dumps Length : 1 or 2 bytes (depending on control token)
537
+ - Dumps : as stated by dumps length
538
+ - Literal Lengths FSE table (as needed depending on encoding method)
539
+ - Offset Codes FSE table (as needed depending on encoding method)
540
+ - Match Lengths FSE table (as needed depending on encoding method)
541
+
542
+ 2.1) Control Token
543
+ 8 bits, divided as :
544
+ 0-1 : dumpsLength
545
+ 2-3 : MatchLength, FSE encoding method
546
+ 4-5 : Offset Codes, FSE encoding method
547
+ 6-7 : Literal Lengths, FSE encoding method
548
+
549
+ FSE encoding method :
550
+ FSE_ENCODING_RAW : uncompressed; no header
551
+ FSE_ENCODING_RLE : single repeated value; header 1 byte
552
+ FSE_ENCODING_STATIC : use prepared table; no header
553
+ FSE_ENCODING_DYNAMIC : read NCount
554
+ */
555
+
556
+ size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
557
+ {
558
+ BYTE* const ostart = (BYTE* const)dst;
559
+
560
+ if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
561
+ memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
562
+
563
+ /* Build header */
564
+ ostart[0] = (BYTE)(srcSize>>16);
565
+ ostart[1] = (BYTE)(srcSize>>8);
566
+ ostart[2] = (BYTE) srcSize;
567
+ ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
568
+
569
+ return ZSTD_blockHeaderSize+srcSize;
570
+ }
571
+
572
+
573
+ static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
574
+ {
575
+ BYTE* const ostart = (BYTE* const)dst;
576
+ U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
577
+
578
+ if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
579
+
580
+ switch(flSize)
581
+ {
582
+ case 1: /* 2 - 1 - 5 */
583
+ ostart[0] = (BYTE)((lbt_raw<<6) + (0<<5) + srcSize);
584
+ break;
585
+ case 2: /* 2 - 2 - 12 */
586
+ ostart[0] = (BYTE)((lbt_raw<<6) + (2<<4) + (srcSize >> 8));
587
+ ostart[1] = (BYTE)srcSize;
588
+ break;
589
+ default: /*note : should not be necessary : flSize is within {1,2,3} */
590
+ case 3: /* 2 - 2 - 20 */
591
+ ostart[0] = (BYTE)((lbt_raw<<6) + (3<<4) + (srcSize >> 16));
592
+ ostart[1] = (BYTE)(srcSize>>8);
593
+ ostart[2] = (BYTE)srcSize;
594
+ break;
595
+ }
596
+
597
+ memcpy(ostart + flSize, src, srcSize);
598
+ return srcSize + flSize;
599
+ }
600
+
601
+ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
602
+ {
603
+ BYTE* const ostart = (BYTE* const)dst;
604
+ U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
605
+
606
+ (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
607
+
608
+ switch(flSize)
609
+ {
610
+ case 1: /* 2 - 1 - 5 */
611
+ ostart[0] = (BYTE)((lbt_rle<<6) + (0<<5) + srcSize);
612
+ break;
613
+ case 2: /* 2 - 2 - 12 */
614
+ ostart[0] = (BYTE)((lbt_rle<<6) + (2<<4) + (srcSize >> 8));
615
+ ostart[1] = (BYTE)srcSize;
616
+ break;
617
+ default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
618
+ case 3: /* 2 - 2 - 20 */
619
+ ostart[0] = (BYTE)((lbt_rle<<6) + (3<<4) + (srcSize >> 16));
620
+ ostart[1] = (BYTE)(srcSize>>8);
621
+ ostart[2] = (BYTE)srcSize;
622
+ break;
623
+ }
624
+
625
+ ostart[flSize] = *(const BYTE*)src;
626
+ return flSize+1;
627
+ }
628
+
629
+
630
+ static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
631
+
632
+ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
633
+ void* dst, size_t dstCapacity,
634
+ const void* src, size_t srcSize)
635
+ {
636
+ size_t const minGain = ZSTD_minGain(srcSize);
637
+ size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
638
+ BYTE* const ostart = (BYTE*)dst;
639
+ U32 singleStream = srcSize < 256;
640
+ litBlockType_t hType = lbt_huffman;
641
+ size_t cLitSize;
642
+
643
+
644
+ /* small ? don't even attempt compression (speed opt) */
645
+ # define LITERAL_NOENTROPY 63
646
+ { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
647
+ if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
648
+ }
649
+
650
+ if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
651
+ if (zc->flagStaticTables && (lhSize==3)) {
652
+ hType = lbt_repeat;
653
+ singleStream = 1;
654
+ cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
655
+ } else {
656
+ cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11)
657
+ : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11);
658
+ }
659
+
660
+ if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
661
+ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
662
+ if (cLitSize==1)
663
+ return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
664
+
665
+ /* Build header */
666
+ switch(lhSize)
667
+ {
668
+ case 3: /* 2 - 2 - 10 - 10 */
669
+ ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
670
+ ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
671
+ ostart[2] = (BYTE)(cLitSize);
672
+ break;
673
+ case 4: /* 2 - 2 - 14 - 14 */
674
+ ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
675
+ ostart[1] = (BYTE)(srcSize>> 2);
676
+ ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
677
+ ostart[3] = (BYTE)(cLitSize);
678
+ break;
679
+ default: /* should not be necessary, lhSize is only {3,4,5} */
680
+ case 5: /* 2 - 2 - 18 - 18 */
681
+ ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
682
+ ostart[1] = (BYTE)(srcSize>>6);
683
+ ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
684
+ ostart[3] = (BYTE)(cLitSize>>8);
685
+ ostart[4] = (BYTE)(cLitSize);
686
+ break;
687
+ }
688
+ return lhSize+cLitSize;
689
+ }
690
+
691
+
692
+ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
693
+ {
694
+ /* LL codes */
695
+ { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
696
+ 8, 9, 10, 11, 12, 13, 14, 15,
697
+ 16, 16, 17, 17, 18, 18, 19, 19,
698
+ 20, 20, 20, 20, 21, 21, 21, 21,
699
+ 22, 22, 22, 22, 22, 22, 22, 22,
700
+ 23, 23, 23, 23, 23, 23, 23, 23,
701
+ 24, 24, 24, 24, 24, 24, 24, 24,
702
+ 24, 24, 24, 24, 24, 24, 24, 24 };
703
+ const BYTE LL_deltaCode = 19;
704
+ const U16* const llTable = seqStorePtr->litLengthStart;
705
+ BYTE* const llCodeTable = seqStorePtr->llCodeStart;
706
+ size_t u;
707
+ for (u=0; u<nbSeq; u++) {
708
+ U32 const ll = llTable[u];
709
+ llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit32(ll) + LL_deltaCode : LL_Code[ll];
710
+ }
711
+ if (seqStorePtr->longLengthID==1)
712
+ llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
713
+ }
714
+
715
+ /* Offset codes */
716
+ { const U32* const offsetTable = seqStorePtr->offsetStart;
717
+ BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
718
+ size_t u;
719
+ for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit32(offsetTable[u]);
720
+ }
721
+
722
+ /* ML codes */
723
+ { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
724
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
725
+ 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
726
+ 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
727
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
728
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
729
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
730
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
731
+ const BYTE ML_deltaCode = 36;
732
+ const U16* const mlTable = seqStorePtr->matchLengthStart;
733
+ BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
734
+ size_t u;
735
+ for (u=0; u<nbSeq; u++) {
736
+ U32 const ml = mlTable[u];
737
+ mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit32(ml) + ML_deltaCode : ML_Code[ml];
738
+ }
739
+ if (seqStorePtr->longLengthID==2)
740
+ mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
741
+ }
742
+ }
743
+
744
+
745
+ size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
746
+ void* dst, size_t dstCapacity,
747
+ size_t srcSize)
748
+ {
749
+ const seqStore_t* seqStorePtr = &(zc->seqStore);
750
+ U32 count[MaxSeq+1];
751
+ S16 norm[MaxSeq+1];
752
+ FSE_CTable* CTable_LitLength = zc->litlengthCTable;
753
+ FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
754
+ FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
755
+ U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
756
+ U16* const llTable = seqStorePtr->litLengthStart;
757
+ U16* const mlTable = seqStorePtr->matchLengthStart;
758
+ const U32* const offsetTable = seqStorePtr->offsetStart;
759
+ const U32* const offsetTableEnd = seqStorePtr->offset;
760
+ BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
761
+ BYTE* const llCodeTable = seqStorePtr->llCodeStart;
762
+ BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
763
+ BYTE* const ostart = (BYTE*)dst;
764
+ BYTE* const oend = ostart + dstCapacity;
765
+ BYTE* op = ostart;
766
+ size_t const nbSeq = offsetTableEnd - offsetTable;
767
+ BYTE* seqHead;
768
+
769
+ /* Compress literals */
770
+ { const BYTE* const literals = seqStorePtr->litStart;
771
+ size_t const litSize = seqStorePtr->lit - literals;
772
+ size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
773
+ if (ZSTD_isError(cSize)) return cSize;
774
+ op += cSize;
775
+ }
776
+
777
+ /* Sequences Header */
778
+ if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
779
+ if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
780
+ else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
781
+ else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
782
+ if (nbSeq==0) goto _check_compressibility;
783
+
784
+ /* seqHead : flags for FSE encoding type */
785
+ seqHead = op++;
786
+
787
+ #define MIN_SEQ_FOR_DYNAMIC_FSE 64
788
+ #define MAX_SEQ_FOR_STATIC_FSE 1000
789
+
790
+ /* convert length/distances into codes */
791
+ ZSTD_seqToCodes(seqStorePtr, nbSeq);
792
+
793
+ /* CTable for Literal Lengths */
794
+ { U32 max = MaxLL;
795
+ size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
796
+ if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
797
+ *op++ = llCodeTable[0];
798
+ FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
799
+ LLtype = FSE_ENCODING_RLE;
800
+ } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
801
+ LLtype = FSE_ENCODING_STATIC;
802
+ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
803
+ FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
804
+ LLtype = FSE_ENCODING_RAW;
805
+ } else {
806
+ size_t nbSeq_1 = nbSeq;
807
+ const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
808
+ if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
809
+ FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
810
+ { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
811
+ if (FSE_isError(NCountSize)) return ERROR(GENERIC);
812
+ op += NCountSize; }
813
+ FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
814
+ LLtype = FSE_ENCODING_DYNAMIC;
815
+ } }
816
+
817
+ /* CTable for Offsets */
818
+ { U32 max = MaxOff;
819
+ size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
820
+ if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
821
+ *op++ = ofCodeTable[0];
822
+ FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
823
+ Offtype = FSE_ENCODING_RLE;
824
+ } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
825
+ Offtype = FSE_ENCODING_STATIC;
826
+ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
827
+ FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
828
+ Offtype = FSE_ENCODING_RAW;
829
+ } else {
830
+ size_t nbSeq_1 = nbSeq;
831
+ const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
832
+ if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
833
+ FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
834
+ { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
835
+ if (FSE_isError(NCountSize)) return ERROR(GENERIC);
836
+ op += NCountSize; }
837
+ FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
838
+ Offtype = FSE_ENCODING_DYNAMIC;
839
+ } }
840
+
841
+ /* CTable for MatchLengths */
842
+ { U32 max = MaxML;
843
+ size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
844
+ if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
845
+ *op++ = *mlCodeTable;
846
+ FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
847
+ MLtype = FSE_ENCODING_RLE;
848
+ } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
849
+ MLtype = FSE_ENCODING_STATIC;
850
+ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
851
+ FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
852
+ MLtype = FSE_ENCODING_RAW;
853
+ } else {
854
+ size_t nbSeq_1 = nbSeq;
855
+ const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
856
+ if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
857
+ FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
858
+ { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
859
+ if (FSE_isError(NCountSize)) return ERROR(GENERIC);
860
+ op += NCountSize; }
861
+ FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
862
+ MLtype = FSE_ENCODING_DYNAMIC;
863
+ } }
864
+
865
+ *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
866
+ zc->flagStaticTables = 0;
867
+
868
+ /* Encoding Sequences */
869
+ { BIT_CStream_t blockStream;
870
+ FSE_CState_t stateMatchLength;
871
+ FSE_CState_t stateOffsetBits;
872
+ FSE_CState_t stateLitLength;
873
+
874
+ { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
875
+ if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
876
+
877
+ /* first symbols */
878
+ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
879
+ FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
880
+ FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
881
+ BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
882
+ if (MEM_32bits()) BIT_flushBits(&blockStream);
883
+ BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
884
+ if (MEM_32bits()) BIT_flushBits(&blockStream);
885
+ BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
886
+ BIT_flushBits(&blockStream);
887
+
888
+ { size_t n;
889
+ for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
890
+ const BYTE ofCode = ofCodeTable[n];
891
+ const BYTE mlCode = mlCodeTable[n];
892
+ const BYTE llCode = llCodeTable[n];
893
+ const U32 llBits = LL_bits[llCode];
894
+ const U32 mlBits = ML_bits[mlCode];
895
+ const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
896
+ /* (7)*/ /* (7)*/
897
+ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
898
+ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
899
+ if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
900
+ FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
901
+ if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
902
+ BIT_flushBits(&blockStream); /* (7)*/
903
+ BIT_addBits(&blockStream, llTable[n], llBits);
904
+ if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
905
+ BIT_addBits(&blockStream, mlTable[n], mlBits);
906
+ if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
907
+ BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
908
+ BIT_flushBits(&blockStream); /* (7)*/
909
+ } }
910
+
911
+ FSE_flushCState(&blockStream, &stateMatchLength);
912
+ FSE_flushCState(&blockStream, &stateOffsetBits);
913
+ FSE_flushCState(&blockStream, &stateLitLength);
914
+
915
+ { size_t const streamSize = BIT_closeCStream(&blockStream);
916
+ if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
917
+ op += streamSize;
918
+ } }
919
+
920
+ /* check compressibility */
921
+ _check_compressibility:
922
+ { size_t const minGain = ZSTD_minGain(srcSize);
923
+ size_t const maxCSize = srcSize - minGain;
924
+ if ((size_t)(op-ostart) >= maxCSize) return 0; }
925
+
926
+ /* confirm repcodes */
927
+ { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }
928
+
929
+ return op - ostart;
930
+ }
931
+
932
+
933
+ /*! ZSTD_storeSeq() :
934
+ Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
935
+ `offsetCode` : distance to match, or 0 == repCode.
936
+ `matchCode` : matchLength - MINMATCH
937
+ */
938
+ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
939
+ {
940
+ #if 0 /* for debug */
941
+ static const BYTE* g_start = NULL;
942
+ const U32 pos = (U32)(literals - g_start);
943
+ if (g_start==NULL) g_start = literals;
944
+ //if ((pos > 1) && (pos < 50000))
945
+ printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
946
+ pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
947
+ #endif
948
+ ZSTD_statsUpdatePrices(&seqStorePtr->stats, litLength, (const BYTE*)literals, offsetCode, matchCode); /* debug only */
949
+
950
+ /* copy Literals */
951
+ ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
952
+ seqStorePtr->lit += litLength;
953
+
954
+ /* literal Length */
955
+ if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->litLength - seqStorePtr->litLengthStart); }
956
+ *seqStorePtr->litLength++ = (U16)litLength;
957
+
958
+ /* match offset */
959
+ *(seqStorePtr->offset++) = offsetCode + 1;
960
+
961
+ /* match Length */
962
+ if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->matchLength - seqStorePtr->matchLengthStart); }
963
+ *seqStorePtr->matchLength++ = (U16)matchCode;
964
+ }
965
+
966
+
967
+ /*-*************************************
968
+ * Match length counter
969
+ ***************************************/
970
+ static unsigned ZSTD_NbCommonBytes (register size_t val)
971
+ {
972
+ if (MEM_isLittleEndian()) {
973
+ if (MEM_64bits()) {
974
+ # if defined(_MSC_VER) && defined(_WIN64)
975
+ unsigned long r = 0;
976
+ _BitScanForward64( &r, (U64)val );
977
+ return (unsigned)(r>>3);
978
+ # elif defined(__GNUC__) && (__GNUC__ >= 3)
979
+ return (__builtin_ctzll((U64)val) >> 3);
980
+ # else
981
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
982
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
983
+ # endif
984
+ } else { /* 32 bits */
985
+ # if defined(_MSC_VER)
986
+ unsigned long r=0;
987
+ _BitScanForward( &r, (U32)val );
988
+ return (unsigned)(r>>3);
989
+ # elif defined(__GNUC__) && (__GNUC__ >= 3)
990
+ return (__builtin_ctz((U32)val) >> 3);
991
+ # else
992
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
993
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
994
+ # endif
995
+ }
996
+ } else { /* Big Endian CPU */
997
+ if (MEM_64bits()) {
998
+ # if defined(_MSC_VER) && defined(_WIN64)
999
+ unsigned long r = 0;
1000
+ _BitScanReverse64( &r, val );
1001
+ return (unsigned)(r>>3);
1002
+ # elif defined(__GNUC__) && (__GNUC__ >= 3)
1003
+ return (__builtin_clzll(val) >> 3);
1004
+ # else
1005
+ unsigned r;
1006
+ const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1007
+ if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1008
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1009
+ r += (!val);
1010
+ return r;
1011
+ # endif
1012
+ } else { /* 32 bits */
1013
+ # if defined(_MSC_VER)
1014
+ unsigned long r = 0;
1015
+ _BitScanReverse( &r, (unsigned long)val );
1016
+ return (unsigned)(r>>3);
1017
+ # elif defined(__GNUC__) && (__GNUC__ >= 3)
1018
+ return (__builtin_clz((U32)val) >> 3);
1019
+ # else
1020
+ unsigned r;
1021
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1022
+ r += (!val);
1023
+ return r;
1024
+ # endif
1025
+ } }
1026
+ }
1027
+
1028
+
1029
+ static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
1030
+ {
1031
+ const BYTE* const pStart = pIn;
1032
+ const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
1033
+
1034
+ while (pIn < pInLoopLimit) {
1035
+ size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
1036
+ if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1037
+ pIn += ZSTD_NbCommonBytes(diff);
1038
+ return (size_t)(pIn - pStart);
1039
+ }
1040
+ if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1041
+ if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1042
+ if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1043
+ return (size_t)(pIn - pStart);
1044
+ }
1045
+
1046
+ /** ZSTD_count_2segments() :
1047
+ * can count match length with `ip` & `match` in 2 different segments.
1048
+ * convention : on reaching mEnd, match count continue starting from iStart
1049
+ */
1050
+ static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1051
+ {
1052
+ const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
1053
+ size_t matchLength = ZSTD_count(ip, match, vEnd);
1054
+ if (match + matchLength == mEnd)
1055
+ matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
1056
+ return matchLength;
1057
+ }
1058
+
1059
+
1060
+ /*-*************************************
1061
+ * Hashes
1062
+ ***************************************/
1063
+ static const U32 prime3bytes = 506832829U;
1064
+ static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
1065
+ MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
1066
+
1067
+ static const U32 prime4bytes = 2654435761U;
1068
+ static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
1069
+ static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
1070
+
1071
+ static const U64 prime5bytes = 889523592379ULL;
1072
+ static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
1073
+ static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
1074
+
1075
+ static const U64 prime6bytes = 227718039650203ULL;
1076
+ static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
1077
+ static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
1078
+
1079
+ static const U64 prime7bytes = 58295818150454627ULL;
1080
+ static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
1081
+ static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
1082
+
1083
+ //static const U64 prime8bytes = 58295818150454627ULL;
1084
+ static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1085
+ static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1086
+ static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1087
+
1088
+ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
1089
+ {
1090
+ switch(mls)
1091
+ {
1092
+ default:
1093
+ case 4: return ZSTD_hash4Ptr(p, hBits);
1094
+ case 5: return ZSTD_hash5Ptr(p, hBits);
1095
+ case 6: return ZSTD_hash6Ptr(p, hBits);
1096
+ case 7: return ZSTD_hash7Ptr(p, hBits);
1097
+ case 8: return ZSTD_hash8Ptr(p, hBits);
1098
+ }
1099
+ }
1100
+
1101
+
1102
+ /*-*************************************
1103
+ * Fast Scan
1104
+ ***************************************/
1105
+ static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1106
+ {
1107
+ U32* const hashTable = zc->hashTable;
1108
+ const U32 hBits = zc->params.cParams.hashLog;
1109
+ const BYTE* const base = zc->base;
1110
+ const BYTE* ip = base + zc->nextToUpdate;
1111
+ const BYTE* const iend = ((const BYTE*)end) - 8;
1112
+ const size_t fastHashFillStep = 3;
1113
+
1114
+ while(ip <= iend) {
1115
+ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
1116
+ ip += fastHashFillStep;
1117
+ }
1118
+ }
1119
+
1120
+
1121
+ FORCE_INLINE
1122
+ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
1123
+ const void* src, size_t srcSize,
1124
+ const U32 mls)
1125
+ {
1126
+ U32* const hashTable = cctx->hashTable;
1127
+ const U32 hBits = cctx->params.cParams.hashLog;
1128
+ seqStore_t* seqStorePtr = &(cctx->seqStore);
1129
+ const BYTE* const base = cctx->base;
1130
+ const BYTE* const istart = (const BYTE*)src;
1131
+ const BYTE* ip = istart;
1132
+ const BYTE* anchor = istart;
1133
+ const U32 lowestIndex = cctx->dictLimit;
1134
+ const BYTE* const lowest = base + lowestIndex;
1135
+ const BYTE* const iend = istart + srcSize;
1136
+ const BYTE* const ilimit = iend - 8;
1137
+ U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1138
+ U32 offsetSaved = 0;
1139
+
1140
+ /* init */
1141
+ ip += (ip==lowest);
1142
+ { U32 const maxRep = (U32)(ip-lowest);
1143
+ if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1144
+ if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1145
+ }
1146
+
1147
+ /* Main Search Loop */
1148
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1149
+ size_t mLength;
1150
+ size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1151
+ U32 const current = (U32)(ip-base);
1152
+ U32 const matchIndex = hashTable[h];
1153
+ const BYTE* match = base + matchIndex;
1154
+ hashTable[h] = current; /* update hash table */
1155
+
1156
+ if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1157
+ mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1158
+ ip++;
1159
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1160
+ } else {
1161
+ U32 offset;
1162
+ if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
1163
+ ip += ((ip-anchor) >> g_searchStrength) + 1;
1164
+ continue;
1165
+ }
1166
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1167
+ offset = (U32)(ip-match);
1168
+ while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1169
+ offset_2 = offset_1;
1170
+ offset_1 = offset;
1171
+
1172
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1173
+ }
1174
+
1175
+ /* match found */
1176
+ ip += mLength;
1177
+ anchor = ip;
1178
+
1179
+ if (ip <= ilimit) {
1180
+ /* Fill Table */
1181
+ hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
1182
+ hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1183
+ /* check immediate repcode */
1184
+ while ( (ip <= ilimit)
1185
+ && ( (offset_2>0)
1186
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1187
+ /* store sequence */
1188
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
1189
+ { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
1190
+ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
1191
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1192
+ ip += rLength;
1193
+ anchor = ip;
1194
+ continue; /* faster when present ... (?) */
1195
+ } } }
1196
+
1197
+ /* save reps for next block */
1198
+ cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1199
+ cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
1200
+
1201
+ /* Last Literals */
1202
+ { size_t const lastLLSize = iend - anchor;
1203
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
1204
+ seqStorePtr->lit += lastLLSize;
1205
+ }
1206
+ }
1207
+
1208
+
1209
+ static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
1210
+ const void* src, size_t srcSize)
1211
+ {
1212
+ const U32 mls = ctx->params.cParams.searchLength;
1213
+ switch(mls)
1214
+ {
1215
+ default:
1216
+ case 4 :
1217
+ ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
1218
+ case 5 :
1219
+ ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
1220
+ case 6 :
1221
+ ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
1222
+ case 7 :
1223
+ ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
1224
+ }
1225
+ }
1226
+
1227
+
1228
+ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
1229
+ const void* src, size_t srcSize,
1230
+ const U32 mls)
1231
+ {
1232
+ U32* hashTable = ctx->hashTable;
1233
+ const U32 hBits = ctx->params.cParams.hashLog;
1234
+ seqStore_t* seqStorePtr = &(ctx->seqStore);
1235
+ const BYTE* const base = ctx->base;
1236
+ const BYTE* const dictBase = ctx->dictBase;
1237
+ const BYTE* const istart = (const BYTE*)src;
1238
+ const BYTE* ip = istart;
1239
+ const BYTE* anchor = istart;
1240
+ const U32 lowestIndex = ctx->lowLimit;
1241
+ const BYTE* const dictStart = dictBase + lowestIndex;
1242
+ const U32 dictLimit = ctx->dictLimit;
1243
+ const BYTE* const lowPrefixPtr = base + dictLimit;
1244
+ const BYTE* const dictEnd = dictBase + dictLimit;
1245
+ const BYTE* const iend = istart + srcSize;
1246
+ const BYTE* const ilimit = iend - 8;
1247
+ U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1248
+
1249
+ /* Search Loop */
1250
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1251
+ const size_t h = ZSTD_hashPtr(ip, hBits, mls);
1252
+ const U32 matchIndex = hashTable[h];
1253
+ const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1254
+ const BYTE* match = matchBase + matchIndex;
1255
+ const U32 current = (U32)(ip-base);
1256
+ const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1257
+ const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1258
+ const BYTE* repMatch = repBase + repIndex;
1259
+ size_t mLength;
1260
+ hashTable[h] = current; /* update hash table */
1261
+
1262
+ if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1263
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1264
+ const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1265
+ mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
1266
+ ip++;
1267
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1268
+ } else {
1269
+ if ( (matchIndex < lowestIndex) ||
1270
+ (MEM_read32(match) != MEM_read32(ip)) ) {
1271
+ ip += ((ip-anchor) >> g_searchStrength) + 1;
1272
+ continue;
1273
+ }
1274
+ { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1275
+ const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1276
+ U32 offset;
1277
+ mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1278
+ while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1279
+ offset = current - matchIndex;
1280
+ offset_2 = offset_1;
1281
+ offset_1 = offset;
1282
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1283
+ } }
1284
+
1285
+ /* found a match : store it */
1286
+ ip += mLength;
1287
+ anchor = ip;
1288
+
1289
+ if (ip <= ilimit) {
1290
+ /* Fill Table */
1291
+ hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
1292
+ hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1293
+ /* check immediate repcode */
1294
+ while (ip <= ilimit) {
1295
+ U32 const current2 = (U32)(ip-base);
1296
+ U32 const repIndex2 = current2 - offset_2;
1297
+ const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1298
+ if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1299
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1300
+ const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1301
+ size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1302
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1303
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1304
+ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1305
+ ip += repLength2;
1306
+ anchor = ip;
1307
+ continue;
1308
+ }
1309
+ break;
1310
+ } } }
1311
+
1312
+ /* save reps for next block */
1313
+ ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1314
+
1315
+ /* Last Literals */
1316
+ { size_t const lastLLSize = iend - anchor;
1317
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
1318
+ seqStorePtr->lit += lastLLSize;
1319
+ }
1320
+ }
1321
+
1322
+
1323
+ static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
1324
+ const void* src, size_t srcSize)
1325
+ {
1326
+ const U32 mls = ctx->params.cParams.searchLength;
1327
+ switch(mls)
1328
+ {
1329
+ default:
1330
+ case 4 :
1331
+ ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
1332
+ case 5 :
1333
+ ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
1334
+ case 6 :
1335
+ ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
1336
+ case 7 :
1337
+ ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
1338
+ }
1339
+ }
1340
+
1341
+
1342
+ /*-*************************************
1343
+ * Double Fast
1344
+ ***************************************/
1345
+ static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1346
+ {
1347
+ U32* const hashLarge = cctx->hashTable;
1348
+ const U32 hBitsL = cctx->params.cParams.hashLog;
1349
+ U32* const hashSmall = cctx->chainTable;
1350
+ const U32 hBitsS = cctx->params.cParams.chainLog;
1351
+ const BYTE* const base = cctx->base;
1352
+ const BYTE* ip = base + cctx->nextToUpdate;
1353
+ const BYTE* const iend = ((const BYTE*)end) - 8;
1354
+ const size_t fastHashFillStep = 3;
1355
+
1356
+ while(ip <= iend) {
1357
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1358
+ hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1359
+ ip += fastHashFillStep;
1360
+ }
1361
+ }
1362
+
1363
+
1364
+ FORCE_INLINE
1365
+ void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1366
+ const void* src, size_t srcSize,
1367
+ const U32 mls)
1368
+ {
1369
+ U32* const hashLong = cctx->hashTable;
1370
+ const U32 hBitsL = cctx->params.cParams.hashLog;
1371
+ U32* const hashSmall = cctx->chainTable;
1372
+ const U32 hBitsS = cctx->params.cParams.chainLog;
1373
+ seqStore_t* seqStorePtr = &(cctx->seqStore);
1374
+ const BYTE* const base = cctx->base;
1375
+ const BYTE* const istart = (const BYTE*)src;
1376
+ const BYTE* ip = istart;
1377
+ const BYTE* anchor = istart;
1378
+ const U32 lowestIndex = cctx->dictLimit;
1379
+ const BYTE* const lowest = base + lowestIndex;
1380
+ const BYTE* const iend = istart + srcSize;
1381
+ const BYTE* const ilimit = iend - 8;
1382
+ U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1383
+ U32 offsetSaved = 0;
1384
+
1385
+ /* init */
1386
+ ip += (ip==lowest);
1387
+ { U32 const maxRep = (U32)(ip-lowest);
1388
+ if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1389
+ if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1390
+ }
1391
+
1392
+ /* Main Search Loop */
1393
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1394
+ size_t mLength;
1395
+ size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1396
+ size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1397
+ U32 const current = (U32)(ip-base);
1398
+ U32 const matchIndexL = hashLong[h2];
1399
+ U32 const matchIndexS = hashSmall[h];
1400
+ const BYTE* matchLong = base + matchIndexL;
1401
+ const BYTE* match = base + matchIndexS;
1402
+ hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1403
+
1404
+ if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1405
+ mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1406
+ ip++;
1407
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1408
+ } else {
1409
+ U32 offset;
1410
+ if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1411
+ mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
1412
+ offset = (U32)(ip-matchLong);
1413
+ while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1414
+ } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
1415
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1416
+ offset = (U32)(ip-match);
1417
+ while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1418
+ } else {
1419
+ ip += ((ip-anchor) >> g_searchStrength) + 1;
1420
+ continue;
1421
+ }
1422
+
1423
+ offset_2 = offset_1;
1424
+ offset_1 = offset;
1425
+
1426
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1427
+ }
1428
+
1429
+ /* match found */
1430
+ ip += mLength;
1431
+ anchor = ip;
1432
+
1433
+ if (ip <= ilimit) {
1434
+ /* Fill Table */
1435
+ hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1436
+ hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1437
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1438
+ hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1439
+
1440
+ /* check immediate repcode */
1441
+ while ( (ip <= ilimit)
1442
+ && ( (offset_2>0)
1443
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1444
+ /* store sequence */
1445
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
1446
+ { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
1447
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1448
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1449
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1450
+ ip += rLength;
1451
+ anchor = ip;
1452
+ continue; /* faster when present ... (?) */
1453
+ } } }
1454
+
1455
+ /* save reps for next block */
1456
+ cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1457
+ cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
1458
+
1459
+ /* Last Literals */
1460
+ { size_t const lastLLSize = iend - anchor;
1461
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
1462
+ seqStorePtr->lit += lastLLSize;
1463
+ }
1464
+ }
1465
+
1466
+
1467
+ static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1468
+ {
1469
+ const U32 mls = ctx->params.cParams.searchLength;
1470
+ switch(mls)
1471
+ {
1472
+ default:
1473
+ case 4 :
1474
+ ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1475
+ case 5 :
1476
+ ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1477
+ case 6 :
1478
+ ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1479
+ case 7 :
1480
+ ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1481
+ }
1482
+ }
1483
+
1484
+
1485
+ static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1486
+ const void* src, size_t srcSize,
1487
+ const U32 mls)
1488
+ {
1489
+ U32* const hashLong = ctx->hashTable;
1490
+ const U32 hBitsL = ctx->params.cParams.hashLog;
1491
+ U32* const hashSmall = ctx->chainTable;
1492
+ const U32 hBitsS = ctx->params.cParams.chainLog;
1493
+ seqStore_t* seqStorePtr = &(ctx->seqStore);
1494
+ const BYTE* const base = ctx->base;
1495
+ const BYTE* const dictBase = ctx->dictBase;
1496
+ const BYTE* const istart = (const BYTE*)src;
1497
+ const BYTE* ip = istart;
1498
+ const BYTE* anchor = istart;
1499
+ const U32 lowestIndex = ctx->lowLimit;
1500
+ const BYTE* const dictStart = dictBase + lowestIndex;
1501
+ const U32 dictLimit = ctx->dictLimit;
1502
+ const BYTE* const lowPrefixPtr = base + dictLimit;
1503
+ const BYTE* const dictEnd = dictBase + dictLimit;
1504
+ const BYTE* const iend = istart + srcSize;
1505
+ const BYTE* const ilimit = iend - 8;
1506
+ U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1507
+
1508
+ /* Search Loop */
1509
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1510
+ const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1511
+ const U32 matchIndex = hashSmall[hSmall];
1512
+ const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1513
+ const BYTE* match = matchBase + matchIndex;
1514
+
1515
+ const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1516
+ const U32 matchLongIndex = hashLong[hLong];
1517
+ const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1518
+ const BYTE* matchLong = matchLongBase + matchLongIndex;
1519
+
1520
+ const U32 current = (U32)(ip-base);
1521
+ const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1522
+ const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1523
+ const BYTE* repMatch = repBase + repIndex;
1524
+ size_t mLength;
1525
+ hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1526
+
1527
+ if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1528
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1529
+ const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1530
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1531
+ ip++;
1532
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1533
+ } else {
1534
+ if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1535
+ const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1536
+ const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1537
+ U32 offset;
1538
+ mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1539
+ offset = current - matchLongIndex;
1540
+ while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1541
+ offset_2 = offset_1;
1542
+ offset_1 = offset;
1543
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1544
+ } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
1545
+ const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1546
+ const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1547
+ U32 offset;
1548
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1549
+ while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1550
+ offset = current - matchIndex;
1551
+ offset_2 = offset_1;
1552
+ offset_1 = offset;
1553
+ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1554
+ } else {
1555
+ ip += ((ip-anchor) >> g_searchStrength) + 1;
1556
+ continue;
1557
+ } }
1558
+
1559
+ /* found a match : store it */
1560
+ ip += mLength;
1561
+ anchor = ip;
1562
+
1563
+ if (ip <= ilimit) {
1564
+ /* Fill Table */
1565
+ hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1566
+ hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1567
+ hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1568
+ hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1569
+ /* check immediate repcode */
1570
+ while (ip <= ilimit) {
1571
+ U32 const current2 = (U32)(ip-base);
1572
+ U32 const repIndex2 = current2 - offset_2;
1573
+ const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1574
+ if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1575
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1576
+ const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1577
+ size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1578
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1579
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1580
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1581
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1582
+ ip += repLength2;
1583
+ anchor = ip;
1584
+ continue;
1585
+ }
1586
+ break;
1587
+ } } }
1588
+
1589
+ /* save reps for next block */
1590
+ ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1591
+
1592
+ /* Last Literals */
1593
+ { size_t const lastLLSize = iend - anchor;
1594
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
1595
+ seqStorePtr->lit += lastLLSize;
1596
+ }
1597
+ }
1598
+
1599
+
1600
+ static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1601
+ const void* src, size_t srcSize)
1602
+ {
1603
+ const U32 mls = ctx->params.cParams.searchLength;
1604
+ switch(mls)
1605
+ {
1606
+ default:
1607
+ case 4 :
1608
+ ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1609
+ case 5 :
1610
+ ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1611
+ case 6 :
1612
+ ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1613
+ case 7 :
1614
+ ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1615
+ }
1616
+ }
1617
+
1618
+
1619
+ /*-*************************************
1620
+ * Binary Tree search
1621
+ ***************************************/
1622
+ /** ZSTD_insertBt1() : add one or multiple positions to tree.
1623
+ * ip : assumed <= iend-8 .
1624
+ * @return : nb of positions added */
1625
+ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1626
+ U32 extDict)
1627
+ {
1628
+ U32* const hashTable = zc->hashTable;
1629
+ const U32 hashLog = zc->params.cParams.hashLog;
1630
+ const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1631
+ U32* const bt = zc->chainTable;
1632
+ const U32 btLog = zc->params.cParams.chainLog - 1;
1633
+ const U32 btMask= (1 << btLog) - 1;
1634
+ U32 matchIndex = hashTable[h];
1635
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
1636
+ const BYTE* const base = zc->base;
1637
+ const BYTE* const dictBase = zc->dictBase;
1638
+ const U32 dictLimit = zc->dictLimit;
1639
+ const BYTE* const dictEnd = dictBase + dictLimit;
1640
+ const BYTE* const prefixStart = base + dictLimit;
1641
+ const BYTE* match = base + matchIndex;
1642
+ const U32 current = (U32)(ip-base);
1643
+ const U32 btLow = btMask >= current ? 0 : current - btMask;
1644
+ U32* smallerPtr = bt + 2*(current&btMask);
1645
+ U32* largerPtr = smallerPtr + 1;
1646
+ U32 dummy32; /* to be nullified at the end */
1647
+ const U32 windowLow = zc->lowLimit;
1648
+ U32 matchEndIdx = current+8;
1649
+ size_t bestLength = 8;
1650
+ #ifdef ZSTD_C_PREDICT
1651
+ U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1652
+ U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1653
+ predictedSmall += (predictedSmall>0);
1654
+ predictedLarge += (predictedLarge>0);
1655
+ #endif /* ZSTD_C_PREDICT */
1656
+
1657
+ hashTable[h] = current; /* Update Hash Table */
1658
+
1659
+ while (nbCompares-- && (matchIndex > windowLow)) {
1660
+ U32* nextPtr = bt + 2*(matchIndex & btMask);
1661
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1662
+ #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
1663
+ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
1664
+ if (matchIndex == predictedSmall) {
1665
+ /* no need to check length, result known */
1666
+ *smallerPtr = matchIndex;
1667
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1668
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1669
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1670
+ predictedSmall = predictPtr[1] + (predictPtr[1]>0);
1671
+ continue;
1672
+ }
1673
+ if (matchIndex == predictedLarge) {
1674
+ *largerPtr = matchIndex;
1675
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1676
+ largerPtr = nextPtr;
1677
+ matchIndex = nextPtr[0];
1678
+ predictedLarge = predictPtr[0] + (predictPtr[0]>0);
1679
+ continue;
1680
+ }
1681
+ #endif
1682
+ if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
1683
+ match = base + matchIndex;
1684
+ if (match[matchLength] == ip[matchLength])
1685
+ matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1686
+ } else {
1687
+ match = dictBase + matchIndex;
1688
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1689
+ if (matchIndex+matchLength >= dictLimit)
1690
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1691
+ }
1692
+
1693
+ if (matchLength > bestLength) {
1694
+ bestLength = matchLength;
1695
+ if (matchLength > matchEndIdx - matchIndex)
1696
+ matchEndIdx = matchIndex + (U32)matchLength;
1697
+ }
1698
+
1699
+ if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1700
+ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
1701
+
1702
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
1703
+ /* match is smaller than current */
1704
+ *smallerPtr = matchIndex; /* update smaller idx */
1705
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1706
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1707
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1708
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1709
+ } else {
1710
+ /* match is larger than current */
1711
+ *largerPtr = matchIndex;
1712
+ commonLengthLarger = matchLength;
1713
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1714
+ largerPtr = nextPtr;
1715
+ matchIndex = nextPtr[0];
1716
+ } }
1717
+
1718
+ *smallerPtr = *largerPtr = 0;
1719
+ if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
1720
+ if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1721
+ return 1;
1722
+ }
1723
+
1724
+
1725
+ static size_t ZSTD_insertBtAndFindBestMatch (
1726
+ ZSTD_CCtx* zc,
1727
+ const BYTE* const ip, const BYTE* const iend,
1728
+ size_t* offsetPtr,
1729
+ U32 nbCompares, const U32 mls,
1730
+ U32 extDict)
1731
+ {
1732
+ U32* const hashTable = zc->hashTable;
1733
+ const U32 hashLog = zc->params.cParams.hashLog;
1734
+ const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1735
+ U32* const bt = zc->chainTable;
1736
+ const U32 btLog = zc->params.cParams.chainLog - 1;
1737
+ const U32 btMask= (1 << btLog) - 1;
1738
+ U32 matchIndex = hashTable[h];
1739
+ size_t commonLengthSmaller=0, commonLengthLarger=0;
1740
+ const BYTE* const base = zc->base;
1741
+ const BYTE* const dictBase = zc->dictBase;
1742
+ const U32 dictLimit = zc->dictLimit;
1743
+ const BYTE* const dictEnd = dictBase + dictLimit;
1744
+ const BYTE* const prefixStart = base + dictLimit;
1745
+ const U32 current = (U32)(ip-base);
1746
+ const U32 btLow = btMask >= current ? 0 : current - btMask;
1747
+ const U32 windowLow = zc->lowLimit;
1748
+ U32* smallerPtr = bt + 2*(current&btMask);
1749
+ U32* largerPtr = bt + 2*(current&btMask) + 1;
1750
+ U32 matchEndIdx = current+8;
1751
+ U32 dummy32; /* to be nullified at the end */
1752
+ size_t bestLength = 0;
1753
+
1754
+ hashTable[h] = current; /* Update Hash Table */
1755
+
1756
+ while (nbCompares-- && (matchIndex > windowLow)) {
1757
+ U32* nextPtr = bt + 2*(matchIndex & btMask);
1758
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1759
+ const BYTE* match;
1760
+
1761
+ if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
1762
+ match = base + matchIndex;
1763
+ if (match[matchLength] == ip[matchLength])
1764
+ matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1765
+ } else {
1766
+ match = dictBase + matchIndex;
1767
+ matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1768
+ if (matchIndex+matchLength >= dictLimit)
1769
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1770
+ }
1771
+
1772
+ if (matchLength > bestLength) {
1773
+ if (matchLength > matchEndIdx - matchIndex)
1774
+ matchEndIdx = matchIndex + (U32)matchLength;
1775
+ if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
1776
+ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
1777
+ if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1778
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
1779
+ }
1780
+
1781
+ if (match[matchLength] < ip[matchLength]) {
1782
+ /* match is smaller than current */
1783
+ *smallerPtr = matchIndex; /* update smaller idx */
1784
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1785
+ if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1786
+ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1787
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1788
+ } else {
1789
+ /* match is larger than current */
1790
+ *largerPtr = matchIndex;
1791
+ commonLengthLarger = matchLength;
1792
+ if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1793
+ largerPtr = nextPtr;
1794
+ matchIndex = nextPtr[0];
1795
+ } }
1796
+
1797
+ *smallerPtr = *largerPtr = 0;
1798
+
1799
+ zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
1800
+ return bestLength;
1801
+ }
1802
+
1803
+
1804
+ static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1805
+ {
1806
+ const BYTE* const base = zc->base;
1807
+ const U32 target = (U32)(ip - base);
1808
+ U32 idx = zc->nextToUpdate;
1809
+
1810
+ while(idx < target)
1811
+ idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
1812
+ }
1813
+
1814
+ /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
1815
+ static size_t ZSTD_BtFindBestMatch (
1816
+ ZSTD_CCtx* zc,
1817
+ const BYTE* const ip, const BYTE* const iLimit,
1818
+ size_t* offsetPtr,
1819
+ const U32 maxNbAttempts, const U32 mls)
1820
+ {
1821
+ if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1822
+ ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1823
+ return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1824
+ }
1825
+
1826
+
1827
+ static size_t ZSTD_BtFindBestMatch_selectMLS (
1828
+ ZSTD_CCtx* zc, /* Index table will be updated */
1829
+ const BYTE* ip, const BYTE* const iLimit,
1830
+ size_t* offsetPtr,
1831
+ const U32 maxNbAttempts, const U32 matchLengthSearch)
1832
+ {
1833
+ switch(matchLengthSearch)
1834
+ {
1835
+ default :
1836
+ case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1837
+ case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1838
+ case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1839
+ }
1840
+ }
1841
+
1842
+
1843
+ static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1844
+ {
1845
+ const BYTE* const base = zc->base;
1846
+ const U32 target = (U32)(ip - base);
1847
+ U32 idx = zc->nextToUpdate;
1848
+
1849
+ while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1850
+ }
1851
+
1852
+
1853
+ /** Tree updater, providing best match */
1854
+ static size_t ZSTD_BtFindBestMatch_extDict (
1855
+ ZSTD_CCtx* zc,
1856
+ const BYTE* const ip, const BYTE* const iLimit,
1857
+ size_t* offsetPtr,
1858
+ const U32 maxNbAttempts, const U32 mls)
1859
+ {
1860
+ if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1861
+ ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
1862
+ return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
1863
+ }
1864
+
1865
+
1866
+ static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1867
+ ZSTD_CCtx* zc, /* Index table will be updated */
1868
+ const BYTE* ip, const BYTE* const iLimit,
1869
+ size_t* offsetPtr,
1870
+ const U32 maxNbAttempts, const U32 matchLengthSearch)
1871
+ {
1872
+ switch(matchLengthSearch)
1873
+ {
1874
+ default :
1875
+ case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1876
+ case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1877
+ case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1878
+ }
1879
+ }
1880
+
1881
+
1882
+
1883
+ /* ***********************
1884
+ * Hash Chain
1885
+ *************************/
1886
+
1887
+ #define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1888
+
1889
+
1890
+ /* Update chains up to ip (excluded)
1891
+ Assumption : always within prefix (ie. not within extDict) */
1892
+ FORCE_INLINE
1893
+ U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1894
+ {
1895
+ U32* const hashTable = zc->hashTable;
1896
+ const U32 hashLog = zc->params.cParams.hashLog;
1897
+ U32* const chainTable = zc->chainTable;
1898
+ const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1899
+ const BYTE* const base = zc->base;
1900
+ const U32 target = (U32)(ip - base);
1901
+ U32 idx = zc->nextToUpdate;
1902
+
1903
+ while(idx < target) { /* catch up */
1904
+ size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1905
+ NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1906
+ hashTable[h] = idx;
1907
+ idx++;
1908
+ }
1909
+
1910
+ zc->nextToUpdate = target;
1911
+ return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1912
+ }
1913
+
1914
+
1915
+
1916
+ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1917
+ size_t ZSTD_HcFindBestMatch_generic (
1918
+ ZSTD_CCtx* zc, /* Index table will be updated */
1919
+ const BYTE* const ip, const BYTE* const iLimit,
1920
+ size_t* offsetPtr,
1921
+ const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1922
+ {
1923
+ U32* const chainTable = zc->chainTable;
1924
+ const U32 chainSize = (1 << zc->params.cParams.chainLog);
1925
+ const U32 chainMask = chainSize-1;
1926
+ const BYTE* const base = zc->base;
1927
+ const BYTE* const dictBase = zc->dictBase;
1928
+ const U32 dictLimit = zc->dictLimit;
1929
+ const BYTE* const prefixStart = base + dictLimit;
1930
+ const BYTE* const dictEnd = dictBase + dictLimit;
1931
+ const U32 lowLimit = zc->lowLimit;
1932
+ const U32 current = (U32)(ip-base);
1933
+ const U32 minChain = current > chainSize ? current - chainSize : 0;
1934
+ int nbAttempts=maxNbAttempts;
1935
+ size_t ml=EQUAL_READ32-1;
1936
+
1937
+ /* HC4 match finder */
1938
+ U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1939
+
1940
+ for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
1941
+ const BYTE* match;
1942
+ size_t currentMl=0;
1943
+ if ((!extDict) || matchIndex >= dictLimit) {
1944
+ match = base + matchIndex;
1945
+ if (match[ml] == ip[ml]) /* potentially better */
1946
+ currentMl = ZSTD_count(ip, match, iLimit);
1947
+ } else {
1948
+ match = dictBase + matchIndex;
1949
+ if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1950
+ currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1951
+ }
1952
+
1953
+ /* save best solution */
1954
+ if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1955
+
1956
+ if (matchIndex <= minChain) break;
1957
+ matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1958
+ }
1959
+
1960
+ return ml;
1961
+ }
1962
+
1963
+
1964
+ FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1965
+ ZSTD_CCtx* zc,
1966
+ const BYTE* ip, const BYTE* const iLimit,
1967
+ size_t* offsetPtr,
1968
+ const U32 maxNbAttempts, const U32 matchLengthSearch)
1969
+ {
1970
+ switch(matchLengthSearch)
1971
+ {
1972
+ default :
1973
+ case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1974
+ case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1975
+ case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1976
+ }
1977
+ }
1978
+
1979
+
1980
+ FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1981
+ ZSTD_CCtx* zc,
1982
+ const BYTE* ip, const BYTE* const iLimit,
1983
+ size_t* offsetPtr,
1984
+ const U32 maxNbAttempts, const U32 matchLengthSearch)
1985
+ {
1986
+ switch(matchLengthSearch)
1987
+ {
1988
+ default :
1989
+ case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1990
+ case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1991
+ case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1992
+ }
1993
+ }
1994
+
1995
+
1996
+ /* *******************************
1997
+ * Common parser - lazy strategy
1998
+ *********************************/
1999
+ FORCE_INLINE
2000
+ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2001
+ const void* src, size_t srcSize,
2002
+ const U32 searchMethod, const U32 depth)
2003
+ {
2004
+ seqStore_t* seqStorePtr = &(ctx->seqStore);
2005
+ const BYTE* const istart = (const BYTE*)src;
2006
+ const BYTE* ip = istart;
2007
+ const BYTE* anchor = istart;
2008
+ const BYTE* const iend = istart + srcSize;
2009
+ const BYTE* const ilimit = iend - 8;
2010
+ const BYTE* const base = ctx->base + ctx->dictLimit;
2011
+
2012
+ U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
2013
+ U32 const mls = ctx->params.cParams.searchLength;
2014
+
2015
+ typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2016
+ size_t* offsetPtr,
2017
+ U32 maxNbAttempts, U32 matchLengthSearch);
2018
+ searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
2019
+ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
2020
+
2021
+ /* init */
2022
+ ip += (ip==base);
2023
+ ctx->nextToUpdate3 = ctx->nextToUpdate;
2024
+ { U32 const maxRep = (U32)(ip-base);
2025
+ if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2026
+ if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2027
+ }
2028
+
2029
+ /* Match Loop */
2030
+ while (ip < ilimit) {
2031
+ size_t matchLength=0;
2032
+ size_t offset=0;
2033
+ const BYTE* start=ip+1;
2034
+
2035
+ /* check repCode */
2036
+ if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
2037
+ /* repcode : we take it */
2038
+ matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
2039
+ if (depth==0) goto _storeSequence;
2040
+ }
2041
+
2042
+ /* first search (depth 0) */
2043
+ { size_t offsetFound = 99999999;
2044
+ size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
2045
+ if (ml2 > matchLength)
2046
+ matchLength = ml2, start = ip, offset=offsetFound;
2047
+ }
2048
+
2049
+ if (matchLength < EQUAL_READ32) {
2050
+ ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2051
+ continue;
2052
+ }
2053
+
2054
+ /* let's try to find a better solution */
2055
+ if (depth>=1)
2056
+ while (ip<ilimit) {
2057
+ ip ++;
2058
+ if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
2059
+ size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
2060
+ int const gain2 = (int)(mlRep * 3);
2061
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
2062
+ if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
2063
+ matchLength = mlRep, offset = 0, start = ip;
2064
+ }
2065
+ { size_t offset2=99999999;
2066
+ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2067
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2068
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
2069
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2070
+ matchLength = ml2, offset = offset2, start = ip;
2071
+ continue; /* search a better one */
2072
+ } }
2073
+
2074
+ /* let's find an even better one */
2075
+ if ((depth==2) && (ip<ilimit)) {
2076
+ ip ++;
2077
+ if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
2078
+ size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
2079
+ int const gain2 = (int)(ml2 * 4);
2080
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
2081
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
2082
+ matchLength = ml2, offset = 0, start = ip;
2083
+ }
2084
+ { size_t offset2=99999999;
2085
+ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2086
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2087
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
2088
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2089
+ matchLength = ml2, offset = offset2, start = ip;
2090
+ continue;
2091
+ } } }
2092
+ break; /* nothing found : store previous solution */
2093
+ }
2094
+
2095
+ /* catch up */
2096
+ if (offset) {
2097
+ while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
2098
+ { start--; matchLength++; }
2099
+ offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
2100
+ }
2101
+
2102
+ /* store sequence */
2103
+ _storeSequence:
2104
+ { size_t const litLength = start - anchor;
2105
+ ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
2106
+ anchor = ip = start + matchLength;
2107
+ }
2108
+
2109
+ /* check immediate repcode */
2110
+ while ( (ip <= ilimit)
2111
+ && ((offset_2>0)
2112
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
2113
+ /* store sequence */
2114
+ matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
2115
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
2116
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2117
+ ip += matchLength;
2118
+ anchor = ip;
2119
+ continue; /* faster when present ... (?) */
2120
+ } }
2121
+
2122
+ /* Save reps for next block */
2123
+ ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset;
2124
+ ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset;
2125
+
2126
+ /* Last Literals */
2127
+ { size_t const lastLLSize = iend - anchor;
2128
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
2129
+ seqStorePtr->lit += lastLLSize;
2130
+ ZSTD_statsUpdatePrices(&seqStorePtr->stats, lastLLSize, anchor, 0, 0);
2131
+ }
2132
+ }
2133
+
2134
+
2135
+ static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2136
+ {
2137
+ ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2138
+ }
2139
+
2140
+ static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2141
+ {
2142
+ ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2143
+ }
2144
+
2145
+ static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2146
+ {
2147
+ ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2148
+ }
2149
+
2150
+ static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2151
+ {
2152
+ ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2153
+ }
2154
+
2155
+
2156
+ FORCE_INLINE
2157
+ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2158
+ const void* src, size_t srcSize,
2159
+ const U32 searchMethod, const U32 depth)
2160
+ {
2161
+ seqStore_t* seqStorePtr = &(ctx->seqStore);
2162
+ const BYTE* const istart = (const BYTE*)src;
2163
+ const BYTE* ip = istart;
2164
+ const BYTE* anchor = istart;
2165
+ const BYTE* const iend = istart + srcSize;
2166
+ const BYTE* const ilimit = iend - 8;
2167
+ const BYTE* const base = ctx->base;
2168
+ const U32 dictLimit = ctx->dictLimit;
2169
+ const U32 lowestIndex = ctx->lowLimit;
2170
+ const BYTE* const prefixStart = base + dictLimit;
2171
+ const BYTE* const dictBase = ctx->dictBase;
2172
+ const BYTE* const dictEnd = dictBase + dictLimit;
2173
+ const BYTE* const dictStart = dictBase + ctx->lowLimit;
2174
+
2175
+ const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2176
+ const U32 mls = ctx->params.cParams.searchLength;
2177
+
2178
+ typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2179
+ size_t* offsetPtr,
2180
+ U32 maxNbAttempts, U32 matchLengthSearch);
2181
+ searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2182
+
2183
+ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
2184
+
2185
+ /* init */
2186
+ ctx->nextToUpdate3 = ctx->nextToUpdate;
2187
+ ip += (ip == prefixStart);
2188
+
2189
+ /* Match Loop */
2190
+ while (ip < ilimit) {
2191
+ size_t matchLength=0;
2192
+ size_t offset=0;
2193
+ const BYTE* start=ip+1;
2194
+ U32 current = (U32)(ip-base);
2195
+
2196
+ /* check repCode */
2197
+ { const U32 repIndex = (U32)(current+1 - offset_1);
2198
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2199
+ const BYTE* const repMatch = repBase + repIndex;
2200
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2201
+ if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
2202
+ /* repcode detected we should take it */
2203
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2204
+ matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2205
+ if (depth==0) goto _storeSequence;
2206
+ } }
2207
+
2208
+ /* first search (depth 0) */
2209
+ { size_t offsetFound = 99999999;
2210
+ size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
2211
+ if (ml2 > matchLength)
2212
+ matchLength = ml2, start = ip, offset=offsetFound;
2213
+ }
2214
+
2215
+ if (matchLength < EQUAL_READ32) {
2216
+ ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2217
+ continue;
2218
+ }
2219
+
2220
+ /* let's try to find a better solution */
2221
+ if (depth>=1)
2222
+ while (ip<ilimit) {
2223
+ ip ++;
2224
+ current++;
2225
+ /* check repCode */
2226
+ if (offset) {
2227
+ const U32 repIndex = (U32)(current - offset_1);
2228
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2229
+ const BYTE* const repMatch = repBase + repIndex;
2230
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2231
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
2232
+ /* repcode detected */
2233
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2234
+ size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2235
+ int const gain2 = (int)(repLength * 3);
2236
+ int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
2237
+ if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2238
+ matchLength = repLength, offset = 0, start = ip;
2239
+ } }
2240
+
2241
+ /* search match, depth 1 */
2242
+ { size_t offset2=99999999;
2243
+ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2244
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2245
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
2246
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2247
+ matchLength = ml2, offset = offset2, start = ip;
2248
+ continue; /* search a better one */
2249
+ } }
2250
+
2251
+ /* let's find an even better one */
2252
+ if ((depth==2) && (ip<ilimit)) {
2253
+ ip ++;
2254
+ current++;
2255
+ /* check repCode */
2256
+ if (offset) {
2257
+ const U32 repIndex = (U32)(current - offset_1);
2258
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2259
+ const BYTE* const repMatch = repBase + repIndex;
2260
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2261
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
2262
+ /* repcode detected */
2263
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2264
+ size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2265
+ int gain2 = (int)(repLength * 4);
2266
+ int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
2267
+ if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2268
+ matchLength = repLength, offset = 0, start = ip;
2269
+ } }
2270
+
2271
+ /* search match, depth 2 */
2272
+ { size_t offset2=99999999;
2273
+ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2274
+ int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2275
+ int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
2276
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2277
+ matchLength = ml2, offset = offset2, start = ip;
2278
+ continue;
2279
+ } } }
2280
+ break; /* nothing found : store previous solution */
2281
+ }
2282
+
2283
+ /* catch up */
2284
+ if (offset) {
2285
+ U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
2286
+ const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2287
+ const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
2288
+ while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
2289
+ offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
2290
+ }
2291
+
2292
+ /* store sequence */
2293
+ _storeSequence:
2294
+ { size_t const litLength = start - anchor;
2295
+ ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
2296
+ anchor = ip = start + matchLength;
2297
+ }
2298
+
2299
+ /* check immediate repcode */
2300
+ while (ip <= ilimit) {
2301
+ const U32 repIndex = (U32)((ip-base) - offset_2);
2302
+ const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2303
+ const BYTE* const repMatch = repBase + repIndex;
2304
+ if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2305
+ if (MEM_read32(ip) == MEM_read32(repMatch)) {
2306
+ /* repcode detected we should take it */
2307
+ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2308
+ matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2309
+ offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
2310
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2311
+ ip += matchLength;
2312
+ anchor = ip;
2313
+ continue; /* faster when present ... (?) */
2314
+ }
2315
+ break;
2316
+ } }
2317
+
2318
+ /* Save reps for next block */
2319
+ ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
2320
+
2321
+ /* Last Literals */
2322
+ { size_t const lastLLSize = iend - anchor;
2323
+ memcpy(seqStorePtr->lit, anchor, lastLLSize);
2324
+ seqStorePtr->lit += lastLLSize;
2325
+ }
2326
+ }
2327
+
2328
+
2329
+ void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2330
+ {
2331
+ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
2332
+ }
2333
+
2334
+ static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2335
+ {
2336
+ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
2337
+ }
2338
+
2339
+ static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2340
+ {
2341
+ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
2342
+ }
2343
+
2344
+ static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2345
+ {
2346
+ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
2347
+ }
2348
+
2349
+
2350
+ /* The optimal parser */
2351
+ #include "zstd_opt.h"
2352
+
2353
+ static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2354
+ {
2355
+ #ifdef ZSTD_OPT_H_91842398743
2356
+ ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
2357
+ #else
2358
+ (void)ctx; (void)src; (void)srcSize;
2359
+ return;
2360
+ #endif
2361
+ }
2362
+
2363
+ static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2364
+ {
2365
+ #ifdef ZSTD_OPT_H_91842398743
2366
+ ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
2367
+ #else
2368
+ (void)ctx; (void)src; (void)srcSize;
2369
+ return;
2370
+ #endif
2371
+ }
2372
+
2373
+
2374
+ typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
2375
+
2376
+ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
2377
+ {
2378
+ static const ZSTD_blockCompressor blockCompressor[2][7] = {
2379
+ { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
2380
+ { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict }
2381
+ };
2382
+
2383
+ return blockCompressor[extDict][(U32)strat];
2384
+ }
2385
+
2386
+
2387
+ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2388
+ {
2389
+ ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
2390
+ if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
2391
+ ZSTD_resetSeqStore(&(zc->seqStore));
2392
+ blockCompressor(zc, src, srcSize);
2393
+ return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
2394
+ }
2395
+
2396
+
2397
+
2398
+
2399
+ static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2400
+ void* dst, size_t dstCapacity,
2401
+ const void* src, size_t srcSize)
2402
+ {
2403
+ size_t blockSize = cctx->blockSize;
2404
+ size_t remaining = srcSize;
2405
+ const BYTE* ip = (const BYTE*)src;
2406
+ BYTE* const ostart = (BYTE*)dst;
2407
+ BYTE* op = ostart;
2408
+ const U32 maxDist = 1 << cctx->params.cParams.windowLog;
2409
+ ZSTD_stats_t* stats = &cctx->seqStore.stats;
2410
+ ZSTD_statsInit(stats); /* debug only */
2411
+
2412
+ if (cctx->params.fParams.checksumFlag)
2413
+ XXH64_update(&cctx->xxhState, src, srcSize);
2414
+
2415
+ while (remaining) {
2416
+ size_t cSize;
2417
+ ZSTD_statsResetFreqs(stats); /* debug only */
2418
+
2419
+ if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
2420
+ if (remaining < blockSize) blockSize = remaining;
2421
+
2422
+ if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
2423
+ /* enforce maxDist */
2424
+ U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2425
+ if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2426
+ if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
2427
+ }
2428
+
2429
+ cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
2430
+ if (ZSTD_isError(cSize)) return cSize;
2431
+
2432
+ if (cSize == 0) { /* block is not compressible */
2433
+ cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
2434
+ if (ZSTD_isError(cSize)) return cSize;
2435
+ } else {
2436
+ op[0] = (BYTE)(cSize>>16);
2437
+ op[1] = (BYTE)(cSize>>8);
2438
+ op[2] = (BYTE)cSize;
2439
+ op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
2440
+ cSize += 3;
2441
+ }
2442
+
2443
+ remaining -= blockSize;
2444
+ dstCapacity -= cSize;
2445
+ ip += blockSize;
2446
+ op += cSize;
2447
+ }
2448
+
2449
+ ZSTD_statsPrint(stats, cctx->params.cParams.searchLength);
2450
+ return op-ostart;
2451
+ }
2452
+
2453
+
2454
+ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2455
+ ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
2456
+ { BYTE* const op = (BYTE*)dst;
2457
+ U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2458
+ U32 const checksumFlag = params.fParams.checksumFlag>0;
2459
+ U32 const windowSize = 1U << params.cParams.windowLog;
2460
+ U32 const directModeFlag = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1));
2461
+ BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2462
+ U32 const fcsCode = params.fParams.contentSizeFlag ?
2463
+ (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2464
+ 0;
2465
+ BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (directModeFlag<<5) + (fcsCode<<6) );
2466
+ size_t pos;
2467
+
2468
+ if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
2469
+
2470
+ MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2471
+ op[4] = frameHeaderDecriptionByte; pos=5;
2472
+ if (!directModeFlag) op[pos++] = windowLogByte;
2473
+ switch(dictIDSizeCode)
2474
+ {
2475
+ default: /* impossible */
2476
+ case 0 : break;
2477
+ case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2478
+ case 2 : MEM_writeLE16(op+pos, (U16)(dictID)); pos+=2; break;
2479
+ case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2480
+ }
2481
+ switch(fcsCode)
2482
+ {
2483
+ default: /* impossible */
2484
+ case 0 : if (directModeFlag) op[pos++] = (BYTE)(pledgedSrcSize); break;
2485
+ case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2486
+ case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
2487
+ case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
2488
+ }
2489
+ return pos;
2490
+ }
2491
+
2492
+
2493
+ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
2494
+ void* dst, size_t dstCapacity,
2495
+ const void* src, size_t srcSize,
2496
+ U32 frame)
2497
+ {
2498
+ const BYTE* const ip = (const BYTE*) src;
2499
+ size_t fhSize = 0;
2500
+
2501
+ if (zc->stage==0) return ERROR(stage_wrong);
2502
+ if (frame && (zc->stage==1)) { /* copy saved header */
2503
+ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, zc->frameContentSize, zc->dictID);
2504
+ if (ZSTD_isError(fhSize)) return fhSize;
2505
+ dstCapacity -= fhSize;
2506
+ dst = (char*)dst + fhSize;
2507
+ zc->stage = 2;
2508
+ }
2509
+
2510
+ /* Check if blocks follow each other */
2511
+ if (src != zc->nextSrc) {
2512
+ /* not contiguous */
2513
+ size_t const delta = zc->nextSrc - ip;
2514
+ zc->lowLimit = zc->dictLimit;
2515
+ zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2516
+ zc->dictBase = zc->base;
2517
+ zc->base -= delta;
2518
+ zc->nextToUpdate = zc->dictLimit;
2519
+ if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
2520
+ }
2521
+
2522
+ /* preemptive overflow correction */
2523
+ if (zc->lowLimit > (1<<30)) {
2524
+ U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) | (zc->params.cParams.strategy == ZSTD_btopt);
2525
+ U32 const chainMask = (1 << (zc->params.cParams.chainLog - btplus)) - 1;
2526
+ U32 const newLowLimit = zc->lowLimit & chainMask; /* preserve position % chainSize */
2527
+ U32 const correction = zc->lowLimit - newLowLimit;
2528
+ ZSTD_reduceIndex(zc, correction);
2529
+ zc->base += correction;
2530
+ zc->dictBase += correction;
2531
+ zc->lowLimit = newLowLimit;
2532
+ zc->dictLimit -= correction;
2533
+ if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2534
+ else zc->nextToUpdate -= correction;
2535
+ }
2536
+
2537
+ /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
2538
+ if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
2539
+ zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2540
+ if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
2541
+ }
2542
+
2543
+ zc->nextSrc = ip + srcSize;
2544
+ { size_t const cSize = frame ?
2545
+ ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2546
+ ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
2547
+ if (ZSTD_isError(cSize)) return cSize;
2548
+ return cSize + fhSize;
2549
+ }
2550
+ }
2551
+
2552
+
2553
+ size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2554
+ void* dst, size_t dstCapacity,
2555
+ const void* src, size_t srcSize)
2556
+ {
2557
+ return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
2558
+ }
2559
+
2560
+
2561
+ size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2562
+ {
2563
+ size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << zc->params.cParams.windowLog);
2564
+ if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
2565
+ ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.cParams.searchLength);
2566
+ return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
2567
+ }
2568
+
2569
+
2570
+ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2571
+ {
2572
+ const BYTE* const ip = (const BYTE*) src;
2573
+ const BYTE* const iend = ip + srcSize;
2574
+
2575
+ /* input becomes current prefix */
2576
+ zc->lowLimit = zc->dictLimit;
2577
+ zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2578
+ zc->dictBase = zc->base;
2579
+ zc->base += ip - zc->nextSrc;
2580
+ zc->nextToUpdate = zc->dictLimit;
2581
+ zc->loadedDictEnd = (U32)(iend - zc->base);
2582
+
2583
+ zc->nextSrc = iend;
2584
+ if (srcSize <= 8) return 0;
2585
+
2586
+ switch(zc->params.cParams.strategy)
2587
+ {
2588
+ case ZSTD_fast:
2589
+ ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
2590
+ break;
2591
+
2592
+ case ZSTD_dfast:
2593
+ ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2594
+ break;
2595
+
2596
+ case ZSTD_greedy:
2597
+ case ZSTD_lazy:
2598
+ case ZSTD_lazy2:
2599
+ ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
2600
+ break;
2601
+
2602
+ case ZSTD_btlazy2:
2603
+ case ZSTD_btopt:
2604
+ ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
2605
+ break;
2606
+
2607
+ default:
2608
+ return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2609
+ }
2610
+
2611
+ zc->nextToUpdate = zc->loadedDictEnd;
2612
+ return 0;
2613
+ }
2614
+
2615
+
2616
+ /* Dictionary format :
2617
+ Magic == ZSTD_DICT_MAGIC (4 bytes)
2618
+ HUF_writeCTable(256)
2619
+ FSE_writeNCount(ml)
2620
+ FSE_writeNCount(off)
2621
+ FSE_writeNCount(ll)
2622
+ RepOffsets
2623
+ Dictionary content
2624
+ */
2625
+ /*! ZSTD_loadDictEntropyStats() :
2626
+ @return : size read from dictionary
2627
+ note : magic number supposed already checked */
2628
+ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
2629
+ {
2630
+ const BYTE* dictPtr = (const BYTE*)dict;
2631
+ const BYTE* const dictEnd = dictPtr + dictSize;
2632
+
2633
+ { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
2634
+ if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
2635
+ dictPtr += hufHeaderSize;
2636
+ }
2637
+
2638
+ { short offcodeNCount[MaxOff+1];
2639
+ unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2640
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
2641
+ if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2642
+ { size_t const errorCode = FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2643
+ if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
2644
+ dictPtr += offcodeHeaderSize;
2645
+ }
2646
+
2647
+ { short matchlengthNCount[MaxML+1];
2648
+ unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2649
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
2650
+ if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2651
+ { size_t const errorCode = FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2652
+ if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
2653
+ dictPtr += matchlengthHeaderSize;
2654
+ }
2655
+
2656
+ { short litlengthNCount[MaxLL+1];
2657
+ unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2658
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
2659
+ if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2660
+ { size_t const errorCode = FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2661
+ if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
2662
+ dictPtr += litlengthHeaderSize;
2663
+ }
2664
+
2665
+ if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
2666
+ cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2667
+ cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2668
+ cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
2669
+ dictPtr += 12;
2670
+
2671
+ cctx->flagStaticTables = 1;
2672
+ return dictPtr - (const BYTE*)dict;
2673
+ }
2674
+
2675
+ /** ZSTD_compress_insertDictionary() :
2676
+ * @return : 0, or an error code */
2677
+ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2678
+ {
2679
+ if ((dict==NULL) || (dictSize<=8)) return 0;
2680
+
2681
+ /* default : dict is pure content */
2682
+ if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
2683
+ zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
2684
+
2685
+ /* known magic number : dict is parsed for entropy stats and content */
2686
+ { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8) + 8;
2687
+ if (ZSTD_isError(eSize)) return eSize;
2688
+ return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2689
+ }
2690
+ }
2691
+
2692
+
2693
+ /*! ZSTD_compressBegin_internal() :
2694
+ * @return : 0, or an error code */
2695
+ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
2696
+ const void* dict, size_t dictSize,
2697
+ ZSTD_parameters params, U64 pledgedSrcSize)
2698
+ {
2699
+ size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, pledgedSrcSize, 1);
2700
+ if (ZSTD_isError(resetError)) return resetError;
2701
+
2702
+ return ZSTD_compress_insertDictionary(zc, dict, dictSize);
2703
+ }
2704
+
2705
+
2706
+ /*! ZSTD_compressBegin_advanced() :
2707
+ * @return : 0, or an error code */
2708
+ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
2709
+ const void* dict, size_t dictSize,
2710
+ ZSTD_parameters params, unsigned long long pledgedSrcSize)
2711
+ {
2712
+ /* compression parameters verification and optimization */
2713
+ { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2714
+ if (ZSTD_isError(errorCode)) return errorCode; }
2715
+
2716
+ return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
2717
+ }
2718
+
2719
+
2720
+ size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
2721
+ {
2722
+ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2723
+ ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", cctx->base, compressionLevel);
2724
+ return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
2725
+ }
2726
+
2727
+
2728
+ size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
2729
+ {
2730
+ ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
2731
+ return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
2732
+ }
2733
+
2734
+
2735
+ /*! ZSTD_compressEnd() :
2736
+ * Write frame epilogue.
2737
+ * @return : nb of bytes written into dst (or an error code) */
2738
+ size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
2739
+ {
2740
+ BYTE* op = (BYTE*)dst;
2741
+ size_t fhSize = 0;
2742
+
2743
+ /* not even init ! */
2744
+ if (cctx->stage==0) return ERROR(stage_wrong);
2745
+
2746
+ /* special case : empty frame */
2747
+ if (cctx->stage==1) {
2748
+ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
2749
+ if (ZSTD_isError(fhSize)) return fhSize;
2750
+ dstCapacity -= fhSize;
2751
+ op += fhSize;
2752
+ cctx->stage = 2;
2753
+ }
2754
+
2755
+ /* frame epilogue */
2756
+ if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
2757
+ { U32 const checksum = cctx->params.fParams.checksumFlag ?
2758
+ (U32)((XXH64_digest(&cctx->xxhState) >> 11) & ((1<<22)-1)) :
2759
+ 0;
2760
+ op[0] = (BYTE)((bt_end<<6) + (checksum>>16));
2761
+ op[1] = (BYTE)(checksum>>8);
2762
+ op[2] = (BYTE)checksum;
2763
+ }
2764
+
2765
+ cctx->stage = 0; /* return to "created but not init" status */
2766
+ return 3+fhSize;
2767
+ }
2768
+
2769
+
2770
+ /*! ZSTD_compress_usingPreparedCCtx() :
2771
+ * Same as ZSTD_compress_usingDict, but using a reference context `preparedCCtx`, where dictionary has been loaded.
2772
+ * It avoids reloading the dictionary each time.
2773
+ * `preparedCCtx` must have been properly initialized using ZSTD_compressBegin_usingDict() or ZSTD_compressBegin_advanced().
2774
+ * Requires 2 contexts : 1 for reference (preparedCCtx) which will not be modified, and 1 to run the compression operation (cctx) */
2775
+ static size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2776
+ void* dst, size_t dstCapacity,
2777
+ const void* src, size_t srcSize)
2778
+ {
2779
+ { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2780
+ if (ZSTD_isError(errorCode)) return errorCode;
2781
+ }
2782
+ { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2783
+ if (ZSTD_isError(cSize)) return cSize;
2784
+
2785
+ { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2786
+ if (ZSTD_isError(endSize)) return endSize;
2787
+ return cSize + endSize;
2788
+ } }
2789
+ }
2790
+
2791
+
2792
+ static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
2793
+ void* dst, size_t dstCapacity,
2794
+ const void* src, size_t srcSize,
2795
+ const void* dict,size_t dictSize,
2796
+ ZSTD_parameters params)
2797
+ {
2798
+ BYTE* const ostart = (BYTE*)dst;
2799
+ BYTE* op = ostart;
2800
+
2801
+ /* Init */
2802
+ { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
2803
+ if(ZSTD_isError(errorCode)) return errorCode; }
2804
+
2805
+ /* body (compression) */
2806
+ { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
2807
+ if(ZSTD_isError(oSize)) return oSize;
2808
+ op += oSize;
2809
+ dstCapacity -= oSize; }
2810
+
2811
+ /* Close frame */
2812
+ { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
2813
+ if(ZSTD_isError(oSize)) return oSize;
2814
+ op += oSize; }
2815
+
2816
+ return (op - ostart);
2817
+ }
2818
+
2819
+ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2820
+ void* dst, size_t dstCapacity,
2821
+ const void* src, size_t srcSize,
2822
+ const void* dict,size_t dictSize,
2823
+ ZSTD_parameters params)
2824
+ {
2825
+ size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
2826
+ if (ZSTD_isError(errorCode)) return errorCode;
2827
+ return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2828
+ }
2829
+
2830
+ size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel)
2831
+ {
2832
+ ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dictSize);
2833
+ params.fParams.contentSizeFlag = 1;
2834
+ ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel);
2835
+ return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2836
+ }
2837
+
2838
+ size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
2839
+ {
2840
+ ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
2841
+ return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
2842
+ }
2843
+
2844
+ size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
2845
+ {
2846
+ size_t result;
2847
+ ZSTD_CCtx ctxBody;
2848
+ memset(&ctxBody, 0, sizeof(ctxBody));
2849
+ memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
2850
+ result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
2851
+ ctxBody.customMem.customFree(ctxBody.customMem.opaque, ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
2852
+ return result;
2853
+ }
2854
+
2855
+
2856
+ /* ===== Dictionary API ===== */
2857
+
2858
+ struct ZSTD_CDict_s {
2859
+ void* dictContent;
2860
+ size_t dictContentSize;
2861
+ ZSTD_CCtx* refContext;
2862
+ }; /* typedef'd tp ZSTD_CDict within zstd.h */
2863
+
2864
+ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem)
2865
+ {
2866
+ if (!customMem.customAlloc && !customMem.customFree)
2867
+ customMem = defaultCustomMem;
2868
+
2869
+ if (!customMem.customAlloc || !customMem.customFree) /* can't have 1/2 custom alloc/free as NULL */
2870
+ return NULL;
2871
+
2872
+ { ZSTD_CDict* const cdict = (ZSTD_CDict*) customMem.customAlloc(customMem.opaque, sizeof(*cdict));
2873
+ void* const dictContent = customMem.customAlloc(customMem.opaque, dictSize);
2874
+ ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2875
+
2876
+ if (!dictContent || !cdict || !cctx) {
2877
+ customMem.customFree(customMem.opaque, dictContent);
2878
+ customMem.customFree(customMem.opaque, cdict);
2879
+ customMem.customFree(customMem.opaque, cctx);
2880
+ return NULL;
2881
+ }
2882
+
2883
+ memcpy(dictContent, dict, dictSize);
2884
+ { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, dictContent, dictSize, params, 0);
2885
+ if (ZSTD_isError(errorCode)) {
2886
+ customMem.customFree(customMem.opaque, dictContent);
2887
+ customMem.customFree(customMem.opaque, cdict);
2888
+ customMem.customFree(customMem.opaque, cctx);
2889
+ return NULL;
2890
+ } }
2891
+
2892
+ cdict->dictContent = dictContent;
2893
+ cdict->dictContentSize = dictSize;
2894
+ cdict->refContext = cctx;
2895
+ return cdict;
2896
+ }
2897
+ }
2898
+
2899
+ ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2900
+ {
2901
+ ZSTD_customMem const allocator = { NULL, NULL, NULL };
2902
+ ZSTD_parameters params;
2903
+ memset(&params, 0, sizeof(params));
2904
+ params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2905
+ params.fParams.contentSizeFlag = 1;
2906
+ return ZSTD_createCDict_advanced(dict, dictSize, params, allocator);
2907
+ }
2908
+
2909
+ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2910
+ {
2911
+ ZSTD_freeFunction const cFree = cdict->refContext->customMem.customFree;
2912
+ void* const opaque = cdict->refContext->customMem.opaque;
2913
+ ZSTD_freeCCtx(cdict->refContext);
2914
+ cFree(opaque, cdict->dictContent);
2915
+ cFree(opaque, cdict);
2916
+ return 0;
2917
+ }
2918
+
2919
+ ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2920
+ void* dst, size_t dstCapacity,
2921
+ const void* src, size_t srcSize,
2922
+ const ZSTD_CDict* cdict)
2923
+ {
2924
+ return ZSTD_compress_usingPreparedCCtx(cctx, cdict->refContext,
2925
+ dst, dstCapacity,
2926
+ src, srcSize);
2927
+ }
2928
+
2929
+
2930
+
2931
+ /*-===== Pre-defined compression levels =====-*/
2932
+
2933
+ #define ZSTD_DEFAULT_CLEVEL 1
2934
+ #define ZSTD_MAX_CLEVEL 22
2935
+ unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2936
+
2937
+ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
2938
+ { /* "default" */
2939
+ /* W, C, H, S, L, TL, strat */
2940
+ { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - not used */
2941
+ { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
2942
+ { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
2943
+ { 20, 16, 18, 1, 5, 16, ZSTD_dfast }, /* level 3 */
2944
+ { 20, 13, 17, 2, 5, 16, ZSTD_greedy }, /* level 4.*/
2945
+ { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
2946
+ { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
2947
+ { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
2948
+ { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8.*/
2949
+ { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
2950
+ { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
2951
+ { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
2952
+ { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
2953
+ { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
2954
+ { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
2955
+ { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
2956
+ { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
2957
+ { 23, 23, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 17.*/
2958
+ { 23, 23, 22, 6, 5, 24, ZSTD_btopt }, /* level 18.*/
2959
+ { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19.*/
2960
+ { 25, 26, 23, 7, 3, 64, ZSTD_btopt }, /* level 20.*/
2961
+ { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21.*/
2962
+ { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22.*/
2963
+ },
2964
+ { /* for srcSize <= 256 KB */
2965
+ /* W, C, H, S, L, T, strat */
2966
+ { 18, 12, 12, 1, 7, 4, ZSTD_fast }, /* level 0 - not used */
2967
+ { 18, 13, 14, 1, 6, 4, ZSTD_fast }, /* level 1 */
2968
+ { 18, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 2 */
2969
+ { 18, 13, 15, 1, 5, 4, ZSTD_greedy }, /* level 3.*/
2970
+ { 18, 15, 17, 1, 5, 4, ZSTD_greedy }, /* level 4.*/
2971
+ { 18, 16, 17, 4, 5, 4, ZSTD_greedy }, /* level 5 */
2972
+ { 18, 17, 17, 5, 5, 4, ZSTD_greedy }, /* level 6 */
2973
+ { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2974
+ { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2975
+ { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2976
+ { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2977
+ { 18, 18, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 11.*/
2978
+ { 18, 18, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 12.*/
2979
+ { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2980
+ { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
2981
+ { 18, 18, 18, 8, 4, 24, ZSTD_btopt }, /* level 15.*/
2982
+ { 18, 19, 18, 8, 3, 48, ZSTD_btopt }, /* level 16.*/
2983
+ { 18, 19, 18, 8, 3, 96, ZSTD_btopt }, /* level 17.*/
2984
+ { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2985
+ { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
2986
+ { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
2987
+ { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
2988
+ { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
2989
+ },
2990
+ { /* for srcSize <= 128 KB */
2991
+ /* W, C, H, S, L, T, strat */
2992
+ { 17, 12, 12, 1, 7, 4, ZSTD_fast }, /* level 0 - not used */
2993
+ { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2994
+ { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2995
+ { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2996
+ { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2997
+ { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2998
+ { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2999
+ { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
3000
+ { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
3001
+ { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
3002
+ { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
3003
+ { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
3004
+ { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
3005
+ { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
3006
+ { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3007
+ { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3008
+ { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3009
+ { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3010
+ { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3011
+ { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
3012
+ { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
3013
+ { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
3014
+ { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
3015
+ },
3016
+ { /* for srcSize <= 16 KB */
3017
+ /* W, C, H, S, L, T, strat */
3018
+ { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
3019
+ { 14, 14, 14, 1, 7, 6, ZSTD_fast }, /* level 1 */
3020
+ { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3021
+ { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3022
+ { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3023
+ { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3024
+ { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3025
+ { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3026
+ { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3027
+ { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
3028
+ { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3029
+ { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3030
+ { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3031
+ { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3032
+ { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3033
+ { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3034
+ { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3035
+ { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3036
+ { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3037
+ { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
3038
+ { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
3039
+ { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
3040
+ { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
3041
+ },
3042
+ };
3043
+
3044
+ /*! ZSTD_getCParams() :
3045
+ * @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3046
+ * Size values are optional, provide 0 if not known or unused */
3047
+ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
3048
+ {
3049
+ ZSTD_compressionParameters cp;
3050
+ size_t const addedSize = srcSize ? 0 : 500;
3051
+ U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
3052
+ U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
3053
+ if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
3054
+ if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
3055
+ cp = ZSTD_defaultCParameters[tableID][compressionLevel];
3056
+ if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3057
+ if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
3058
+ if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
3059
+ if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3060
+ }
3061
+ cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
3062
+ return cp;
3063
+ }
3064
+
3065
+ /*! ZSTD_getParams() :
3066
+ * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
3067
+ * All fields of `ZSTD_frameParameters` are set to default (0) */
3068
+ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
3069
+ ZSTD_parameters params;
3070
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3071
+ memset(&params, 0, sizeof(params));
3072
+ params.cParams = cParams;
3073
+ return params;
3074
+ }