]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/zstd/tests/zstreamtest.c
MFHead @347527
[FreeBSD/FreeBSD.git] / sys / contrib / zstd / tests / zstreamtest.c
1 /*
2  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under both the BSD-style license (found in the
6  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7  * in the COPYING file in the root directory of this source tree).
8  * You may select, at your option, one of the above-listed licenses.
9  */
10
11
12 /*-************************************
13  *  Compiler specific
14  **************************************/
15 #ifdef _MSC_VER    /* Visual Studio */
16 #  define _CRT_SECURE_NO_WARNINGS   /* fgets */
17 #  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */
18 #  pragma warning(disable : 4146)   /* disable: C4146: minus unsigned expression */
19 #endif
20
21
22 /*-************************************
23  *  Includes
24  **************************************/
25 #include <stdlib.h>       /* free */
26 #include <stdio.h>        /* fgets, sscanf */
27 #include <string.h>       /* strcmp */
28 #include <assert.h>       /* assert */
29 #include "timefn.h"       /* UTIL_time_t, UTIL_getTime */
30 #include "mem.h"
31 #define ZSTD_STATIC_LINKING_ONLY  /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
32 #include "zstd.h"         /* ZSTD_compressBound */
33 #include "zstd_errors.h"  /* ZSTD_error_srcSize_wrong */
34 #include "zstdmt_compress.h"
35 #include "zdict.h"        /* ZDICT_trainFromBuffer */
36 #include "datagen.h"      /* RDG_genBuffer */
37 #define XXH_STATIC_LINKING_ONLY   /* XXH64_state_t */
38 #include "xxhash.h"       /* XXH64_* */
39 #include "seqgen.h"
40 #include "util.h"
41 #include "timefn.h"       /* UTIL_time_t, UTIL_clockSpanMicro, UTIL_getTime */
42
43
44 /*-************************************
45  *  Constants
46  **************************************/
47 #define KB *(1U<<10)
48 #define MB *(1U<<20)
49 #define GB *(1U<<30)
50
51 static const int nbTestsDefault = 10000;
52 static const U32 g_cLevelMax_smallTests = 10;
53 #define COMPRESSIBLE_NOISE_LENGTH (10 MB)
54 #define FUZ_COMPRESSIBILITY_DEFAULT 50
55 static const U32 prime32 = 2654435761U;
56
57
58 /*-************************************
59  *  Display Macros
60  **************************************/
61 #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
62 #define DISPLAYLEVEL(l, ...)  if (g_displayLevel>=l) {                     \
63                                   DISPLAY(__VA_ARGS__);                    \
64                                   if (g_displayLevel>=4) fflush(stderr); }
65 static U32 g_displayLevel = 2;
66
67 static const U64 g_refreshRate = SEC_TO_MICRO / 6;
68 static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
69
70 #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
71             if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
72             { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
73             if (g_displayLevel>=4) fflush(stderr); } }
74
75 static U64 g_clockTime = 0;
76
77
78 /*-*******************************************************
79  *  Check macros
80  *********************************************************/
81 #undef MIN
82 #undef MAX
83 #define MIN(a,b) ((a)<(b)?(a):(b))
84 #define MAX(a,b) ((a)>(b)?(a):(b))
85 /*! FUZ_rand() :
86     @return : a 27 bits random value, from a 32-bits `seed`.
87     `seed` is also modified */
88 #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
89 static U32 FUZ_rand(U32* seedPtr)
90 {
91     static const U32 prime2 = 2246822519U;
92     U32 rand32 = *seedPtr;
93     rand32 *= prime32;
94     rand32 += prime2;
95     rand32  = FUZ_rotl32(rand32, 13);
96     *seedPtr = rand32;
97     return rand32 >> 5;
98 }
99
100 #define CHECK(cond, ...) {                                   \
101     if (cond) {                                              \
102         DISPLAY("Error => ");                                \
103         DISPLAY(__VA_ARGS__);                                \
104         DISPLAY(" (seed %u, test nb %u, line %u) \n",        \
105                 (unsigned)seed, testNb, __LINE__);           \
106         goto _output_error;                                  \
107 }   }
108
109 #define CHECK_Z(f) {                                         \
110     size_t const err = f;                                    \
111     CHECK(ZSTD_isError(err), "%s : %s ",                     \
112           #f, ZSTD_getErrorName(err));                       \
113 }
114
115 #define CHECK_RET(ret, cond, ...) {                          \
116     if (cond) {                                              \
117         DISPLAY("Error %llu => ", (unsigned long long)ret);  \
118         DISPLAY(__VA_ARGS__);                                \
119         DISPLAY(" (line %u)\n", __LINE__);                   \
120         return ret;                                          \
121 }   }
122
123 #define CHECK_RET_Z(f) {                                     \
124     size_t const err = f;                                    \
125     CHECK_RET(err, ZSTD_isError(err), "%s : %s ",            \
126           #f, ZSTD_getErrorName(err));                       \
127 }
128
129
130 /*======================================================
131  *   Basic Unit tests
132  *======================================================*/
133
134 typedef struct {
135     void* start;
136     size_t size;
137     size_t filled;
138 } buffer_t;
139
140 static const buffer_t kBuffNull = { NULL, 0 , 0 };
141
142 static void FUZ_freeDictionary(buffer_t dict)
143 {
144     free(dict.start);
145 }
146
147 static buffer_t FUZ_createDictionary(const void* src, size_t srcSize, size_t blockSize, size_t requestedDictSize)
148 {
149     buffer_t dict = kBuffNull;
150     size_t const nbBlocks = (srcSize + (blockSize-1)) / blockSize;
151     size_t* const blockSizes = (size_t*)malloc(nbBlocks * sizeof(size_t));
152     if (!blockSizes) return kBuffNull;
153     dict.start = malloc(requestedDictSize);
154     if (!dict.start) { free(blockSizes); return kBuffNull; }
155     {   size_t nb;
156         for (nb=0; nb<nbBlocks-1; nb++) blockSizes[nb] = blockSize;
157         blockSizes[nbBlocks-1] = srcSize - (blockSize * (nbBlocks-1));
158     }
159     {   size_t const dictSize = ZDICT_trainFromBuffer(dict.start, requestedDictSize, src, blockSizes, (unsigned)nbBlocks);
160         free(blockSizes);
161         if (ZDICT_isError(dictSize)) { FUZ_freeDictionary(dict); return kBuffNull; }
162         dict.size = requestedDictSize;
163         dict.filled = dictSize;
164         return dict;
165     }
166 }
167
168 /* Round trips data and updates xxh with the decompressed data produced */
169 static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
170                             XXH64_state_t* xxh, void* data, size_t size,
171                             ZSTD_EndDirective endOp)
172 {
173     static BYTE compressed[1024];
174     static BYTE uncompressed[1024];
175
176     ZSTD_inBuffer cin = {data, size, 0};
177     size_t cret;
178
179     do {
180         ZSTD_outBuffer cout = { compressed, sizeof(compressed), 0 };
181         ZSTD_inBuffer din   = { compressed, 0, 0 };
182         ZSTD_outBuffer dout = { uncompressed, 0, 0 };
183
184         cret = ZSTD_compressStream2(cctx, &cout, &cin, endOp);
185         if (ZSTD_isError(cret))
186             return cret;
187
188         din.size = cout.pos;
189         while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
190             size_t dret;
191
192             dout.pos = 0;
193             dout.size = sizeof(uncompressed);
194             dret = ZSTD_decompressStream(dctx, &dout, &din);
195             if (ZSTD_isError(dret))
196                 return dret;
197             XXH64_update(xxh, dout.dst, dout.pos);
198             if (dret == 0)
199                 break;
200         }
201     } while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
202     return 0;
203 }
204
205 /* Generates some data and round trips it */
206 static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
207                                     XXH64_state_t* xxh, SEQ_stream* seq,
208                                     SEQ_gen_type type, unsigned value)
209 {
210     static BYTE data[1024];
211     size_t gen;
212
213     do {
214         SEQ_outBuffer sout = {data, sizeof(data), 0};
215         size_t ret;
216         gen = SEQ_gen(seq, type, value, &sout);
217
218         ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
219         if (ZSTD_isError(ret))
220             return ret;
221     } while (gen != 0);
222
223     return 0;
224 }
225
226 static size_t getCCtxParams(ZSTD_CCtx* zc, ZSTD_parameters* savedParams)
227 {
228     int value;
229     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_windowLog, (int*)&savedParams->cParams.windowLog));
230     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_hashLog, (int*)&savedParams->cParams.hashLog));
231     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_chainLog, (int*)&savedParams->cParams.chainLog));
232     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_searchLog, (int*)&savedParams->cParams.searchLog));
233     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_minMatch, (int*)&savedParams->cParams.minMatch));
234     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetLength, (int*)&savedParams->cParams.targetLength));
235     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_strategy, &value));
236     savedParams->cParams.strategy = value;
237
238     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_checksumFlag, &savedParams->fParams.checksumFlag));
239     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_contentSizeFlag, &savedParams->fParams.contentSizeFlag));
240     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_dictIDFlag, &value));
241     savedParams->fParams.noDictIDFlag = !value;
242     return 0;
243 }
244
245 static U32 badParameters(ZSTD_CCtx* zc, ZSTD_parameters const savedParams)
246 {
247     ZSTD_parameters params;
248     if (ZSTD_isError(getCCtxParams(zc, &params))) return 10;
249     CHECK_RET(1, params.cParams.windowLog != savedParams.cParams.windowLog, "windowLog");
250     CHECK_RET(2, params.cParams.hashLog != savedParams.cParams.hashLog, "hashLog");
251     CHECK_RET(3, params.cParams.chainLog != savedParams.cParams.chainLog, "chainLog");
252     CHECK_RET(4, params.cParams.searchLog != savedParams.cParams.searchLog, "searchLog");
253     CHECK_RET(5, params.cParams.minMatch != savedParams.cParams.minMatch, "minMatch");
254     CHECK_RET(6, params.cParams.targetLength != savedParams.cParams.targetLength, "targetLength");
255
256     CHECK_RET(7, params.fParams.checksumFlag != savedParams.fParams.checksumFlag, "checksumFlag");
257     CHECK_RET(8, params.fParams.contentSizeFlag != savedParams.fParams.contentSizeFlag, "contentSizeFlag");
258     CHECK_RET(9, params.fParams.noDictIDFlag != savedParams.fParams.noDictIDFlag, "noDictIDFlag");
259     return 0;
260 }
261
262 static int basicUnitTests(U32 seed, double compressibility)
263 {
264     size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
265     void* CNBuffer = malloc(CNBufferSize);
266     size_t const skippableFrameSize = 200 KB;
267     size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
268     void* compressedBuffer = malloc(compressedBufferSize);
269     size_t const decodedBufferSize = CNBufferSize;
270     void* decodedBuffer = malloc(decodedBufferSize);
271     size_t cSize;
272     int testResult = 0;
273     int testNb = 1;
274     U32 coreSeed = 0;  /* this name to conform with CHECK_Z macro display */
275     ZSTD_CStream* zc = ZSTD_createCStream();
276     ZSTD_DStream* zd = ZSTD_createDStream();
277     ZSTDMT_CCtx* mtctx = ZSTDMT_createCCtx(2);
278
279     ZSTD_inBuffer  inBuff, inBuff2;
280     ZSTD_outBuffer outBuff;
281     buffer_t dictionary = kBuffNull;
282     size_t const dictSize = 128 KB;
283     unsigned dictID = 0;
284
285     /* Create compressible test buffer */
286     if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd) {
287         DISPLAY("Not enough memory, aborting \n");
288         goto _output_error;
289     }
290     RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
291
292     /* Create dictionary */
293     DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
294     dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
295     if (!dictionary.start) {
296         DISPLAY("Error creating dictionary, aborting \n");
297         goto _output_error;
298     }
299     dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
300
301     /* Basic compression test */
302     DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
303     CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
304     outBuff.dst = (char*)(compressedBuffer);
305     outBuff.size = compressedBufferSize;
306     outBuff.pos = 0;
307     inBuff.src = CNBuffer;
308     inBuff.size = CNBufferSize;
309     inBuff.pos = 0;
310     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
311     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
312     { size_t const r = ZSTD_endStream(zc, &outBuff);
313       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
314     DISPLAYLEVEL(3, "OK (%u bytes)\n", (unsigned)outBuff.pos);
315
316     /* generate skippable frame */
317     MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
318     MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
319     cSize = skippableFrameSize + 8;
320
321     /* Basic compression test using dict */
322     DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
323     CHECK_Z( ZSTD_initCStream_usingDict(zc, CNBuffer, dictSize, 1 /* cLevel */) );
324     outBuff.dst = (char*)(compressedBuffer)+cSize;
325     assert(compressedBufferSize > cSize);
326     outBuff.size = compressedBufferSize - cSize;
327     outBuff.pos = 0;
328     inBuff.src = CNBuffer;
329     inBuff.size = CNBufferSize;
330     inBuff.pos = 0;
331     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
332     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
333     { size_t const r = ZSTD_endStream(zc, &outBuff);
334       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
335     cSize += outBuff.pos;
336     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
337                     (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
338
339     /* context size functions */
340     DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
341     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
342         size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
343         size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
344         if (ZSTD_isError(cstreamSize)) goto _output_error;
345         if (ZSTD_isError(cdictSize)) goto _output_error;
346         DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)(cstreamSize + cdictSize));
347     }
348
349     /* context size functions */
350     DISPLAYLEVEL(3, "test%3i : estimate CStream size using CCtxParams : ", testNb++);
351     {   ZSTD_CCtx_params* const params = ZSTD_createCCtxParams();
352         size_t cstreamSize, cctxSize;
353         CHECK_Z( ZSTD_CCtxParams_setParameter(params, ZSTD_c_compressionLevel, 19) );
354         cstreamSize = ZSTD_estimateCStreamSize_usingCCtxParams(params);
355         CHECK_Z(cstreamSize);
356         cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
357         CHECK_Z(cctxSize);
358         if (cstreamSize <= cctxSize + 2 * ZSTD_BLOCKSIZE_MAX) goto _output_error;
359         ZSTD_freeCCtxParams(params);
360         DISPLAYLEVEL(3, "OK \n");
361     }
362
363     DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
364     {   size_t const s = ZSTD_sizeof_CStream(zc);
365         if (ZSTD_isError(s)) goto _output_error;
366         DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
367     }
368
369     /* Attempt bad compression parameters */
370     DISPLAYLEVEL(3, "test%3i : use bad compression parameters : ", testNb++);
371     {   size_t r;
372         ZSTD_parameters params = ZSTD_getParams(1, 0, 0);
373         params.cParams.minMatch = 2;
374         r = ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
375         if (!ZSTD_isError(r)) goto _output_error;
376         DISPLAYLEVEL(3, "init error : %s \n", ZSTD_getErrorName(r));
377     }
378
379     /* skippable frame test */
380     DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
381     CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
382     inBuff.src = compressedBuffer;
383     inBuff.size = cSize;
384     inBuff.pos = 0;
385     outBuff.dst = decodedBuffer;
386     outBuff.size = CNBufferSize;
387     outBuff.pos = 0;
388     {   size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
389         DISPLAYLEVEL(5, " ( ZSTD_decompressStream => %u ) ", (unsigned)r);
390         if (r != 0) goto _output_error;
391     }
392     if (outBuff.pos != 0) goto _output_error;   /* skippable frame output len is 0 */
393     DISPLAYLEVEL(3, "OK \n");
394
395     /* Basic decompression test */
396     inBuff2 = inBuff;
397     DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
398     ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
399     CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT+1) );  /* large limit */
400     { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
401       if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
402     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
403     if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
404     DISPLAYLEVEL(3, "OK \n");
405
406     /* Re-use without init */
407     DISPLAYLEVEL(3, "test%3i : decompress again without init (re-use previous settings): ", testNb++);
408     outBuff.pos = 0;
409     { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2);
410       if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
411     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
412     if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
413     DISPLAYLEVEL(3, "OK \n");
414
415     /* check regenerated data is byte exact */
416     DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
417     {   size_t i;
418         for (i=0; i<CNBufferSize; i++) {
419             if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
420     }   }
421     DISPLAYLEVEL(3, "OK \n");
422
423     /* context size functions */
424     DISPLAYLEVEL(3, "test%3i : estimate DStream size : ", testNb++);
425     {   ZSTD_frameHeader fhi;
426         const void* cStart = (char*)compressedBuffer + (skippableFrameSize + 8);
427         size_t const gfhError = ZSTD_getFrameHeader(&fhi, cStart, cSize);
428         if (gfhError!=0) goto _output_error;
429         DISPLAYLEVEL(5, " (windowSize : %u) ", (unsigned)fhi.windowSize);
430         {   size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
431                             /* uses ZSTD_initDStream_usingDict() */
432                            + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
433             if (ZSTD_isError(s)) goto _output_error;
434             DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
435     }   }
436
437     DISPLAYLEVEL(3, "test%3i : check actual DStream size : ", testNb++);
438     { size_t const s = ZSTD_sizeof_DStream(zd);
439       if (ZSTD_isError(s)) goto _output_error;
440       DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
441     }
442
443     /* Decompression by small increment */
444     DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
445     {   /* skippable frame */
446         size_t r = 1;
447         ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
448         inBuff.src = compressedBuffer;
449         outBuff.dst = decodedBuffer;
450         inBuff.pos = 0;
451         outBuff.pos = 0;
452         while (r) {   /* skippable frame */
453             size_t const inSize = (FUZ_rand(&coreSeed) & 15) + 1;
454             size_t const outSize = (FUZ_rand(&coreSeed) & 15) + 1;
455             inBuff.size = inBuff.pos + inSize;
456             outBuff.size = outBuff.pos + outSize;
457             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
458             if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream on skippable frame error : %s \n", ZSTD_getErrorName(r));
459             if (ZSTD_isError(r)) goto _output_error;
460         }
461         /* normal frame */
462         ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
463         r=1;
464         while (r) {
465             size_t const inSize = FUZ_rand(&coreSeed) & 15;
466             size_t const outSize = (FUZ_rand(&coreSeed) & 15) + (!inSize);   /* avoid having both sizes at 0 => would trigger a no_forward_progress error */
467             inBuff.size = inBuff.pos + inSize;
468             outBuff.size = outBuff.pos + outSize;
469             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
470             if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(r));
471             if (ZSTD_isError(r)) goto _output_error;
472         }
473     }
474     if (outBuff.pos != CNBufferSize) DISPLAYLEVEL(4, "outBuff.pos != CNBufferSize : should have regenerated same amount ! \n");
475     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
476     if (inBuff.pos != cSize) DISPLAYLEVEL(4, "inBuff.pos != cSize : should have real all input ! \n");
477     if (inBuff.pos != cSize) goto _output_error;   /* should have read the entire frame */
478     DISPLAYLEVEL(3, "OK \n");
479
480     /* check regenerated data is byte exact */
481     DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
482     {   size_t i;
483         for (i=0; i<CNBufferSize; i++) {
484             if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;;
485     }   }
486     DISPLAYLEVEL(3, "OK \n");
487
488     /* Decompression forward progress */
489     DISPLAYLEVEL(3, "test%3i : generate error when ZSTD_decompressStream() doesn't progress : ", testNb++);
490     {   /* skippable frame */
491         size_t r = 0;
492         int decNb = 0;
493         int const maxDec = 100;
494         inBuff.src = compressedBuffer;
495         inBuff.size = cSize;
496         inBuff.pos = 0;
497
498         outBuff.dst = decodedBuffer;
499         outBuff.pos = 0;
500         outBuff.size = CNBufferSize-1;   /* 1 byte missing */
501
502         for (decNb=0; decNb<maxDec; decNb++) {
503             if (r==0) ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
504             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
505             if (ZSTD_isError(r)) break;
506         }
507         if (!ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream should have triggered a no_forward_progress error \n");
508         if (!ZSTD_isError(r)) goto _output_error;   /* should have triggered no_forward_progress error */
509     }
510     DISPLAYLEVEL(3, "OK \n");
511
512     /* _srcSize compression test */
513     DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
514     CHECK_Z( ZSTD_initCStream_srcSize(zc, 1, CNBufferSize) );
515     outBuff.dst = (char*)(compressedBuffer);
516     outBuff.size = compressedBufferSize;
517     outBuff.pos = 0;
518     inBuff.src = CNBuffer;
519     inBuff.size = CNBufferSize;
520     inBuff.pos = 0;
521     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
522     CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
523     {   size_t const r = ZSTD_endStream(zc, &outBuff);
524         CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
525     }
526     {   unsigned long long origSize = ZSTD_findDecompressedSize(outBuff.dst, outBuff.pos);
527         CHECK(origSize == ZSTD_CONTENTSIZE_UNKNOWN, "Unknown!");
528         CHECK((size_t)origSize != CNBufferSize, "Exact original size must be present (got %llu)", origSize);
529     }
530     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
531
532     /* wrong _srcSize compression test */
533     DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
534     ZSTD_initCStream_srcSize(zc, 1, CNBufferSize+1);
535     outBuff.dst = (char*)(compressedBuffer);
536     outBuff.size = compressedBufferSize;
537     outBuff.pos = 0;
538     inBuff.src = CNBuffer;
539     inBuff.size = CNBufferSize;
540     inBuff.pos = 0;
541     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
542     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
543     { size_t const r = ZSTD_endStream(zc, &outBuff);
544       if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
545       DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
546
547     /* wrong _srcSize compression test */
548     DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
549     ZSTD_initCStream_srcSize(zc, 1, CNBufferSize-1);
550     outBuff.dst = (char*)(compressedBuffer);
551     outBuff.size = compressedBufferSize;
552     outBuff.pos = 0;
553     inBuff.src = CNBuffer;
554     inBuff.size = CNBufferSize;
555     inBuff.pos = 0;
556     {   size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
557         if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
558         DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
559     }
560
561     DISPLAYLEVEL(3, "test%3i : wrong srcSize !contentSizeFlag : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
562     {   ZSTD_parameters params = ZSTD_getParams(1, CNBufferSize, 0);
563         params.fParams.contentSizeFlag = 0;
564         CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, CNBufferSize - MIN(CNBufferSize, 200 KB)));
565         outBuff.dst = (char*)compressedBuffer;
566         outBuff.size = compressedBufferSize;
567         outBuff.pos = 0;
568         inBuff.src = CNBuffer;
569         inBuff.size = CNBufferSize;
570         inBuff.pos = 0;
571         {   size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
572             if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
573             DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
574     }   }
575
576     /* Complex context re-use scenario */
577     DISPLAYLEVEL(3, "test%3i : context re-use : ", testNb++);
578     ZSTD_freeCStream(zc);
579     zc = ZSTD_createCStream();
580     if (zc==NULL) goto _output_error;   /* memory allocation issue */
581     /* use 1 */
582     {   size_t const inSize = 513;
583         DISPLAYLEVEL(5, "use1 ");
584         ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize);   /* needs btopt + search3 to trigger hashLog3 */
585         inBuff.src = CNBuffer;
586         inBuff.size = inSize;
587         inBuff.pos = 0;
588         outBuff.dst = (char*)(compressedBuffer)+cSize;
589         outBuff.size = ZSTD_compressBound(inSize);
590         outBuff.pos = 0;
591         DISPLAYLEVEL(5, "compress1 ");
592         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
593         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
594         DISPLAYLEVEL(5, "end1 ");
595         { size_t const r = ZSTD_endStream(zc, &outBuff);
596             if (r != 0) goto _output_error; }  /* error, or some data not flushed */
597     }
598     /* use 2 */
599     {   size_t const inSize = 1025;   /* will not continue, because tables auto-adjust and are therefore different size */
600         DISPLAYLEVEL(5, "use2 ");
601         ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize);   /* needs btopt + search3 to trigger hashLog3 */
602         inBuff.src = CNBuffer;
603         inBuff.size = inSize;
604         inBuff.pos = 0;
605         outBuff.dst = (char*)(compressedBuffer)+cSize;
606         outBuff.size = ZSTD_compressBound(inSize);
607         outBuff.pos = 0;
608         DISPLAYLEVEL(5, "compress2 ");
609         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
610         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
611         DISPLAYLEVEL(5, "end2 ");
612         { size_t const r = ZSTD_endStream(zc, &outBuff);
613             if (r != 0) goto _output_error; }  /* error, or some data not flushed */
614     }
615     DISPLAYLEVEL(3, "OK \n");
616
617     /* CDict scenario */
618     DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
619     {   ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
620         size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
621         DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (unsigned)initError);
622         if (ZSTD_isError(initError)) goto _output_error;
623         outBuff.dst = compressedBuffer;
624         outBuff.size = compressedBufferSize;
625         outBuff.pos = 0;
626         inBuff.src = CNBuffer;
627         inBuff.size = CNBufferSize;
628         inBuff.pos = 0;
629         DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
630         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
631         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
632         {   size_t const r = ZSTD_endStream(zc, &outBuff);
633             DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (unsigned)r);
634             if (r != 0) goto _output_error;  /* error, or some data not flushed */
635         }
636         cSize = outBuff.pos;
637         ZSTD_freeCDict(cdict);
638         DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
639     }
640
641     DISPLAYLEVEL(3, "test%3i : check CStream size : ", testNb++);
642     { size_t const s = ZSTD_sizeof_CStream(zc);
643       if (ZSTD_isError(s)) goto _output_error;
644       DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
645     }
646
647     DISPLAYLEVEL(4, "test%3i : check Dictionary ID : ", testNb++);
648     { unsigned const dID = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
649       if (dID != dictID) goto _output_error;
650       DISPLAYLEVEL(4, "OK (%u) \n", dID);
651     }
652
653     /* DDict scenario */
654     DISPLAYLEVEL(3, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (unsigned)CNBufferSize);
655     {   ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
656         size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
657         if (ZSTD_isError(initError)) goto _output_error;
658         outBuff.dst = decodedBuffer;
659         outBuff.size = CNBufferSize;
660         outBuff.pos = 0;
661         inBuff.src = compressedBuffer;
662         inBuff.size = cSize;
663         inBuff.pos = 0;
664         { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
665           if (r != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
666         if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
667         if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
668         ZSTD_freeDDict(ddict);
669         DISPLAYLEVEL(3, "OK \n");
670     }
671
672     /* Memory restriction */
673     DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
674     ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
675     CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, 10) );  /* too small limit */
676     outBuff.dst = decodedBuffer;
677     outBuff.size = CNBufferSize;
678     outBuff.pos = 0;
679     inBuff.src = compressedBuffer;
680     inBuff.size = cSize;
681     inBuff.pos = 0;
682     { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
683       if (!ZSTD_isError(r)) goto _output_error;  /* must fail : frame requires > 100 bytes */
684       DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
685     ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters);   /* leave zd in good shape for next tests */
686
687     DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
688     {   ZSTD_DCtx* const dctx = ZSTD_createDCtx();
689         int const maxLevel = 16;   /* first level with zstd_opt */
690         int level;
691         assert(maxLevel < ZSTD_maxCLevel());
692         CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
693         for (level = 1; level <= maxLevel; ++level) {
694             ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
695             size_t const maxSize = MIN(1 MB, CNBufferSize);
696             size_t size;
697             for (size = 512; size <= maxSize; size <<= 1) {
698                 U64 const crcOrig = XXH64(CNBuffer, size, 0);
699                 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
700                 ZSTD_parameters savedParams;
701                 getCCtxParams(cctx, &savedParams);
702                 outBuff.dst = compressedBuffer;
703                 outBuff.size = compressedBufferSize;
704                 outBuff.pos = 0;
705                 inBuff.src = CNBuffer;
706                 inBuff.size = size;
707                 inBuff.pos = 0;
708                 CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
709                 CHECK_Z(ZSTD_compressStream2(cctx, &outBuff, &inBuff, ZSTD_e_end));
710                 CHECK(badParameters(cctx, savedParams), "Bad CCtx params");
711                 if (inBuff.pos != inBuff.size) goto _output_error;
712                 {   ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
713                     ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
714                     CHECK_Z( ZSTD_decompressStream(dctx, &decOut, &decIn) );
715                     if (decIn.pos != decIn.size) goto _output_error;
716                     if (decOut.pos != size) goto _output_error;
717                     {   U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
718                         if (crcDec != crcOrig) goto _output_error;
719                 }   }
720                 ZSTD_freeCCtx(cctx);
721             }
722             ZSTD_freeCDict(cdict);
723         }
724         ZSTD_freeDCtx(dctx);
725     }
726     DISPLAYLEVEL(3, "OK\n");
727
728     ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
729     CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dictionary.start, dictionary.filled) );
730     cSize = ZSTD_compress2(zc, compressedBuffer, compressedBufferSize, CNBuffer, MIN(CNBufferSize, 100 KB));
731     CHECK_Z(cSize);
732     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with dictionary : ", testNb++);
733     {
734         ZSTD_DCtx* dctx = ZSTD_createDCtx();
735         /* We should fail to decompress without a dictionary. */
736         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
737         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
738             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
739             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
740             if (!ZSTD_isError(ret)) goto _output_error;
741         }
742         /* We should succeed to decompress with the dictionary. */
743         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
744         CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
745         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
746             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
747             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
748             if (in.pos != in.size) goto _output_error;
749         }
750         /* The dictionary should presist across calls. */
751         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
752             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
753             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
754             if (in.pos != in.size) goto _output_error;
755         }
756         /* The dictionary should not be cleared by ZSTD_reset_session_only. */
757         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
758         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
759             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
760             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
761             if (in.pos != in.size) goto _output_error;
762         }
763         /* When we reset the context the dictionary is cleared. */
764         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
765         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
766             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
767             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
768             if (!ZSTD_isError(ret)) goto _output_error;
769         }
770         ZSTD_freeDCtx(dctx);
771     }
772     DISPLAYLEVEL(3, "OK \n");
773
774     DISPLAYLEVEL(3, "test%3i : ZSTD_resetDStream() with dictionary : ", testNb++);
775     {
776         ZSTD_DCtx* dctx = ZSTD_createDCtx();
777         /* We should succeed to decompress with the dictionary. */
778         ZSTD_resetDStream(dctx);
779         CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
780         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
781             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
782             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
783             if (in.pos != in.size) goto _output_error;
784         }
785         /* The dictionary should not be cleared by ZSTD_resetDStream(). */
786         ZSTD_resetDStream(dctx);
787         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
788             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
789             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
790             if (in.pos != in.size) goto _output_error;
791         }
792         /* The dictionary should be cleared by ZSTD_initDStream(). */
793         CHECK_Z( ZSTD_initDStream(dctx) );
794         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
795             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
796             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
797             if (!ZSTD_isError(ret)) goto _output_error;
798         }
799         ZSTD_freeDCtx(dctx);
800     }
801     DISPLAYLEVEL(3, "OK \n");
802
803     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with ddict : ", testNb++);
804     {
805         ZSTD_DCtx* dctx = ZSTD_createDCtx();
806         ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
807         /* We should succeed to decompress with the ddict. */
808         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
809         CHECK_Z( ZSTD_DCtx_refDDict(dctx, ddict) );
810         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
811             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
812             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
813             if (in.pos != in.size) goto _output_error;
814         }
815         /* The ddict should presist across calls. */
816         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
817             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
818             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
819             if (in.pos != in.size) goto _output_error;
820         }
821         /* When we reset the context the ddict is cleared. */
822         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
823         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
824             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
825             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
826             if (!ZSTD_isError(ret)) goto _output_error;
827         }
828         ZSTD_freeDCtx(dctx);
829         ZSTD_freeDDict(ddict);
830     }
831     DISPLAYLEVEL(3, "OK \n");
832
833     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressDCtx() with prefix : ", testNb++);
834     {
835         ZSTD_DCtx* dctx = ZSTD_createDCtx();
836         /* We should succeed to decompress with the prefix. */
837         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
838         CHECK_Z( ZSTD_DCtx_refPrefix_advanced(dctx, dictionary.start, dictionary.filled, ZSTD_dct_auto) );
839         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
840             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
841             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
842             if (in.pos != in.size) goto _output_error;
843         }
844         /* The prefix should be cleared after the first compression. */
845         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
846             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
847             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
848             if (!ZSTD_isError(ret)) goto _output_error;
849         }
850         ZSTD_freeDCtx(dctx);
851     }
852     DISPLAYLEVEL(3, "OK \n");
853
854     DISPLAYLEVEL(3, "test%3i : ZSTD_initDStream*() with dictionary : ", testNb++);
855     {
856         ZSTD_DCtx* dctx = ZSTD_createDCtx();
857         ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
858         size_t ret;
859         /* We should succeed to decompress with the dictionary. */
860         CHECK_Z( ZSTD_initDStream_usingDict(dctx, dictionary.start, dictionary.filled) );
861         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
862         /* The dictionary should presist across calls. */
863         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
864         /* We should succeed to decompress with the ddict. */
865         CHECK_Z( ZSTD_initDStream_usingDDict(dctx, ddict) );
866         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
867         /* The ddict should presist across calls. */
868         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
869         /* When we reset the context the ddict is cleared. */
870         CHECK_Z( ZSTD_initDStream(dctx) );
871         ret = ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize);
872         if (!ZSTD_isError(ret)) goto _output_error;
873         ZSTD_freeDCtx(dctx);
874         ZSTD_freeDDict(ddict);
875     }
876     DISPLAYLEVEL(3, "OK \n");
877
878     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
879     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
880         ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
881         ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem);
882         size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
883         if (ZSTD_isError(initError)) goto _output_error;
884         outBuff.dst = compressedBuffer;
885         outBuff.size = compressedBufferSize;
886         outBuff.pos = 0;
887         inBuff.src = CNBuffer;
888         inBuff.size = CNBufferSize;
889         inBuff.pos = 0;
890         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
891         if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
892         { size_t const r = ZSTD_endStream(zc, &outBuff);
893           if (r != 0) goto _output_error; }  /* error, or some data not flushed */
894         cSize = outBuff.pos;
895         ZSTD_freeCDict(cdict);
896         DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
897     }
898
899     DISPLAYLEVEL(3, "test%3i : try retrieving dictID from frame : ", testNb++);
900     {   U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
901         if (did != 0) goto _output_error;
902     }
903     DISPLAYLEVEL(3, "OK (not detected) \n");
904
905     DISPLAYLEVEL(3, "test%3i : decompress without dictionary : ", testNb++);
906     {   size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
907         if (!ZSTD_isError(r)) goto _output_error;  /* must fail : dictionary not used */
908         DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
909     }
910
911     DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
912     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
913     outBuff.dst = compressedBuffer;
914     outBuff.size = compressedBufferSize;
915     outBuff.pos = 0;
916     inBuff.src = CNBuffer;
917     inBuff.size = CNBufferSize;
918     inBuff.pos = 0;
919     CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
920     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
921     cSize = outBuff.pos;
922     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
923
924     DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
925     CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
926     outBuff.dst = decodedBuffer;
927     outBuff.size = CNBufferSize;
928     outBuff.pos = 0;
929     inBuff.src = compressedBuffer;
930     inBuff.size = cSize;
931     inBuff.pos = 0;
932     CHECK_Z( ZSTD_decompressStream(zd, &outBuff, &inBuff) );
933     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
934     if (outBuff.pos != CNBufferSize) goto _output_error;  /* must regenerate whole input */
935     DISPLAYLEVEL(3, "OK \n");
936
937     DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
938     {   size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
939         if (!ZSTD_isError(r)) goto _output_error;  /* must fail : dictionary not used */
940         DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
941     }
942
943     DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compressStream2 : ", testNb++);
944     outBuff.dst = compressedBuffer;
945     outBuff.size = compressedBufferSize;
946     outBuff.pos = 0;
947     inBuff.src = CNBuffer;
948     inBuff.size = CNBufferSize;
949     inBuff.pos = 0;
950     CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
951     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
952     cSize = outBuff.pos;
953     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
954
955     DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
956     CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
957     DISPLAYLEVEL(3, "OK \n");
958
959     /* Empty srcSize */
960     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
961     {   ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
962         params.fParams.contentSizeFlag = 1;
963         CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0 /* pledgedSrcSize==0 means "empty" when params.fParams.contentSizeFlag is set */) );
964     } /* cstream advanced shall write content size = 0 */
965     outBuff.dst = compressedBuffer;
966     outBuff.size = compressedBufferSize;
967     outBuff.pos = 0;
968     inBuff.src = CNBuffer;
969     inBuff.size = 0;
970     inBuff.pos = 0;
971     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
972     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
973     cSize = outBuff.pos;
974     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
975     DISPLAYLEVEL(3, "OK \n");
976
977     DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly : ", testNb++);
978     {   ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
979         params.fParams.contentSizeFlag = 1;
980         CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
981     } /* cstream advanced shall write content size = 0 */
982     inBuff.src = CNBuffer;
983     inBuff.size = 0;
984     inBuff.pos = 0;
985     outBuff.dst = compressedBuffer;
986     outBuff.size = compressedBufferSize;
987     outBuff.pos = 0;
988     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
989     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
990     cSize = outBuff.pos;
991     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
992
993     ZSTD_resetCStream(zc, 0); /* resetCStream should treat 0 as unknown */
994     outBuff.dst = compressedBuffer;
995     outBuff.size = compressedBufferSize;
996     outBuff.pos = 0;
997     inBuff.src = CNBuffer;
998     inBuff.size = 0;
999     inBuff.pos = 0;
1000     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1001     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1002     cSize = outBuff.pos;
1003     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
1004     DISPLAYLEVEL(3, "OK \n");
1005
1006     /* Basic multithreading compression test */
1007     DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
1008     {   ZSTD_parameters const params = ZSTD_getParams(1, 0, 0);
1009         int jobSize;
1010         CHECK_Z( ZSTDMT_getMTCtxParameter(mtctx, ZSTDMT_p_jobSize, &jobSize));
1011         CHECK(jobSize != 0, "job size non-zero");
1012         CHECK_Z( ZSTDMT_initCStream_advanced(mtctx, CNBuffer, dictSize, params, CNBufferSize) );
1013         CHECK_Z( ZSTDMT_getMTCtxParameter(mtctx, ZSTDMT_p_jobSize, &jobSize));
1014         CHECK(jobSize != 0, "job size non-zero");
1015     }
1016     outBuff.dst = compressedBuffer;
1017     outBuff.size = compressedBufferSize;
1018     outBuff.pos = 0;
1019     inBuff.src = CNBuffer;
1020     inBuff.size = CNBufferSize;
1021     inBuff.pos = 0;
1022     {   size_t const compressResult = ZSTDMT_compressStream_generic(mtctx, &outBuff, &inBuff, ZSTD_e_end);
1023         if (compressResult != 0) goto _output_error;  /* compression must be completed in a single round */
1024     }
1025     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1026     {   size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
1027         if (compressedSize != outBuff.pos) goto _output_error;  /* must be a full valid frame */
1028     }
1029     DISPLAYLEVEL(3, "OK \n");
1030
1031     /* Complex multithreading + dictionary test */
1032     {   U32 const nbWorkers = 2;
1033         size_t const jobSize = 4 * 1 MB;
1034         size_t const srcSize = jobSize * nbWorkers;  /* we want each job to have predictable size */
1035         size_t const segLength = 2 KB;
1036         size_t const offset = 600 KB;   /* must be larger than window defined in cdict */
1037         size_t const start = jobSize + (offset-1);
1038         const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
1039         BYTE* const dst = (BYTE*)CNBuffer + start - offset;
1040         DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (unsigned)srcSize);
1041         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 3) );
1042         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers) );
1043         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_jobSize, jobSize) );
1044         assert(start > offset);
1045         assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
1046         memcpy(dst, srcToCopy, segLength);   /* create a long repetition at long distance for job 2 */
1047         outBuff.dst = compressedBuffer;
1048         outBuff.size = compressedBufferSize;
1049         outBuff.pos = 0;
1050         inBuff.src = CNBuffer;
1051         inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
1052         inBuff.pos = 0;
1053     }
1054     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled);   /* intentionally lies on estimatedSrcSize, to push cdict into targeting a small window size */
1055         ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
1056         DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
1057         CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
1058         CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
1059         CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );  /* do not keep a reference to cdict, as its lifetime ends */
1060         ZSTD_freeCDict(cdict);
1061     }
1062     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1063     cSize = outBuff.pos;
1064     DISPLAYLEVEL(3, "OK \n");
1065
1066     DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
1067     {   ZSTD_DStream* const dstream = ZSTD_createDCtx();
1068         ZSTD_frameHeader zfh;
1069         ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
1070         DISPLAYLEVEL(5, "frame windowsize = %u : ", (unsigned)zfh.windowSize);
1071         outBuff.dst = decodedBuffer;
1072         outBuff.size = CNBufferSize;
1073         outBuff.pos = 0;
1074         inBuff.src = compressedBuffer;
1075         inBuff.pos = 0;
1076         CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
1077         inBuff.size = 1;  /* avoid shortcut to single-pass mode */
1078         CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1079         inBuff.size = cSize;
1080         CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1081         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1082         ZSTD_freeDStream(dstream);
1083     }
1084     DISPLAYLEVEL(3, "OK \n");
1085
1086     DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
1087     {   unsigned const kMaxWindowLog = 24;
1088         unsigned value;
1089         ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
1090         ZSTD_CDict* cdict;
1091         ZSTD_DDict* ddict;
1092         SEQ_stream seq = SEQ_initStream(0x87654321);
1093         SEQ_gen_type type;
1094         XXH64_state_t xxh;
1095
1096         XXH64_reset(&xxh, 0);
1097         cParams.windowLog = kMaxWindowLog;
1098         cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
1099         ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1100
1101         if (!cdict || !ddict) goto _output_error;
1102
1103         ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
1104         ZSTD_resetDStream(zd);
1105         CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1106         CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
1107         CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, kMaxWindowLog));
1108         /* Test all values < 300 */
1109         for (value = 0; value < 300; ++value) {
1110             for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1111                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1112             }
1113         }
1114         /* Test values 2^8 to 2^17 */
1115         for (value = (1 << 8); value < (1 << 17); value <<= 1) {
1116             for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1117                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1118                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
1119             }
1120         }
1121         /* Test offset values up to the max window log */
1122         for (value = 8; value <= kMaxWindowLog; ++value) {
1123             CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
1124         }
1125
1126         CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
1127         CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
1128
1129         ZSTD_freeCDict(cdict);
1130         ZSTD_freeDDict(ddict);
1131     }
1132     DISPLAYLEVEL(3, "OK \n");
1133
1134     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_srcSize sets requestedParams : ", testNb++);
1135     {   int level;
1136         CHECK_Z(ZSTD_initCStream_srcSize(zc, 11, ZSTD_CONTENTSIZE_UNKNOWN));
1137         CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
1138         CHECK(level != 11, "Compression level does not match");
1139         ZSTD_resetCStream(zc, ZSTD_CONTENTSIZE_UNKNOWN);
1140         CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
1141         CHECK(level != 11, "Compression level does not match");
1142     }
1143     DISPLAYLEVEL(3, "OK \n");
1144
1145     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced sets requestedParams : ", testNb++);
1146     {   ZSTD_parameters const params = ZSTD_getParams(9, 0, 0);
1147         CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN));
1148         CHECK(badParameters(zc, params), "Compression parameters do not match");
1149         ZSTD_resetCStream(zc, ZSTD_CONTENTSIZE_UNKNOWN);
1150         CHECK(badParameters(zc, params), "Compression parameters do not match");
1151     }
1152     DISPLAYLEVEL(3, "OK \n");
1153
1154     /* Overlen overwriting window data bug */
1155     DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
1156     {   /* This test has a window size of 1024 bytes and consists of 3 blocks:
1157             1. 'a' repeated 517 times
1158             2. 'b' repeated 516 times
1159             3. a compressed block with no literals and 3 sequence commands:
1160                 litlength = 0, offset = 24, match length = 24
1161                 litlength = 0, offset = 24, match length = 3 (this one creates an overlength write of length 2*WILDCOPY_OVERLENGTH - 3)
1162                 litlength = 0, offset = 1021, match length = 3 (this one will try to read from overwritten data if the buffer is too small) */
1163
1164         const char* testCase =
1165             "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
1166             "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
1167             "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
1168         ZSTD_DStream* const zds = ZSTD_createDStream();
1169         if (zds==NULL) goto _output_error;
1170
1171         CHECK_Z( ZSTD_initDStream(zds) );
1172         inBuff.src = testCase;
1173         inBuff.size = 47;
1174         inBuff.pos = 0;
1175         outBuff.dst = decodedBuffer;
1176         outBuff.size = CNBufferSize;
1177         outBuff.pos = 0;
1178
1179         while (inBuff.pos < inBuff.size) {
1180             CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
1181         }
1182
1183         ZSTD_freeDStream(zds);
1184     }
1185     DISPLAYLEVEL(3, "OK \n");
1186
1187     DISPLAYLEVEL(3, "test%3i : dictionary + uncompressible block + reusing tables checks offset table validity: ", testNb++);
1188     {   ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1189             dictionary.start, dictionary.filled,
1190             ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1191             ZSTD_getCParams(3, 0, dictionary.filled),
1192             ZSTD_defaultCMem);
1193         const size_t inbufsize = 2 * 128 * 1024; /* 2 blocks */
1194         const size_t outbufsize = ZSTD_compressBound(inbufsize);
1195         size_t inbufpos = 0;
1196         size_t cursegmentlen;
1197         BYTE *inbuf = (BYTE *)malloc(inbufsize);
1198         BYTE *outbuf = (BYTE *)malloc(outbufsize);
1199         BYTE *checkbuf = (BYTE *)malloc(inbufsize);
1200         size_t ret;
1201
1202         CHECK(cdict == NULL, "failed to alloc cdict");
1203         CHECK(inbuf == NULL, "failed to alloc input buffer");
1204
1205         /* first block is uncompressible */
1206         cursegmentlen = 128 * 1024;
1207         RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0., 0., seed);
1208         inbufpos += cursegmentlen;
1209
1210         /* second block is compressible */
1211         cursegmentlen = 128 * 1024 - 256;
1212         RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0.05, 0., seed);
1213         inbufpos += cursegmentlen;
1214
1215         /* and includes a very long backref */
1216         cursegmentlen = 128;
1217         memcpy(inbuf + inbufpos, dictionary.start + 256, cursegmentlen);
1218         inbufpos += cursegmentlen;
1219
1220         /* and includes a very long backref */
1221         cursegmentlen = 128;
1222         memcpy(inbuf + inbufpos, dictionary.start + 128, cursegmentlen);
1223         inbufpos += cursegmentlen;
1224
1225         ret = ZSTD_compress_usingCDict(zc, outbuf, outbufsize, inbuf, inbufpos, cdict);
1226         CHECK_Z(ret);
1227
1228         ret = ZSTD_decompress_usingDict(zd, checkbuf, inbufsize, outbuf, ret, dictionary.start, dictionary.filled);
1229         CHECK_Z(ret);
1230
1231         CHECK(memcmp(inbuf, checkbuf, inbufpos), "start and finish buffers don't match");
1232
1233         ZSTD_freeCDict(cdict);
1234         free(inbuf);
1235         free(outbuf);
1236         free(checkbuf);
1237     }
1238     DISPLAYLEVEL(3, "OK \n");
1239
1240     DISPLAYLEVEL(3, "test%3i : dictionary + small blocks + reusing tables checks offset table validity: ", testNb++);
1241     {   ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1242             dictionary.start, dictionary.filled,
1243             ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1244             ZSTD_getCParams(3, 0, dictionary.filled),
1245             ZSTD_defaultCMem);
1246         ZSTD_outBuffer out = {compressedBuffer, compressedBufferSize, 0};
1247         int remainingInput = 256 * 1024;
1248         int offset;
1249
1250         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1251         CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1252         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
1253         /* Write a bunch of 6 byte blocks */
1254         while (remainingInput > 0) {
1255           char testBuffer[6] = "\xAA\xAA\xAA\xAA\xAA\xAA";
1256           const size_t kSmallBlockSize = sizeof(testBuffer);
1257           ZSTD_inBuffer in = {testBuffer, kSmallBlockSize, 0};
1258
1259           CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_flush));
1260           CHECK(in.pos != in.size, "input not fully consumed");
1261           remainingInput -= kSmallBlockSize;
1262         }
1263         /* Write several very long offset matches into the dictionary */
1264         for (offset = 1024; offset >= 0; offset -= 128) {
1265           ZSTD_inBuffer in = {dictionary.start + offset, 128, 0};
1266           ZSTD_EndDirective flush = offset > 0 ? ZSTD_e_continue : ZSTD_e_end;
1267           CHECK_Z(ZSTD_compressStream2(zc, &out, &in, flush));
1268           CHECK(in.pos != in.size, "input not fully consumed");
1269         }
1270         /* Ensure decompression works */
1271         CHECK_Z(ZSTD_decompress_usingDict(zd, decodedBuffer, CNBufferSize, out.dst, out.pos, dictionary.start, dictionary.filled));
1272
1273         ZSTD_freeCDict(cdict);
1274     }
1275     DISPLAYLEVEL(3, "OK \n");
1276
1277 _end:
1278     FUZ_freeDictionary(dictionary);
1279     ZSTD_freeCStream(zc);
1280     ZSTD_freeDStream(zd);
1281     ZSTDMT_freeCCtx(mtctx);
1282     free(CNBuffer);
1283     free(compressedBuffer);
1284     free(decodedBuffer);
1285     return testResult;
1286
1287 _output_error:
1288     testResult = 1;
1289     DISPLAY("Error detected in Unit tests ! \n");
1290     goto _end;
1291 }
1292
1293
1294 /* ======   Fuzzer tests   ====== */
1295
1296 static size_t findDiff(const void* buf1, const void* buf2, size_t max)
1297 {
1298     const BYTE* b1 = (const BYTE*)buf1;
1299     const BYTE* b2 = (const BYTE*)buf2;
1300     size_t u;
1301     for (u=0; u<max; u++) {
1302         if (b1[u] != b2[u]) break;
1303     }
1304     if (u==max) {
1305         DISPLAY("=> No difference detected within %u bytes \n", (unsigned)max);
1306         return u;
1307     }
1308     DISPLAY("Error at position %u / %u \n", (unsigned)u, (unsigned)max);
1309     if (u>=3)
1310         DISPLAY(" %02X %02X %02X ",
1311                 b1[u-3], b1[u-2], b1[u-1]);
1312     DISPLAY(" :%02X:  %02X %02X %02X %02X %02X \n",
1313             b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
1314     if (u>=3)
1315         DISPLAY(" %02X %02X %02X ",
1316                 b2[u-3], b2[u-2], b2[u-1]);
1317     DISPLAY(" :%02X:  %02X %02X %02X %02X %02X \n",
1318             b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
1319     return u;
1320 }
1321
1322 static size_t FUZ_rLogLength(U32* seed, U32 logLength)
1323 {
1324     size_t const lengthMask = ((size_t)1 << logLength) - 1;
1325     return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
1326 }
1327
1328 static size_t FUZ_randomLength(U32* seed, U32 maxLog)
1329 {
1330     U32 const logLength = FUZ_rand(seed) % maxLog;
1331     return FUZ_rLogLength(seed, logLength);
1332 }
1333
1334 /* Return value in range minVal <= v <= maxVal */
1335 static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
1336 {
1337     U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
1338     return (U32)((FUZ_rand(seed) % mod) + minVal);
1339 }
1340
1341 static int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, int bigTests)
1342 {
1343     U32 const maxSrcLog = bigTests ? 24 : 22;
1344     static const U32 maxSampleLog = 19;
1345     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1346     BYTE* cNoiseBuffer[5];
1347     size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
1348     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
1349     size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
1350     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
1351     size_t const dstBufferSize = srcBufferSize;
1352     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
1353     U32 result = 0;
1354     unsigned testNb = 0;
1355     U32 coreSeed = seed;
1356     ZSTD_CStream* zc = ZSTD_createCStream();   /* will be re-created sometimes */
1357     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be re-created sometimes */
1358     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
1359     UTIL_time_t const startClock = UTIL_getTime();
1360     const BYTE* dict = NULL;  /* can keep same dict on 2 consecutive tests */
1361     size_t dictSize = 0;
1362     U32 oldTestLog = 0;
1363     U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
1364
1365     /* allocations */
1366     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1367     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1368     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1369     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1370     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1371     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1372            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1373            "Not enough memory, fuzzer tests cancelled");
1374
1375     /* Create initial samples */
1376     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
1377     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
1378     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1379     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
1380     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
1381     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
1382     ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1383
1384     /* catch up testNb */
1385     for (testNb=1; testNb < startTest; testNb++)
1386         FUZ_rand(&coreSeed);
1387
1388     /* test loop */
1389     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
1390         U32 lseed;
1391         const BYTE* srcBuffer;
1392         size_t totalTestSize, totalGenSize, cSize;
1393         XXH64_state_t xxhState;
1394         U64 crcOrig;
1395         U32 resetAllowed = 1;
1396         size_t maxTestSize;
1397
1398         /* init */
1399         FUZ_rand(&coreSeed);
1400         lseed = coreSeed ^ prime32;
1401         if (nbTests >= testNb) {
1402             DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests);
1403         } else {
1404             DISPLAYUPDATE(2, "\r%6u        ", testNb);
1405         }
1406
1407         /* states full reset (deliberately not synchronized) */
1408         /* some issues can only happen when reusing states */
1409         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1410             ZSTD_freeCStream(zc);
1411             zc = ZSTD_createCStream();
1412             CHECK(zc==NULL, "ZSTD_createCStream : allocation error");
1413             resetAllowed=0;
1414         }
1415         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1416             ZSTD_freeDStream(zd);
1417             zd = ZSTD_createDStream();
1418             CHECK(zd==NULL, "ZSTD_createDStream : allocation error");
1419             CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) );  /* ensure at least one init */
1420         }
1421
1422         /* srcBuffer selection [0-4] */
1423         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1424             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
1425             else {
1426                 buffNb >>= 3;
1427                 if (buffNb & 7) {
1428                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
1429                     buffNb = tnb[buffNb >> 3];
1430                 } else {
1431                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
1432                     buffNb = tnb[buffNb >> 3];
1433             }   }
1434             srcBuffer = cNoiseBuffer[buffNb];
1435         }
1436
1437         /* compression init */
1438         if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
1439             && oldTestLog /* at least one test happened */ && resetAllowed) {
1440             maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
1441             maxTestSize = MIN(maxTestSize, srcBufferSize-16);
1442             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize;
1443                 CHECK_Z( ZSTD_resetCStream(zc, pledgedSrcSize) );
1444             }
1445         } else {
1446             U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
1447             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
1448             U32 const cLevelCandidate = ( FUZ_rand(&lseed) %
1449                                 (ZSTD_maxCLevel() -
1450                                 (MAX(testLog, dictLog) / 3)))
1451                                  + 1;
1452             U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
1453             maxTestSize = FUZ_rLogLength(&lseed, testLog);
1454             oldTestLog = testLog;
1455             /* random dictionary selection */
1456             dictSize  = ((FUZ_rand(&lseed)&7)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
1457             {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1458                 dict = srcBuffer + dictStart;
1459             }
1460             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
1461                 ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
1462                 params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1463                 params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
1464                 params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
1465                 CHECK_Z ( ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1466         }   }
1467
1468         /* multi-segments compression test */
1469         XXH64_reset(&xxhState, 0);
1470         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
1471             U32 n;
1472             for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
1473                 /* compress random chunks into randomly sized dst buffers */
1474                 {   size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1475                     size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
1476                     size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
1477                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1478                     size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
1479                     ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
1480                     outBuff.size = outBuff.pos + dstBuffSize;
1481
1482                     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1483
1484                     XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1485                     memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1486                     totalTestSize += inBuff.pos;
1487                 }
1488
1489                 /* random flush operation, to mess around */
1490                 if ((FUZ_rand(&lseed) & 15) == 0) {
1491                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1492                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1493                     outBuff.size = outBuff.pos + adjustedDstSize;
1494                     CHECK_Z( ZSTD_flushStream(zc, &outBuff) );
1495             }   }
1496
1497             /* final frame epilogue */
1498             {   size_t remainingToFlush = (size_t)(-1);
1499                 while (remainingToFlush) {
1500                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1501                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1502                     outBuff.size = outBuff.pos + adjustedDstSize;
1503                     remainingToFlush = ZSTD_endStream(zc, &outBuff);
1504                     CHECK (ZSTD_isError(remainingToFlush), "end error : %s", ZSTD_getErrorName(remainingToFlush));
1505             }   }
1506             crcOrig = XXH64_digest(&xxhState);
1507             cSize = outBuff.pos;
1508         }
1509
1510         /* multi - fragments decompression test */
1511         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
1512             CHECK_Z ( ZSTD_resetDStream(zd) );
1513         } else {
1514             CHECK_Z ( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
1515         }
1516         {   size_t decompressionResult = 1;
1517             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1518             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1519             for (totalGenSize = 0 ; decompressionResult ; ) {
1520                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1521                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1522                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
1523                 inBuff.size = inBuff.pos + readCSrcSize;
1524                 outBuff.size = outBuff.pos + dstBuffSize;
1525                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1526                 if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
1527                     DISPLAY("checksum error : \n");
1528                     findDiff(copyBuffer, dstBuffer, totalTestSize);
1529                 }
1530                 CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
1531                        ZSTD_getErrorName(decompressionResult) );
1532             }
1533             CHECK (decompressionResult != 0, "frame not fully decoded");
1534             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
1535                     (unsigned)outBuff.pos, (unsigned)totalTestSize);
1536             CHECK (inBuff.pos != cSize, "compressed data should be fully read")
1537             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1538                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1539                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1540         }   }
1541
1542         /*=====   noisy/erroneous src decompression test   =====*/
1543
1544         /* add some noise */
1545         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1546             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1547                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1548                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
1549                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1550                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1551                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1552         }   }
1553
1554         /* try decompression on noisy data */
1555         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
1556         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1557             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1558             while (outBuff.pos < dstBufferSize) {
1559                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1560                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1561                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
1562                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
1563                 outBuff.size = outBuff.pos + adjustedDstSize;
1564                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
1565                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1566                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
1567                     /* No forward progress possible */
1568                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
1569     }   }   }   }
1570     DISPLAY("\r%u fuzzer tests completed   \n", testNb);
1571
1572 _cleanup:
1573     ZSTD_freeCStream(zc);
1574     ZSTD_freeDStream(zd);
1575     ZSTD_freeDStream(zd_noise);
1576     free(cNoiseBuffer[0]);
1577     free(cNoiseBuffer[1]);
1578     free(cNoiseBuffer[2]);
1579     free(cNoiseBuffer[3]);
1580     free(cNoiseBuffer[4]);
1581     free(copyBuffer);
1582     free(cBuffer);
1583     free(dstBuffer);
1584     return result;
1585
1586 _output_error:
1587     result = 1;
1588     goto _cleanup;
1589 }
1590
1591
1592 /* fuzzing ZSTDMT_* interface */
1593 static int fuzzerTests_MT(U32 seed, int nbTests, int startTest,
1594                           double compressibility, int bigTests)
1595 {
1596     const U32 maxSrcLog = bigTests ? 24 : 22;
1597     static const U32 maxSampleLog = 19;
1598     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1599     BYTE* cNoiseBuffer[5];
1600     size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
1601     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
1602     size_t const cBufferSize   = ZSTD_compressBound(srcBufferSize);
1603     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
1604     size_t const dstBufferSize = srcBufferSize;
1605     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
1606     U32 result = 0;
1607     int testNb = 0;
1608     U32 coreSeed = seed;
1609     int nbThreads = 2;
1610     ZSTDMT_CCtx* zc = ZSTDMT_createCCtx(nbThreads);   /* will be reset sometimes */
1611     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be reset sometimes */
1612     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
1613     UTIL_time_t const startClock = UTIL_getTime();
1614     const BYTE* dict=NULL;   /* can keep same dict on 2 consecutive tests */
1615     size_t dictSize = 0;
1616     int const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
1617     U32 const nbThreadsMax = bigTests ? 4 : 2;
1618
1619     /* allocations */
1620     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1621     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1622     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1623     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1624     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1625     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1626            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1627            "Not enough memory, fuzzer tests cancelled");
1628
1629     /* Create initial samples */
1630     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
1631     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
1632     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1633     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
1634     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
1635     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
1636     ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1637     DISPLAYLEVEL(6, "Creating initial context with %i threads \n", nbThreads);
1638
1639     /* catch up testNb */
1640     for (testNb=1; testNb < startTest; testNb++)
1641         FUZ_rand(&coreSeed);
1642
1643     /* test loop */
1644     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
1645         U32 lseed;
1646         const BYTE* srcBuffer;
1647         size_t totalTestSize, totalGenSize, cSize;
1648         XXH64_state_t xxhState;
1649         U64 crcOrig;
1650         size_t maxTestSize;
1651
1652         FUZ_rand(&coreSeed);
1653         if (nbTests >= testNb) {
1654             DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests);
1655         } else {
1656             DISPLAYUPDATE(2, "\r%6u         ", testNb);
1657         }
1658         lseed = coreSeed ^ prime32;
1659
1660         /* states full reset (deliberately not synchronized) */
1661         /* some issues can only happen when reusing states */
1662         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1663             nbThreads = (FUZ_rand(&lseed) % nbThreadsMax) + 1;
1664             DISPLAYLEVEL(5, "Creating new context with %u threads \n", nbThreads);
1665             ZSTDMT_freeCCtx(zc);
1666             zc = ZSTDMT_createCCtx(nbThreads);
1667             CHECK(zc==NULL, "ZSTDMT_createCCtx allocation error")
1668         }
1669         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1670             ZSTD_freeDStream(zd);
1671             zd = ZSTD_createDStream();
1672             CHECK(zd==NULL, "ZSTDMT_createCCtx allocation error")
1673             ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1674         }
1675
1676         /* srcBuffer selection [0-4] */
1677         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1678             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
1679             else {
1680                 buffNb >>= 3;
1681                 if (buffNb & 7) {
1682                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
1683                     buffNb = tnb[buffNb >> 3];
1684                 } else {
1685                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
1686                     buffNb = tnb[buffNb >> 3];
1687             }   }
1688             srcBuffer = cNoiseBuffer[buffNb];
1689         }
1690
1691         /* compression init */
1692         {   U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
1693             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
1694             int const cLevelCandidate = ( FUZ_rand(&lseed)
1695                             % (ZSTD_maxCLevel() - (MAX(testLog, dictLog) / 2)) )
1696                             + 1;
1697             int const cLevelThreadAdjusted = cLevelCandidate - (nbThreads * 2) + 2;  /* reduce cLevel when multiple threads to reduce memory consumption */
1698             int const cLevelMin = MAX(cLevelThreadAdjusted, 1);  /* no negative cLevel yet */
1699             int const cLevel = MIN(cLevelMin, cLevelMax);
1700             maxTestSize = FUZ_rLogLength(&lseed, testLog);
1701
1702             if (FUZ_rand(&lseed)&1) {   /* simple init */
1703                 int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
1704                 DISPLAYLEVEL(5, "Init with compression level = %i \n", compressionLevel);
1705                 CHECK_Z( ZSTDMT_initCStream(zc, compressionLevel) );
1706             } else {   /* advanced init */
1707                 /* random dictionary selection */
1708                 dictSize  = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
1709                 {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
1710                     dict = srcBuffer + dictStart;
1711                 }
1712                 {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
1713                     ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize);
1714                     DISPLAYLEVEL(5, "Init with windowLog = %u, pledgedSrcSize = %u, dictSize = %u \n",
1715                         params.cParams.windowLog, (unsigned)pledgedSrcSize, (unsigned)dictSize);
1716                     params.fParams.checksumFlag = FUZ_rand(&lseed) & 1;
1717                     params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1;
1718                     params.fParams.contentSizeFlag = FUZ_rand(&lseed) & 1;
1719                     DISPLAYLEVEL(5, "checksumFlag : %u \n", params.fParams.checksumFlag);
1720                     CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_overlapLog, FUZ_rand(&lseed) % 12) );
1721                     CHECK_Z( ZSTDMT_setMTCtxParameter(zc, ZSTDMT_p_jobSize, FUZ_rand(&lseed) % (2*maxTestSize+1)) );   /* custom job size */
1722                     CHECK_Z( ZSTDMT_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize) );
1723         }   }   }
1724
1725         /* multi-segments compression test */
1726         XXH64_reset(&xxhState, 0);
1727         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
1728             U32 n;
1729             for (n=0, cSize=0, totalTestSize=0 ; totalTestSize < maxTestSize ; n++) {
1730                 /* compress random chunks into randomly sized dst buffers */
1731                 {   size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1732                     size_t const srcSize = MIN (maxTestSize-totalTestSize, randomSrcSize);
1733                     size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
1734                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1735                     size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
1736                     ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
1737                     outBuff.size = outBuff.pos + dstBuffSize;
1738
1739                     DISPLAYLEVEL(6, "Sending %u bytes to compress \n", (unsigned)srcSize);
1740                     CHECK_Z( ZSTDMT_compressStream(zc, &outBuff, &inBuff) );
1741                     DISPLAYLEVEL(6, "%u bytes read by ZSTDMT_compressStream \n", (unsigned)inBuff.pos);
1742
1743                     XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
1744                     memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
1745                     totalTestSize += inBuff.pos;
1746                 }
1747
1748                 /* random flush operation, to mess around */
1749                 if ((FUZ_rand(&lseed) & 15) == 0) {
1750                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1751                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1752                     size_t const previousPos = outBuff.pos;
1753                     outBuff.size = outBuff.pos + adjustedDstSize;
1754                     DISPLAYLEVEL(5, "Flushing into dst buffer of size %u \n", (unsigned)adjustedDstSize);
1755                     CHECK_Z( ZSTDMT_flushStream(zc, &outBuff) );
1756                     assert(outBuff.pos >= previousPos);
1757                     DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_flushStream \n", (unsigned)(outBuff.pos-previousPos));
1758             }   }
1759
1760             /* final frame epilogue */
1761             {   size_t remainingToFlush = (size_t)(-1);
1762                 while (remainingToFlush) {
1763                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1764                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
1765                     size_t const previousPos = outBuff.pos;
1766                     outBuff.size = outBuff.pos + adjustedDstSize;
1767                     DISPLAYLEVEL(5, "Ending into dst buffer of size %u \n", (unsigned)adjustedDstSize);
1768                     remainingToFlush = ZSTDMT_endStream(zc, &outBuff);
1769                     CHECK (ZSTD_isError(remainingToFlush), "ZSTDMT_endStream error : %s", ZSTD_getErrorName(remainingToFlush));
1770                     assert(outBuff.pos >= previousPos);
1771                     DISPLAYLEVEL(6, "%u bytes flushed by ZSTDMT_endStream \n", (unsigned)(outBuff.pos-previousPos));
1772                     DISPLAYLEVEL(5, "endStream : remainingToFlush : %u \n", (unsigned)remainingToFlush);
1773             }   }
1774             crcOrig = XXH64_digest(&xxhState);
1775             cSize = outBuff.pos;
1776             DISPLAYLEVEL(5, "Frame completed : %u bytes compressed into %u bytes \n",
1777                             (unsigned)totalTestSize, (unsigned)cSize);
1778         }
1779
1780         /* multi - fragments decompression test */
1781         assert(totalTestSize < dstBufferSize);
1782         memset(dstBuffer, 170, totalTestSize);   /* init dest area */
1783         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
1784             CHECK_Z( ZSTD_resetDStream(zd) );
1785         } else {
1786             CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
1787         }
1788         {   size_t decompressionResult = 1;
1789             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1790             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1791             for (totalGenSize = 0 ; decompressionResult ; ) {
1792                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1793                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1794                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
1795                 inBuff.size = inBuff.pos + readCSrcSize;
1796                 outBuff.size = outBuff.pos + dstBuffSize;
1797                 DISPLAYLEVEL(6, "ZSTD_decompressStream input %u bytes into outBuff %u bytes \n",
1798                                 (unsigned)readCSrcSize, (unsigned)dstBuffSize);
1799                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1800                 if (ZSTD_isError(decompressionResult)) {
1801                     DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
1802                     findDiff(copyBuffer, dstBuffer, totalTestSize);
1803                 }
1804                 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
1805                 DISPLAYLEVEL(6, "total ingested (inBuff.pos) = %u and produced (outBuff.pos) = %u \n",
1806                                 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
1807             }
1808             CHECK (outBuff.pos != totalTestSize,
1809                     "decompressed data : wrong size (%u != %u)",
1810                     (unsigned)outBuff.pos, (unsigned)totalTestSize );
1811             CHECK (inBuff.pos != cSize,
1812                     "compressed data should be fully read (%u != %u)",
1813                     (unsigned)inBuff.pos, (unsigned)cSize );
1814             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
1815                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
1816                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
1817         }   }
1818
1819         /*=====   noisy/erroneous src decompression test   =====*/
1820
1821         /* add some noise */
1822         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
1823             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
1824                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
1825                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
1826                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
1827                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
1828                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
1829         }   }
1830
1831         /* try decompression on noisy data */
1832         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
1833         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
1834             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
1835             while (outBuff.pos < dstBufferSize) {
1836                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
1837                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
1838                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
1839                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
1840                 outBuff.size = outBuff.pos + adjustedDstSize;
1841                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
1842                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1843                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
1844                     /* No forward progress possible */
1845                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
1846     }   }   }   }
1847     DISPLAY("\r%u fuzzer tests completed   \n", testNb);
1848
1849 _cleanup:
1850     ZSTDMT_freeCCtx(zc);
1851     ZSTD_freeDStream(zd);
1852     ZSTD_freeDStream(zd_noise);
1853     free(cNoiseBuffer[0]);
1854     free(cNoiseBuffer[1]);
1855     free(cNoiseBuffer[2]);
1856     free(cNoiseBuffer[3]);
1857     free(cNoiseBuffer[4]);
1858     free(copyBuffer);
1859     free(cBuffer);
1860     free(dstBuffer);
1861     return result;
1862
1863 _output_error:
1864     result = 1;
1865     goto _cleanup;
1866 }
1867
1868 /** If useOpaqueAPI, sets param in cctxParams.
1869  *  Otherwise, sets the param in zc. */
1870 static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
1871                                ZSTD_cParameter param, unsigned value,
1872                                int useOpaqueAPI)
1873 {
1874     if (useOpaqueAPI) {
1875         return ZSTD_CCtxParams_setParameter(cctxParams, param, value);
1876     } else {
1877         return ZSTD_CCtx_setParameter(zc, param, value);
1878     }
1879 }
1880
1881 /* Tests for ZSTD_compress_generic() API */
1882 static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
1883                               double compressibility, int bigTests)
1884 {
1885     U32 const maxSrcLog = bigTests ? 24 : 22;
1886     static const U32 maxSampleLog = 19;
1887     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
1888     BYTE* cNoiseBuffer[5];
1889     size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
1890     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
1891     size_t const cBufferSize   = ZSTD_compressBound(srcBufferSize);
1892     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
1893     size_t const dstBufferSize = srcBufferSize;
1894     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
1895     U32 result = 0;
1896     int testNb = 0;
1897     U32 coreSeed = seed;
1898     ZSTD_CCtx* zc = ZSTD_createCCtx();   /* will be reset sometimes */
1899     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be reset sometimes */
1900     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
1901     UTIL_time_t const startClock = UTIL_getTime();
1902     const BYTE* dict = NULL;   /* can keep same dict on 2 consecutive tests */
1903     size_t dictSize = 0;
1904     U32 oldTestLog = 0;
1905     U32 windowLogMalus = 0;   /* can survive between 2 loops */
1906     U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
1907     U32 const nbThreadsMax = bigTests ? 4 : 2;
1908     ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
1909
1910     /* allocations */
1911     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
1912     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
1913     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
1914     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
1915     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
1916     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
1917            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
1918            "Not enough memory, fuzzer tests cancelled");
1919
1920     /* Create initial samples */
1921     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
1922     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
1923     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
1924     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
1925     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
1926     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
1927     CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) );   /* ensure at least one init */
1928
1929     /* catch up testNb */
1930     for (testNb=1; testNb < startTest; testNb++)
1931         FUZ_rand(&coreSeed);
1932
1933     /* test loop */
1934     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
1935         U32 lseed;
1936         int opaqueAPI;
1937         const BYTE* srcBuffer;
1938         size_t totalTestSize, totalGenSize, cSize;
1939         XXH64_state_t xxhState;
1940         U64 crcOrig;
1941         U32 resetAllowed = 1;
1942         size_t maxTestSize;
1943         ZSTD_parameters savedParams;
1944
1945         /* init */
1946         if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests); }
1947         else { DISPLAYUPDATE(2, "\r%6u          ", testNb); }
1948         FUZ_rand(&coreSeed);
1949         lseed = coreSeed ^ prime32;
1950         DISPLAYLEVEL(5, " ***  Test %u  *** \n", testNb);
1951         opaqueAPI = FUZ_rand(&lseed) & 1;
1952
1953         /* states full reset (deliberately not synchronized) */
1954         /* some issues can only happen when reusing states */
1955         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
1956             DISPLAYLEVEL(5, "Creating new context \n");
1957             ZSTD_freeCCtx(zc);
1958             zc = ZSTD_createCCtx();
1959             CHECK(zc == NULL, "ZSTD_createCCtx allocation error");
1960             resetAllowed = 0;
1961         }
1962         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
1963             ZSTD_freeDStream(zd);
1964             zd = ZSTD_createDStream();
1965             CHECK(zd == NULL, "ZSTD_createDStream allocation error");
1966             ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
1967         }
1968
1969         /* srcBuffer selection [0-4] */
1970         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
1971             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
1972             else {
1973                 buffNb >>= 3;
1974                 if (buffNb & 7) {
1975                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
1976                     buffNb = tnb[buffNb >> 3];
1977                 } else {
1978                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
1979                     buffNb = tnb[buffNb >> 3];
1980             }   }
1981             srcBuffer = cNoiseBuffer[buffNb];
1982         }
1983
1984         /* compression init */
1985         CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) );   /* cancel previous dict /*/
1986         if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
1987           && oldTestLog   /* at least one test happened */
1988           && resetAllowed) {
1989             /* just set a compression level */
1990             maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
1991             if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
1992             {   int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
1993                 DISPLAYLEVEL(5, "t%u : compression level : %i \n", testNb, compressionLevel);
1994                 CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_c_compressionLevel, compressionLevel, opaqueAPI) );
1995             }
1996         } else {
1997             U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
1998             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
1999             U32 const cLevelCandidate = (FUZ_rand(&lseed) %
2000                                (ZSTD_maxCLevel() -
2001                                (MAX(testLog, dictLog) / 2))) +
2002                                1;
2003             int const cLevel = MIN(cLevelCandidate, cLevelMax);
2004             DISPLAYLEVEL(5, "t%i: base cLevel : %u \n", testNb, cLevel);
2005             maxTestSize = FUZ_rLogLength(&lseed, testLog);
2006             DISPLAYLEVEL(5, "t%i: maxTestSize : %u \n", testNb, (unsigned)maxTestSize);
2007             oldTestLog = testLog;
2008             /* random dictionary selection */
2009             dictSize  = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
2010             {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2011                 dict = srcBuffer + dictStart;
2012                 if (!dictSize) dict=NULL;
2013             }
2014             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2015                 ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
2016                 const U32 windowLogMax = bigTests ? 24 : 20;
2017                 const U32 searchLogMax = bigTests ? 15 : 13;
2018                 if (dictSize)
2019                     DISPLAYLEVEL(5, "t%u: with dictionary of size : %zu \n", testNb, dictSize);
2020
2021                 /* mess with compression parameters */
2022                 cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
2023                 cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
2024                 cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
2025                 cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
2026                 cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
2027                 cParams.searchLog = MIN(searchLogMax, cParams.searchLog);
2028                 cParams.minMatch += (FUZ_rand(&lseed) & 3) - 1;
2029                 cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
2030                 cParams = ZSTD_adjustCParams(cParams, pledgedSrcSize, dictSize);
2031
2032                 if (FUZ_rand(&lseed) & 1) {
2033                     DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
2034                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_windowLog, cParams.windowLog, opaqueAPI) );
2035                     assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN);   /* guaranteed by ZSTD_adjustCParams() */
2036                     windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
2037                 }
2038                 if (FUZ_rand(&lseed) & 1) {
2039                     DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
2040                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_hashLog, cParams.hashLog, opaqueAPI) );
2041                 }
2042                 if (FUZ_rand(&lseed) & 1) {
2043                     DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
2044                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_chainLog, cParams.chainLog, opaqueAPI) );
2045                 }
2046                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_searchLog, cParams.searchLog, opaqueAPI) );
2047                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_minMatch, cParams.minMatch, opaqueAPI) );
2048                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_targetLength, cParams.targetLength, opaqueAPI) );
2049
2050                 /* mess with long distance matching parameters */
2051                 if (bigTests) {
2052                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_enableLongDistanceMatching, FUZ_rand(&lseed) & 63, opaqueAPI) );
2053                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), opaqueAPI) );
2054                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmMinMatch, FUZ_randomClampedLength(&lseed, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX), opaqueAPI) );
2055                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmBucketSizeLog, FUZ_randomClampedLength(&lseed, ZSTD_LDM_BUCKETSIZELOG_MIN, ZSTD_LDM_BUCKETSIZELOG_MAX), opaqueAPI) );
2056                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashRateLog, FUZ_randomClampedLength(&lseed, ZSTD_LDM_HASHRATELOG_MIN, ZSTD_LDM_HASHRATELOG_MAX), opaqueAPI) );
2057                 }
2058
2059                 /* mess with frame parameters */
2060                 if (FUZ_rand(&lseed) & 1) {
2061                     int const checksumFlag = FUZ_rand(&lseed) & 1;
2062                     DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
2063                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_checksumFlag, checksumFlag, opaqueAPI) );
2064                 }
2065                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2066                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_contentSizeFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2067                 if (FUZ_rand(&lseed) & 1) {
2068                     DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (unsigned)pledgedSrcSize);
2069                     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2070                 }
2071
2072                 /* multi-threading parameters. Only adjust occasionally for small tests. */
2073                 if (bigTests || (FUZ_rand(&lseed) & 0xF) == 0xF) {
2074                     U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
2075                     U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
2076                     int const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
2077                     DISPLAYLEVEL(5, "t%i: nbThreads : %u \n", testNb, nbThreads);
2078                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_nbWorkers, nbThreads, opaqueAPI) );
2079                     if (nbThreads > 1) {
2080                         U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
2081                         CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_overlapLog, FUZ_rand(&lseed) % 10, opaqueAPI) );
2082                         CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), opaqueAPI) );
2083                     }
2084                 }
2085                 /* Enable rsyncable mode 1 in 4 times. */
2086                 setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, (FUZ_rand(&lseed) % 4 == 0), opaqueAPI);
2087
2088                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );
2089
2090                 /* Apply parameters */
2091                 if (opaqueAPI) {
2092                     DISPLAYLEVEL(5, "t%u: applying CCtxParams \n", testNb);
2093                     CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
2094                 }
2095
2096                 if (FUZ_rand(&lseed) & 1) {
2097                     if (FUZ_rand(&lseed) & 1) {
2098                         CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
2099                     } else {
2100                         CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
2101                     }
2102                 } else {
2103                     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
2104                 }
2105         }   }
2106
2107         CHECK_Z(getCCtxParams(zc, &savedParams));
2108
2109         /* multi-segments compression test */
2110         XXH64_reset(&xxhState, 0);
2111         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
2112             for (cSize=0, totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) {
2113                 /* compress random chunks into randomly sized dst buffers */
2114                 size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2115                 size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
2116                 size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
2117                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
2118                 size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
2119                 ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush;
2120                 ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
2121                 outBuff.size = outBuff.pos + dstBuffSize;
2122
2123                 CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, flush) );
2124                 DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
2125                     testNb, (unsigned)inBuff.pos, (unsigned)(totalTestSize + inBuff.pos), (unsigned)flush, (unsigned)outBuff.pos);
2126
2127                 XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
2128                 memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
2129                 totalTestSize += inBuff.pos;
2130             }
2131
2132             /* final frame epilogue */
2133             {   size_t remainingToFlush = 1;
2134                 while (remainingToFlush) {
2135                     ZSTD_inBuffer inBuff = { NULL, 0, 0 };
2136                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
2137                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
2138                     outBuff.size = outBuff.pos + adjustedDstSize;
2139                     DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (unsigned)adjustedDstSize);
2140                     remainingToFlush = ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end);
2141                     DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (unsigned)outBuff.pos);
2142                     CHECK( ZSTD_isError(remainingToFlush),
2143                           "ZSTD_compressStream2 w/ ZSTD_e_end error : %s",
2144                            ZSTD_getErrorName(remainingToFlush) );
2145             }   }
2146             crcOrig = XXH64_digest(&xxhState);
2147             cSize = outBuff.pos;
2148             DISPLAYLEVEL(5, "Frame completed : %zu bytes \n", cSize);
2149         }
2150
2151         CHECK(badParameters(zc, savedParams), "CCtx params are wrong");
2152
2153         /* multi - fragments decompression test */
2154         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
2155             DISPLAYLEVEL(5, "resetting DCtx (dict:%p) \n", dict);
2156             CHECK_Z( ZSTD_resetDStream(zd) );
2157         } else {
2158             if (dictSize)
2159                 DISPLAYLEVEL(5, "using dictionary of size %zu \n", dictSize);
2160             CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
2161         }
2162         {   size_t decompressionResult = 1;
2163             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
2164             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2165             for (totalGenSize = 0 ; decompressionResult ; ) {
2166                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2167                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2168                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
2169                 inBuff.size = inBuff.pos + readCSrcSize;
2170                 outBuff.size = outBuff.pos + dstBuffSize;
2171                 DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
2172                                 (unsigned)readCSrcSize, (unsigned)inBuff.pos, (unsigned)cSize);
2173                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
2174                 DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
2175                                 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
2176                 if (ZSTD_isError(decompressionResult)) {
2177                     DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
2178                     findDiff(copyBuffer, dstBuffer, totalTestSize);
2179                 }
2180                 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
2181                 CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (unsigned)inBuff.pos, (unsigned)cSize);
2182             }
2183             CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (unsigned)inBuff.pos, (unsigned)cSize);
2184             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (unsigned)outBuff.pos, (unsigned)totalTestSize);
2185             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
2186                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
2187                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
2188         }   }
2189
2190         /*=====   noisy/erroneous src decompression test   =====*/
2191
2192         /* add some noise */
2193         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
2194             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
2195                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
2196                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
2197                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
2198                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
2199                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
2200         }   }
2201
2202         /* try decompression on noisy data */
2203         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
2204         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
2205             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2206             while (outBuff.pos < dstBufferSize) {
2207                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2208                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2209                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
2210                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
2211                 outBuff.size = outBuff.pos + adjustedDstSize;
2212                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
2213                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
2214                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
2215                     /* Good so far, but no more progress possible */
2216                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
2217     }   }   }   }
2218     DISPLAY("\r%u fuzzer tests completed   \n", testNb-1);
2219
2220 _cleanup:
2221     ZSTD_freeCCtx(zc);
2222     ZSTD_freeDStream(zd);
2223     ZSTD_freeDStream(zd_noise);
2224     ZSTD_freeCCtxParams(cctxParams);
2225     free(cNoiseBuffer[0]);
2226     free(cNoiseBuffer[1]);
2227     free(cNoiseBuffer[2]);
2228     free(cNoiseBuffer[3]);
2229     free(cNoiseBuffer[4]);
2230     free(copyBuffer);
2231     free(cBuffer);
2232     free(dstBuffer);
2233     return result;
2234
2235 _output_error:
2236     result = 1;
2237     goto _cleanup;
2238 }
2239
2240 /*-*******************************************************
2241 *  Command line
2242 *********************************************************/
2243 static int FUZ_usage(const char* programName)
2244 {
2245     DISPLAY( "Usage :\n");
2246     DISPLAY( "      %s [args]\n", programName);
2247     DISPLAY( "\n");
2248     DISPLAY( "Arguments :\n");
2249     DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
2250     DISPLAY( " -s#    : Select seed (default:prompt user)\n");
2251     DISPLAY( " -t#    : Select starting test number (default:0)\n");
2252     DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
2253     DISPLAY( " -v     : verbose\n");
2254     DISPLAY( " -p     : pause at the end\n");
2255     DISPLAY( " -h     : display help and exit\n");
2256     return 0;
2257 }
2258
2259 typedef enum { simple_api, mt_api, advanced_api } e_api;
2260
2261 int main(int argc, const char** argv)
2262 {
2263     U32 seed = 0;
2264     int seedset = 0;
2265     int nbTests = nbTestsDefault;
2266     int testNb = 0;
2267     int proba = FUZ_COMPRESSIBILITY_DEFAULT;
2268     int result = 0;
2269     int mainPause = 0;
2270     int bigTests = (sizeof(size_t) == 8);
2271     e_api selected_api = simple_api;
2272     const char* const programName = argv[0];
2273     int argNb;
2274
2275     /* Check command line */
2276     for(argNb=1; argNb<argc; argNb++) {
2277         const char* argument = argv[argNb];
2278         assert(argument != NULL);
2279
2280         /* Parsing commands. Aggregated commands are allowed */
2281         if (argument[0]=='-') {
2282
2283             if (!strcmp(argument, "--mt")) { selected_api=mt_api; testNb += !testNb; continue; }
2284             if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
2285             if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
2286
2287             argument++;
2288             while (*argument!=0) {
2289                 switch(*argument)
2290                 {
2291                 case 'h':
2292                     return FUZ_usage(programName);
2293
2294                 case 'v':
2295                     argument++;
2296                     g_displayLevel++;
2297                     break;
2298
2299                 case 'q':
2300                     argument++;
2301                     g_displayLevel--;
2302                     break;
2303
2304                 case 'p': /* pause at the end */
2305                     argument++;
2306                     mainPause = 1;
2307                     break;
2308
2309                 case 'i':   /* limit tests by nb of iterations (default) */
2310                     argument++;
2311                     nbTests=0; g_clockTime=0;
2312                     while ((*argument>='0') && (*argument<='9')) {
2313                         nbTests *= 10;
2314                         nbTests += *argument - '0';
2315                         argument++;
2316                     }
2317                     break;
2318
2319                 case 'T':   /* limit tests by time */
2320                     argument++;
2321                     nbTests=0; g_clockTime=0;
2322                     while ((*argument>='0') && (*argument<='9')) {
2323                         g_clockTime *= 10;
2324                         g_clockTime += *argument - '0';
2325                         argument++;
2326                     }
2327                     if (*argument=='m') {    /* -T1m == -T60 */
2328                         g_clockTime *=60, argument++;
2329                         if (*argument=='n') argument++; /* -T1mn == -T60 */
2330                     } else if (*argument=='s') argument++; /* -T10s == -T10 */
2331                     g_clockTime *= SEC_TO_MICRO;
2332                     break;
2333
2334                 case 's':   /* manually select seed */
2335                     argument++;
2336                     seedset=1;
2337                     seed=0;
2338                     while ((*argument>='0') && (*argument<='9')) {
2339                         seed *= 10;
2340                         seed += *argument - '0';
2341                         argument++;
2342                     }
2343                     break;
2344
2345                 case 't':   /* select starting test number */
2346                     argument++;
2347                     testNb=0;
2348                     while ((*argument>='0') && (*argument<='9')) {
2349                         testNb *= 10;
2350                         testNb += *argument - '0';
2351                         argument++;
2352                     }
2353                     break;
2354
2355                 case 'P':   /* compressibility % */
2356                     argument++;
2357                     proba=0;
2358                     while ((*argument>='0') && (*argument<='9')) {
2359                         proba *= 10;
2360                         proba += *argument - '0';
2361                         argument++;
2362                     }
2363                     if (proba<0) proba=0;
2364                     if (proba>100) proba=100;
2365                     break;
2366
2367                 default:
2368                     return FUZ_usage(programName);
2369                 }
2370     }   }   }   /* for(argNb=1; argNb<argc; argNb++) */
2371
2372     /* Get Seed */
2373     DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
2374
2375     if (!seedset) {
2376         time_t const t = time(NULL);
2377         U32 const h = XXH32(&t, sizeof(t), 1);
2378         seed = h % 10000;
2379     }
2380
2381     DISPLAY("Seed = %u\n", (unsigned)seed);
2382     if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
2383
2384     if (nbTests<=0) nbTests=1;
2385
2386     if (testNb==0) {
2387         result = basicUnitTests(0, ((double)proba) / 100);  /* constant seed for predictability */
2388     }
2389
2390     if (!result) {
2391         switch(selected_api)
2392         {
2393         case simple_api :
2394             result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2395             break;
2396         case mt_api :
2397             result = fuzzerTests_MT(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2398             break;
2399         case advanced_api :
2400             result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
2401             break;
2402         default :
2403             assert(0);   /* impossible */
2404         }
2405     }
2406
2407     if (mainPause) {
2408         int unused;
2409         DISPLAY("Press Enter \n");
2410         unused = getchar();
2411         (void)unused;
2412     }
2413     return result;
2414 }