xref: /netbsd-src/external/bsd/zstd/dist/tests/zstreamtest.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos 
11*3117ece4Schristos 
12*3117ece4Schristos /*-************************************
13*3117ece4Schristos  *  Compiler specific
14*3117ece4Schristos  **************************************/
15*3117ece4Schristos #ifdef _MSC_VER    /* Visual Studio */
16*3117ece4Schristos #  define _CRT_SECURE_NO_WARNINGS   /* fgets */
17*3117ece4Schristos #  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */
18*3117ece4Schristos #  pragma warning(disable : 4146)   /* disable: C4146: minus unsigned expression */
19*3117ece4Schristos #endif
20*3117ece4Schristos 
21*3117ece4Schristos 
22*3117ece4Schristos /*-************************************
23*3117ece4Schristos  *  Includes
24*3117ece4Schristos  **************************************/
25*3117ece4Schristos #include <stdlib.h>       /* free */
26*3117ece4Schristos #include <stdio.h>        /* fgets, sscanf */
27*3117ece4Schristos #include <string.h>       /* strcmp */
28*3117ece4Schristos #include <time.h>         /* time_t, time(), to randomize seed */
29*3117ece4Schristos #include <assert.h>       /* assert */
30*3117ece4Schristos #include "timefn.h"       /* UTIL_time_t, UTIL_getTime */
31*3117ece4Schristos #include "mem.h"
32*3117ece4Schristos #define ZSTD_DISABLE_DEPRECATE_WARNINGS /* No deprecation warnings, we still test some deprecated functions */
33*3117ece4Schristos #define ZSTD_STATIC_LINKING_ONLY  /* ZSTD_maxCLevel, ZSTD_customMem, ZSTD_getDictID_fromFrame */
34*3117ece4Schristos #include "zstd.h"         /* ZSTD_compressBound */
35*3117ece4Schristos #include "zstd_errors.h"  /* ZSTD_error_srcSize_wrong */
36*3117ece4Schristos #include "zdict.h"        /* ZDICT_trainFromBuffer */
37*3117ece4Schristos #include "datagen.h"      /* RDG_genBuffer */
38*3117ece4Schristos #define XXH_STATIC_LINKING_ONLY   /* XXH64_state_t */
39*3117ece4Schristos #include "xxhash.h"       /* XXH64_* */
40*3117ece4Schristos #include "seqgen.h"
41*3117ece4Schristos #include "util.h"
42*3117ece4Schristos #include "timefn.h"       /* UTIL_time_t, UTIL_clockSpanMicro, UTIL_getTime */
43*3117ece4Schristos #include "external_matchfinder.h"   /* zstreamSequenceProducer, EMF_testCase */
44*3117ece4Schristos 
45*3117ece4Schristos /*-************************************
46*3117ece4Schristos  *  Constants
47*3117ece4Schristos  **************************************/
48*3117ece4Schristos #define KB *(1U<<10)
49*3117ece4Schristos #define MB *(1U<<20)
50*3117ece4Schristos #define GB *(1U<<30)
51*3117ece4Schristos 
52*3117ece4Schristos static const int nbTestsDefault = 10000;
53*3117ece4Schristos static const U32 g_cLevelMax_smallTests = 10;
54*3117ece4Schristos #define COMPRESSIBLE_NOISE_LENGTH (10 MB)
55*3117ece4Schristos #define FUZ_COMPRESSIBILITY_DEFAULT 50
56*3117ece4Schristos static const U32 prime32 = 2654435761U;
57*3117ece4Schristos 
58*3117ece4Schristos 
59*3117ece4Schristos /*-************************************
60*3117ece4Schristos  *  Display Macros
61*3117ece4Schristos  **************************************/
62*3117ece4Schristos #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
63*3117ece4Schristos #define DISPLAYLEVEL(l, ...)  if (g_displayLevel>=l) {                     \
64*3117ece4Schristos                                   DISPLAY(__VA_ARGS__);                    \
65*3117ece4Schristos                                   if (g_displayLevel>=4) fflush(stderr); }
66*3117ece4Schristos static U32 g_displayLevel = 2;
67*3117ece4Schristos 
68*3117ece4Schristos static const U64 g_refreshRate = SEC_TO_MICRO / 6;
69*3117ece4Schristos static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
70*3117ece4Schristos 
71*3117ece4Schristos #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
72*3117ece4Schristos             if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \
73*3117ece4Schristos             { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
74*3117ece4Schristos             if (g_displayLevel>=4) fflush(stderr); } }
75*3117ece4Schristos 
76*3117ece4Schristos static U64 g_clockTime = 0;
77*3117ece4Schristos 
78*3117ece4Schristos 
79*3117ece4Schristos /*-*******************************************************
80*3117ece4Schristos  *  Check macros
81*3117ece4Schristos  *********************************************************/
82*3117ece4Schristos #undef MIN
83*3117ece4Schristos #undef MAX
84*3117ece4Schristos #define MIN(a,b) ((a)<(b)?(a):(b))
85*3117ece4Schristos #define MAX(a,b) ((a)>(b)?(a):(b))
86*3117ece4Schristos /*! FUZ_rand() :
87*3117ece4Schristos     @return : a 27 bits random value, from a 32-bits `seed`.
88*3117ece4Schristos     `seed` is also modified */
89*3117ece4Schristos #define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
90*3117ece4Schristos static U32 FUZ_rand(U32* seedPtr)
91*3117ece4Schristos {
92*3117ece4Schristos     static const U32 prime2 = 2246822519U;
93*3117ece4Schristos     U32 rand32 = *seedPtr;
94*3117ece4Schristos     rand32 *= prime32;
95*3117ece4Schristos     rand32 += prime2;
96*3117ece4Schristos     rand32  = FUZ_rotl32(rand32, 13);
97*3117ece4Schristos     *seedPtr = rand32;
98*3117ece4Schristos     return rand32 >> 5;
99*3117ece4Schristos }
100*3117ece4Schristos 
101*3117ece4Schristos #define CHECK(cond, ...) {                                   \
102*3117ece4Schristos     if (cond) {                                              \
103*3117ece4Schristos         DISPLAY("Error => ");                                \
104*3117ece4Schristos         DISPLAY(__VA_ARGS__);                                \
105*3117ece4Schristos         DISPLAY(" (seed %u, test nb %u, line %u) \n",        \
106*3117ece4Schristos                 (unsigned)seed, testNb, __LINE__);           \
107*3117ece4Schristos         goto _output_error;                                  \
108*3117ece4Schristos }   }
109*3117ece4Schristos 
110*3117ece4Schristos #define CHECK_Z(f) {                                         \
111*3117ece4Schristos     size_t const err = f;                                    \
112*3117ece4Schristos     CHECK(ZSTD_isError(err), "%s : %s ",                     \
113*3117ece4Schristos           #f, ZSTD_getErrorName(err));                       \
114*3117ece4Schristos }
115*3117ece4Schristos 
116*3117ece4Schristos #define CHECK_RET(ret, cond, ...) {                          \
117*3117ece4Schristos     if (cond) {                                              \
118*3117ece4Schristos         DISPLAY("Error %llu => ", (unsigned long long)ret);  \
119*3117ece4Schristos         DISPLAY(__VA_ARGS__);                                \
120*3117ece4Schristos         DISPLAY(" (line %u)\n", __LINE__);                   \
121*3117ece4Schristos         return ret;                                          \
122*3117ece4Schristos }   }
123*3117ece4Schristos 
124*3117ece4Schristos #define CHECK_RET_Z(f) {                                     \
125*3117ece4Schristos     size_t const err = f;                                    \
126*3117ece4Schristos     CHECK_RET(err, ZSTD_isError(err), "%s : %s ",            \
127*3117ece4Schristos           #f, ZSTD_getErrorName(err));                       \
128*3117ece4Schristos }
129*3117ece4Schristos 
130*3117ece4Schristos 
131*3117ece4Schristos /*======================================================
132*3117ece4Schristos  *   Basic Unit tests
133*3117ece4Schristos  *======================================================*/
134*3117ece4Schristos 
135*3117ece4Schristos typedef struct {
136*3117ece4Schristos     void* start;
137*3117ece4Schristos     size_t size;
138*3117ece4Schristos     size_t filled;
139*3117ece4Schristos } buffer_t;
140*3117ece4Schristos 
141*3117ece4Schristos static const buffer_t kBuffNull = { NULL, 0 , 0 };
142*3117ece4Schristos 
143*3117ece4Schristos static void FUZ_freeDictionary(buffer_t dict)
144*3117ece4Schristos {
145*3117ece4Schristos     free(dict.start);
146*3117ece4Schristos }
147*3117ece4Schristos 
148*3117ece4Schristos static buffer_t FUZ_createDictionary(const void* src, size_t srcSize, size_t blockSize, size_t requestedDictSize)
149*3117ece4Schristos {
150*3117ece4Schristos     buffer_t dict = kBuffNull;
151*3117ece4Schristos     size_t const nbBlocks = (srcSize + (blockSize-1)) / blockSize;
152*3117ece4Schristos     size_t* const blockSizes = (size_t*)malloc(nbBlocks * sizeof(size_t));
153*3117ece4Schristos     if (!blockSizes) return kBuffNull;
154*3117ece4Schristos     dict.start = malloc(requestedDictSize);
155*3117ece4Schristos     if (!dict.start) { free(blockSizes); return kBuffNull; }
156*3117ece4Schristos     {   size_t nb;
157*3117ece4Schristos         for (nb=0; nb<nbBlocks-1; nb++) blockSizes[nb] = blockSize;
158*3117ece4Schristos         blockSizes[nbBlocks-1] = srcSize - (blockSize * (nbBlocks-1));
159*3117ece4Schristos     }
160*3117ece4Schristos     {   size_t const dictSize = ZDICT_trainFromBuffer(dict.start, requestedDictSize, src, blockSizes, (unsigned)nbBlocks);
161*3117ece4Schristos         free(blockSizes);
162*3117ece4Schristos         if (ZDICT_isError(dictSize)) { FUZ_freeDictionary(dict); return kBuffNull; }
163*3117ece4Schristos         dict.size = requestedDictSize;
164*3117ece4Schristos         dict.filled = dictSize;
165*3117ece4Schristos         return dict;
166*3117ece4Schristos     }
167*3117ece4Schristos }
168*3117ece4Schristos 
169*3117ece4Schristos /* Round trips data and updates xxh with the decompressed data produced */
170*3117ece4Schristos static size_t SEQ_roundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
171*3117ece4Schristos                             XXH64_state_t* xxh, void* data, size_t size,
172*3117ece4Schristos                             ZSTD_EndDirective endOp)
173*3117ece4Schristos {
174*3117ece4Schristos     static BYTE compressed[1024];
175*3117ece4Schristos     static BYTE uncompressed[1024];
176*3117ece4Schristos 
177*3117ece4Schristos     ZSTD_inBuffer cin = {data, size, 0};
178*3117ece4Schristos     size_t cret;
179*3117ece4Schristos 
180*3117ece4Schristos     do {
181*3117ece4Schristos         ZSTD_outBuffer cout = { compressed, sizeof(compressed), 0 };
182*3117ece4Schristos         ZSTD_inBuffer din   = { compressed, 0, 0 };
183*3117ece4Schristos         ZSTD_outBuffer dout = { uncompressed, 0, 0 };
184*3117ece4Schristos 
185*3117ece4Schristos         cret = ZSTD_compressStream2(cctx, &cout, &cin, endOp);
186*3117ece4Schristos         if (ZSTD_isError(cret))
187*3117ece4Schristos             return cret;
188*3117ece4Schristos 
189*3117ece4Schristos         din.size = cout.pos;
190*3117ece4Schristos         while (din.pos < din.size || (endOp == ZSTD_e_end && cret == 0)) {
191*3117ece4Schristos             size_t dret;
192*3117ece4Schristos 
193*3117ece4Schristos             dout.pos = 0;
194*3117ece4Schristos             dout.size = sizeof(uncompressed);
195*3117ece4Schristos             dret = ZSTD_decompressStream(dctx, &dout, &din);
196*3117ece4Schristos             if (ZSTD_isError(dret))
197*3117ece4Schristos                 return dret;
198*3117ece4Schristos             XXH64_update(xxh, dout.dst, dout.pos);
199*3117ece4Schristos             if (dret == 0)
200*3117ece4Schristos                 break;
201*3117ece4Schristos         }
202*3117ece4Schristos     } while (cin.pos < cin.size || (endOp != ZSTD_e_continue && cret != 0));
203*3117ece4Schristos     return 0;
204*3117ece4Schristos }
205*3117ece4Schristos 
206*3117ece4Schristos /* Generates some data and round trips it */
207*3117ece4Schristos static size_t SEQ_generateRoundTrip(ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
208*3117ece4Schristos                                     XXH64_state_t* xxh, SEQ_stream* seq,
209*3117ece4Schristos                                     SEQ_gen_type type, unsigned value)
210*3117ece4Schristos {
211*3117ece4Schristos     static BYTE data[1024];
212*3117ece4Schristos     size_t gen;
213*3117ece4Schristos 
214*3117ece4Schristos     do {
215*3117ece4Schristos         SEQ_outBuffer sout = {data, sizeof(data), 0};
216*3117ece4Schristos         size_t ret;
217*3117ece4Schristos         gen = SEQ_gen(seq, type, value, &sout);
218*3117ece4Schristos 
219*3117ece4Schristos         ret = SEQ_roundTrip(cctx, dctx, xxh, sout.dst, sout.pos, ZSTD_e_continue);
220*3117ece4Schristos         if (ZSTD_isError(ret))
221*3117ece4Schristos             return ret;
222*3117ece4Schristos     } while (gen != 0);
223*3117ece4Schristos 
224*3117ece4Schristos     return 0;
225*3117ece4Schristos }
226*3117ece4Schristos 
227*3117ece4Schristos static size_t getCCtxParams(ZSTD_CCtx* zc, ZSTD_parameters* savedParams)
228*3117ece4Schristos {
229*3117ece4Schristos     int value;
230*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_windowLog, (int*)&savedParams->cParams.windowLog));
231*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_hashLog, (int*)&savedParams->cParams.hashLog));
232*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_chainLog, (int*)&savedParams->cParams.chainLog));
233*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_searchLog, (int*)&savedParams->cParams.searchLog));
234*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_minMatch, (int*)&savedParams->cParams.minMatch));
235*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetLength, (int*)&savedParams->cParams.targetLength));
236*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_strategy, &value));
237*3117ece4Schristos     savedParams->cParams.strategy = value;
238*3117ece4Schristos 
239*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_checksumFlag, &savedParams->fParams.checksumFlag));
240*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_contentSizeFlag, &savedParams->fParams.contentSizeFlag));
241*3117ece4Schristos     CHECK_RET_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_dictIDFlag, &value));
242*3117ece4Schristos     savedParams->fParams.noDictIDFlag = !value;
243*3117ece4Schristos     return 0;
244*3117ece4Schristos }
245*3117ece4Schristos 
246*3117ece4Schristos static U32 badParameters(ZSTD_CCtx* zc, ZSTD_parameters const savedParams)
247*3117ece4Schristos {
248*3117ece4Schristos     ZSTD_parameters params;
249*3117ece4Schristos     if (ZSTD_isError(getCCtxParams(zc, &params))) return 10;
250*3117ece4Schristos     CHECK_RET(1, params.cParams.windowLog != savedParams.cParams.windowLog, "windowLog");
251*3117ece4Schristos     CHECK_RET(2, params.cParams.hashLog != savedParams.cParams.hashLog, "hashLog");
252*3117ece4Schristos     CHECK_RET(3, params.cParams.chainLog != savedParams.cParams.chainLog, "chainLog");
253*3117ece4Schristos     CHECK_RET(4, params.cParams.searchLog != savedParams.cParams.searchLog, "searchLog");
254*3117ece4Schristos     CHECK_RET(5, params.cParams.minMatch != savedParams.cParams.minMatch, "minMatch");
255*3117ece4Schristos     CHECK_RET(6, params.cParams.targetLength != savedParams.cParams.targetLength, "targetLength");
256*3117ece4Schristos 
257*3117ece4Schristos     CHECK_RET(7, params.fParams.checksumFlag != savedParams.fParams.checksumFlag, "checksumFlag");
258*3117ece4Schristos     CHECK_RET(8, params.fParams.contentSizeFlag != savedParams.fParams.contentSizeFlag, "contentSizeFlag");
259*3117ece4Schristos     CHECK_RET(9, params.fParams.noDictIDFlag != savedParams.fParams.noDictIDFlag, "noDictIDFlag");
260*3117ece4Schristos     return 0;
261*3117ece4Schristos }
262*3117ece4Schristos 
263*3117ece4Schristos static int basicUnitTests(U32 seed, double compressibility, int bigTests)
264*3117ece4Schristos {
265*3117ece4Schristos     size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH;
266*3117ece4Schristos     void* CNBuffer = malloc(CNBufferSize);
267*3117ece4Schristos     size_t const skippableFrameSize = 200 KB;
268*3117ece4Schristos     size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH);
269*3117ece4Schristos     void* compressedBuffer = malloc(compressedBufferSize);
270*3117ece4Schristos     size_t const decodedBufferSize = CNBufferSize;
271*3117ece4Schristos     void* decodedBuffer = malloc(decodedBufferSize);
272*3117ece4Schristos     size_t cSize;
273*3117ece4Schristos     int testResult = 0;
274*3117ece4Schristos     int testNb = 1;
275*3117ece4Schristos     U32 coreSeed = 0;  /* this name to conform with CHECK_Z macro display */
276*3117ece4Schristos     ZSTD_CStream* zc = ZSTD_createCStream();
277*3117ece4Schristos     ZSTD_DStream* zd = ZSTD_createDStream();
278*3117ece4Schristos     ZSTD_CCtx* mtctx = ZSTD_createCCtx();
279*3117ece4Schristos 
280*3117ece4Schristos     ZSTD_inBuffer  inBuff, inBuff2;
281*3117ece4Schristos     ZSTD_outBuffer outBuff;
282*3117ece4Schristos     buffer_t dictionary = kBuffNull;
283*3117ece4Schristos     size_t const dictSize = 128 KB;
284*3117ece4Schristos     unsigned dictID = 0;
285*3117ece4Schristos 
286*3117ece4Schristos     /* Create compressible test buffer */
287*3117ece4Schristos     if (!CNBuffer || !compressedBuffer || !decodedBuffer || !zc || !zd || !mtctx) {
288*3117ece4Schristos         DISPLAY("Not enough memory, aborting \n");
289*3117ece4Schristos         goto _output_error;
290*3117ece4Schristos     }
291*3117ece4Schristos     RDG_genBuffer(CNBuffer, CNBufferSize, compressibility, 0., seed);
292*3117ece4Schristos 
293*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(mtctx, ZSTD_c_nbWorkers, 2));
294*3117ece4Schristos 
295*3117ece4Schristos     /* Create dictionary */
296*3117ece4Schristos     DISPLAYLEVEL(3, "creating dictionary for unit tests \n");
297*3117ece4Schristos     dictionary = FUZ_createDictionary(CNBuffer, CNBufferSize / 3, 16 KB, 48 KB);
298*3117ece4Schristos     if (!dictionary.start) {
299*3117ece4Schristos         DISPLAY("Error creating dictionary, aborting \n");
300*3117ece4Schristos         goto _output_error;
301*3117ece4Schristos     }
302*3117ece4Schristos     dictID = ZDICT_getDictID(dictionary.start, dictionary.filled);
303*3117ece4Schristos 
304*3117ece4Schristos     /* Basic compression test */
305*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
306*3117ece4Schristos     CHECK_Z( ZSTD_initCStream(zc, 1 /* cLevel */) );
307*3117ece4Schristos     outBuff.dst = (char*)(compressedBuffer);
308*3117ece4Schristos     outBuff.size = compressedBufferSize;
309*3117ece4Schristos     outBuff.pos = 0;
310*3117ece4Schristos     inBuff.src = CNBuffer;
311*3117ece4Schristos     inBuff.size = CNBufferSize;
312*3117ece4Schristos     inBuff.pos = 0;
313*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
314*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
315*3117ece4Schristos     { size_t const r = ZSTD_endStream(zc, &outBuff);
316*3117ece4Schristos       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
317*3117ece4Schristos     DISPLAYLEVEL(3, "OK (%u bytes)\n", (unsigned)outBuff.pos);
318*3117ece4Schristos 
319*3117ece4Schristos     /* generate skippable frame */
320*3117ece4Schristos     MEM_writeLE32(compressedBuffer, ZSTD_MAGIC_SKIPPABLE_START);
321*3117ece4Schristos     MEM_writeLE32(((char*)compressedBuffer)+4, (U32)skippableFrameSize);
322*3117ece4Schristos     cSize = skippableFrameSize + 8;
323*3117ece4Schristos 
324*3117ece4Schristos     /* Basic compression test using dict */
325*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : skipframe + compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
326*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
327*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
328*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_loadDictionary(zc, CNBuffer, dictSize) );
329*3117ece4Schristos     outBuff.dst = (char*)(compressedBuffer)+cSize;
330*3117ece4Schristos     assert(compressedBufferSize > cSize);
331*3117ece4Schristos     outBuff.size = compressedBufferSize - cSize;
332*3117ece4Schristos     outBuff.pos = 0;
333*3117ece4Schristos     inBuff.src = CNBuffer;
334*3117ece4Schristos     inBuff.size = CNBufferSize;
335*3117ece4Schristos     inBuff.pos = 0;
336*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
337*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
338*3117ece4Schristos     { size_t const r = ZSTD_endStream(zc, &outBuff);
339*3117ece4Schristos       if (r != 0) goto _output_error; }  /* error, or some data not flushed */
340*3117ece4Schristos     cSize += outBuff.pos;
341*3117ece4Schristos     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n",
342*3117ece4Schristos                     (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
343*3117ece4Schristos 
344*3117ece4Schristos     /* context size functions */
345*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : estimate CStream size : ", testNb++);
346*3117ece4Schristos     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictSize);
347*3117ece4Schristos         size_t const cstreamSize = ZSTD_estimateCStreamSize_usingCParams(cParams);
348*3117ece4Schristos         size_t const cdictSize = ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); /* uses ZSTD_initCStream_usingDict() */
349*3117ece4Schristos         if (ZSTD_isError(cstreamSize)) goto _output_error;
350*3117ece4Schristos         if (ZSTD_isError(cdictSize)) goto _output_error;
351*3117ece4Schristos         DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)(cstreamSize + cdictSize));
352*3117ece4Schristos     }
353*3117ece4Schristos 
354*3117ece4Schristos     /* context size functions */
355*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : estimate CStream size using CCtxParams : ", testNb++);
356*3117ece4Schristos     {   ZSTD_CCtx_params* const params = ZSTD_createCCtxParams();
357*3117ece4Schristos         size_t cstreamSize, cctxSize;
358*3117ece4Schristos         CHECK_Z( ZSTD_CCtxParams_setParameter(params, ZSTD_c_compressionLevel, 19) );
359*3117ece4Schristos         cstreamSize = ZSTD_estimateCStreamSize_usingCCtxParams(params);
360*3117ece4Schristos         CHECK_Z(cstreamSize);
361*3117ece4Schristos         cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
362*3117ece4Schristos         CHECK_Z(cctxSize);
363*3117ece4Schristos         if (cstreamSize <= cctxSize + 2 * ZSTD_BLOCKSIZE_MAX) goto _output_error;
364*3117ece4Schristos         ZSTD_freeCCtxParams(params);
365*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
366*3117ece4Schristos     }
367*3117ece4Schristos 
368*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : check actual CStream size : ", testNb++);
369*3117ece4Schristos     {   size_t const s = ZSTD_sizeof_CStream(zc);
370*3117ece4Schristos         if (ZSTD_isError(s)) goto _output_error;
371*3117ece4Schristos         DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
372*3117ece4Schristos     }
373*3117ece4Schristos 
374*3117ece4Schristos     /* Attempt bad compression parameters */
375*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : use bad compression parameters with ZSTD_initCStream_advanced : ", testNb++);
376*3117ece4Schristos     {   size_t r;
377*3117ece4Schristos         ZSTD_parameters params = ZSTD_getParams(1, 0, 0);
378*3117ece4Schristos         params.cParams.minMatch = 2;
379*3117ece4Schristos         r = ZSTD_initCStream_advanced(zc, NULL, 0, params, 0);
380*3117ece4Schristos         if (!ZSTD_isError(r)) goto _output_error;
381*3117ece4Schristos         DISPLAYLEVEL(3, "init error : %s \n", ZSTD_getErrorName(r));
382*3117ece4Schristos     }
383*3117ece4Schristos 
384*3117ece4Schristos     /* skippable frame test */
385*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress skippable frame : ", testNb++);
386*3117ece4Schristos     CHECK_Z( ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize) );
387*3117ece4Schristos     inBuff.src = compressedBuffer;
388*3117ece4Schristos     inBuff.size = cSize;
389*3117ece4Schristos     inBuff.pos = 0;
390*3117ece4Schristos     outBuff.dst = decodedBuffer;
391*3117ece4Schristos     outBuff.size = CNBufferSize;
392*3117ece4Schristos     outBuff.pos = 0;
393*3117ece4Schristos     {   size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
394*3117ece4Schristos         DISPLAYLEVEL(5, " ( ZSTD_decompressStream => %u ) ", (unsigned)r);
395*3117ece4Schristos         if (r != 0) goto _output_error;
396*3117ece4Schristos     }
397*3117ece4Schristos     if (outBuff.pos != 0) goto _output_error;   /* skippable frame output len is 0 */
398*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
399*3117ece4Schristos 
400*3117ece4Schristos     /* Basic decompression test */
401*3117ece4Schristos     inBuff2 = inBuff;
402*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
403*3117ece4Schristos     ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
404*3117ece4Schristos     CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, ZSTD_WINDOWLOG_LIMIT_DEFAULT+1) );  /* large limit */
405*3117ece4Schristos     { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff);
406*3117ece4Schristos       if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
407*3117ece4Schristos     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
408*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
409*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
410*3117ece4Schristos 
411*3117ece4Schristos     /* Reuse without init */
412*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress again without init (reuse previous settings): ", testNb++);
413*3117ece4Schristos     outBuff.pos = 0;
414*3117ece4Schristos     { size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inBuff2);
415*3117ece4Schristos       if (remaining != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
416*3117ece4Schristos     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
417*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
418*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
419*3117ece4Schristos 
420*3117ece4Schristos     /* check regenerated data is byte exact */
421*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
422*3117ece4Schristos     {   size_t i;
423*3117ece4Schristos         for (i=0; i<CNBufferSize; i++) {
424*3117ece4Schristos             if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
425*3117ece4Schristos     }   }
426*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
427*3117ece4Schristos 
428*3117ece4Schristos     /* check decompression fails early if first bytes are wrong */
429*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : early decompression error if first bytes are incorrect : ", testNb++);
430*3117ece4Schristos     {   const char buf[3] = { 0 };  /* too short, not enough to start decoding header */
431*3117ece4Schristos         ZSTD_inBuffer inb = { buf, sizeof(buf), 0 };
432*3117ece4Schristos         size_t const remaining = ZSTD_decompressStream(zd, &outBuff, &inb);
433*3117ece4Schristos         if (!ZSTD_isError(remaining)) goto _output_error; /* should have errored out immediately (note: this does not test the exact error code) */
434*3117ece4Schristos     }
435*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
436*3117ece4Schristos 
437*3117ece4Schristos     /* context size functions */
438*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : estimate DStream size : ", testNb++);
439*3117ece4Schristos     {   ZSTD_frameHeader fhi;
440*3117ece4Schristos         const void* cStart = (char*)compressedBuffer + (skippableFrameSize + 8);
441*3117ece4Schristos         size_t const gfhError = ZSTD_getFrameHeader(&fhi, cStart, cSize);
442*3117ece4Schristos         if (gfhError!=0) goto _output_error;
443*3117ece4Schristos         DISPLAYLEVEL(5, " (windowSize : %u) ", (unsigned)fhi.windowSize);
444*3117ece4Schristos         {   size_t const s = ZSTD_estimateDStreamSize(fhi.windowSize)
445*3117ece4Schristos                             /* uses ZSTD_initDStream_usingDict() */
446*3117ece4Schristos                            + ZSTD_estimateDDictSize(dictSize, ZSTD_dlm_byCopy);
447*3117ece4Schristos             if (ZSTD_isError(s)) goto _output_error;
448*3117ece4Schristos             DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
449*3117ece4Schristos     }   }
450*3117ece4Schristos 
451*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : check actual DStream size : ", testNb++);
452*3117ece4Schristos     { size_t const s = ZSTD_sizeof_DStream(zd);
453*3117ece4Schristos       if (ZSTD_isError(s)) goto _output_error;
454*3117ece4Schristos       DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
455*3117ece4Schristos     }
456*3117ece4Schristos 
457*3117ece4Schristos     /* Decompression by small increment */
458*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress byte-by-byte : ", testNb++);
459*3117ece4Schristos     {   /* skippable frame */
460*3117ece4Schristos         size_t r = 1;
461*3117ece4Schristos         ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
462*3117ece4Schristos         inBuff.src = compressedBuffer;
463*3117ece4Schristos         outBuff.dst = decodedBuffer;
464*3117ece4Schristos         inBuff.pos = 0;
465*3117ece4Schristos         outBuff.pos = 0;
466*3117ece4Schristos         while (r) {   /* skippable frame */
467*3117ece4Schristos             size_t const inSize = (FUZ_rand(&coreSeed) & 15) + 1;
468*3117ece4Schristos             size_t const outSize = (FUZ_rand(&coreSeed) & 15) + 1;
469*3117ece4Schristos             inBuff.size = inBuff.pos + inSize;
470*3117ece4Schristos             outBuff.size = outBuff.pos + outSize;
471*3117ece4Schristos             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
472*3117ece4Schristos             if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream on skippable frame error : %s \n", ZSTD_getErrorName(r));
473*3117ece4Schristos             if (ZSTD_isError(r)) goto _output_error;
474*3117ece4Schristos         }
475*3117ece4Schristos         /* normal frame */
476*3117ece4Schristos         ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
477*3117ece4Schristos         r=1;
478*3117ece4Schristos         while (r) {
479*3117ece4Schristos             size_t const inSize = FUZ_rand(&coreSeed) & 15;
480*3117ece4Schristos             size_t const outSize = (FUZ_rand(&coreSeed) & 15) + (!inSize);   /* avoid having both sizes at 0 => would trigger a no_forward_progress error */
481*3117ece4Schristos             inBuff.size = inBuff.pos + inSize;
482*3117ece4Schristos             outBuff.size = outBuff.pos + outSize;
483*3117ece4Schristos             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
484*3117ece4Schristos             if (ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(r));
485*3117ece4Schristos             if (ZSTD_isError(r)) goto _output_error;
486*3117ece4Schristos         }
487*3117ece4Schristos     }
488*3117ece4Schristos     if (outBuff.pos != CNBufferSize) DISPLAYLEVEL(4, "outBuff.pos != CNBufferSize : should have regenerated same amount ! \n");
489*3117ece4Schristos     if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
490*3117ece4Schristos     if (inBuff.pos != cSize) DISPLAYLEVEL(4, "inBuff.pos != cSize : should have real all input ! \n");
491*3117ece4Schristos     if (inBuff.pos != cSize) goto _output_error;   /* should have read the entire frame */
492*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
493*3117ece4Schristos 
494*3117ece4Schristos     /* check regenerated data is byte exact */
495*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : check decompressed result : ", testNb++);
496*3117ece4Schristos     {   size_t i;
497*3117ece4Schristos         for (i=0; i<CNBufferSize; i++) {
498*3117ece4Schristos             if (((BYTE*)decodedBuffer)[i] != ((BYTE*)CNBuffer)[i]) goto _output_error;
499*3117ece4Schristos     }   }
500*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
501*3117ece4Schristos 
502*3117ece4Schristos     /* Decompression forward progress */
503*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : generate error when ZSTD_decompressStream() doesn't progress : ", testNb++);
504*3117ece4Schristos     {   /* skippable frame */
505*3117ece4Schristos         size_t r = 0;
506*3117ece4Schristos         int decNb = 0;
507*3117ece4Schristos         int const maxDec = 100;
508*3117ece4Schristos         inBuff.src = compressedBuffer;
509*3117ece4Schristos         inBuff.size = cSize;
510*3117ece4Schristos         inBuff.pos = 0;
511*3117ece4Schristos 
512*3117ece4Schristos         outBuff.dst = decodedBuffer;
513*3117ece4Schristos         outBuff.pos = 0;
514*3117ece4Schristos         outBuff.size = CNBufferSize-1;   /* 1 byte missing */
515*3117ece4Schristos 
516*3117ece4Schristos         for (decNb=0; decNb<maxDec; decNb++) {
517*3117ece4Schristos             if (r==0) ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
518*3117ece4Schristos             r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
519*3117ece4Schristos             if (ZSTD_isError(r)) break;
520*3117ece4Schristos         }
521*3117ece4Schristos         if (!ZSTD_isError(r)) DISPLAYLEVEL(4, "ZSTD_decompressStream should have triggered a no_forward_progress error \n");
522*3117ece4Schristos         if (!ZSTD_isError(r)) goto _output_error;   /* should have triggered no_forward_progress error */
523*3117ece4Schristos     }
524*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
525*3117ece4Schristos 
526*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : NULL output and NULL input : ", testNb++);
527*3117ece4Schristos     inBuff.src = NULL;
528*3117ece4Schristos     inBuff.size = 0;
529*3117ece4Schristos     inBuff.pos = 0;
530*3117ece4Schristos     outBuff.dst = NULL;
531*3117ece4Schristos     outBuff.size = 0;
532*3117ece4Schristos     outBuff.pos = 0;
533*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
534*3117ece4Schristos     CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
535*3117ece4Schristos     CHECK_Z( ZSTD_endStream(zc, &outBuff) );
536*3117ece4Schristos     outBuff.dst = (char*)(compressedBuffer);
537*3117ece4Schristos     outBuff.size = compressedBufferSize;
538*3117ece4Schristos     outBuff.pos = 0;
539*3117ece4Schristos     {   size_t const r = ZSTD_endStream(zc, &outBuff);
540*3117ece4Schristos         CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
541*3117ece4Schristos     }
542*3117ece4Schristos     inBuff.src = outBuff.dst;
543*3117ece4Schristos     inBuff.size = outBuff.pos;
544*3117ece4Schristos     inBuff.pos = 0;
545*3117ece4Schristos     outBuff.dst = NULL;
546*3117ece4Schristos     outBuff.size = 0;
547*3117ece4Schristos     outBuff.pos = 0;
548*3117ece4Schristos     CHECK_Z( ZSTD_initDStream(zd) );
549*3117ece4Schristos     {   size_t const ret = ZSTD_decompressStream(zd, &outBuff, &inBuff);
550*3117ece4Schristos         if (ret != 0) goto _output_error;
551*3117ece4Schristos     }
552*3117ece4Schristos     DISPLAYLEVEL(3, "OK\n");
553*3117ece4Schristos 
554*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : NULL output buffer with non-NULL input : ", testNb++);
555*3117ece4Schristos     {
556*3117ece4Schristos         const char* test = "aa";
557*3117ece4Schristos         inBuff.src = test;
558*3117ece4Schristos         inBuff.size = 2;
559*3117ece4Schristos         inBuff.pos = 0;
560*3117ece4Schristos         outBuff.dst = NULL;
561*3117ece4Schristos         outBuff.size = 0;
562*3117ece4Schristos         outBuff.pos = 0;
563*3117ece4Schristos         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
564*3117ece4Schristos         CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
565*3117ece4Schristos         CHECK_Z( ZSTD_endStream(zc, &outBuff) );
566*3117ece4Schristos         outBuff.dst = (char*)(compressedBuffer);
567*3117ece4Schristos         outBuff.size = compressedBufferSize;
568*3117ece4Schristos         outBuff.pos = 0;
569*3117ece4Schristos         {   size_t const r = ZSTD_endStream(zc, &outBuff);
570*3117ece4Schristos             CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
571*3117ece4Schristos         }
572*3117ece4Schristos         inBuff.src = outBuff.dst;
573*3117ece4Schristos         inBuff.size = outBuff.pos;
574*3117ece4Schristos         inBuff.pos = 0;
575*3117ece4Schristos         outBuff.dst = NULL;
576*3117ece4Schristos         outBuff.size = 0;
577*3117ece4Schristos         outBuff.pos = 0;
578*3117ece4Schristos         CHECK_Z( ZSTD_initDStream(zd) );
579*3117ece4Schristos         CHECK_Z(ZSTD_decompressStream(zd, &outBuff, &inBuff));
580*3117ece4Schristos     }
581*3117ece4Schristos 
582*3117ece4Schristos     DISPLAYLEVEL(3, "OK\n");
583*3117ece4Schristos     /* _srcSize compression test */
584*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : compress_srcSize %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
585*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
586*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );
587*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
588*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize) );
589*3117ece4Schristos     outBuff.dst = (char*)(compressedBuffer);
590*3117ece4Schristos     outBuff.size = compressedBufferSize;
591*3117ece4Schristos     outBuff.pos = 0;
592*3117ece4Schristos     inBuff.src = CNBuffer;
593*3117ece4Schristos     inBuff.size = CNBufferSize;
594*3117ece4Schristos     inBuff.pos = 0;
595*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
596*3117ece4Schristos     CHECK(inBuff.pos != inBuff.size, "Entire input should be consumed");
597*3117ece4Schristos     {   size_t const r = ZSTD_endStream(zc, &outBuff);
598*3117ece4Schristos         CHECK(r != 0, "Error or some data not flushed (ret=%zu)", r);
599*3117ece4Schristos     }
600*3117ece4Schristos     {   unsigned long long origSize = ZSTD_findDecompressedSize(outBuff.dst, outBuff.pos);
601*3117ece4Schristos         CHECK(origSize == ZSTD_CONTENTSIZE_UNKNOWN, "Unknown!");
602*3117ece4Schristos         CHECK((size_t)origSize != CNBufferSize, "Exact original size must be present (got %llu)", origSize);
603*3117ece4Schristos     }
604*3117ece4Schristos     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100);
605*3117ece4Schristos 
606*3117ece4Schristos     /* wrong _srcSize compression test */
607*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : too large srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
608*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
609*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );
610*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
611*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize+1) );
612*3117ece4Schristos     outBuff.dst = (char*)(compressedBuffer);
613*3117ece4Schristos     outBuff.size = compressedBufferSize;
614*3117ece4Schristos     outBuff.pos = 0;
615*3117ece4Schristos     inBuff.src = CNBuffer;
616*3117ece4Schristos     inBuff.size = CNBufferSize;
617*3117ece4Schristos     inBuff.pos = 0;
618*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
619*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
620*3117ece4Schristos     { size_t const r = ZSTD_endStream(zc, &outBuff);
621*3117ece4Schristos       if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
622*3117ece4Schristos       DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r)); }
623*3117ece4Schristos 
624*3117ece4Schristos     /* wrong _srcSize compression test */
625*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : too small srcSize : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
626*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
627*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );
628*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 1) );
629*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize-1) );
630*3117ece4Schristos     outBuff.dst = (char*)(compressedBuffer);
631*3117ece4Schristos     outBuff.size = compressedBufferSize;
632*3117ece4Schristos     outBuff.pos = 0;
633*3117ece4Schristos     inBuff.src = CNBuffer;
634*3117ece4Schristos     inBuff.size = CNBufferSize;
635*3117ece4Schristos     inBuff.pos = 0;
636*3117ece4Schristos     {   size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
637*3117ece4Schristos         if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
638*3117ece4Schristos         DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
639*3117ece4Schristos     }
640*3117ece4Schristos 
641*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : wrong srcSize !contentSizeFlag : %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH-1);
642*3117ece4Schristos     {   CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
643*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_contentSizeFlag, 0) );
644*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, CNBufferSize - MIN(CNBufferSize, 200 KB)) );
645*3117ece4Schristos         outBuff.dst = (char*)compressedBuffer;
646*3117ece4Schristos         outBuff.size = compressedBufferSize;
647*3117ece4Schristos         outBuff.pos = 0;
648*3117ece4Schristos         inBuff.src = CNBuffer;
649*3117ece4Schristos         inBuff.size = CNBufferSize;
650*3117ece4Schristos         inBuff.pos = 0;
651*3117ece4Schristos         {   size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff);
652*3117ece4Schristos             if (ZSTD_getErrorCode(r) != ZSTD_error_srcSize_wrong) goto _output_error;    /* must fail : wrong srcSize */
653*3117ece4Schristos             DISPLAYLEVEL(3, "OK (error detected : %s) \n", ZSTD_getErrorName(r));
654*3117ece4Schristos     }   }
655*3117ece4Schristos 
656*3117ece4Schristos     /* Compression state reuse scenario */
657*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : context reuse : ", testNb++);
658*3117ece4Schristos     ZSTD_freeCStream(zc);
659*3117ece4Schristos     zc = ZSTD_createCStream();
660*3117ece4Schristos     if (zc==NULL) goto _output_error;   /* memory allocation issue */
661*3117ece4Schristos     /* use 1 */
662*3117ece4Schristos     {   size_t const inSize = 513;
663*3117ece4Schristos         DISPLAYLEVEL(5, "use1 ");
664*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
665*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 19) );
666*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, inSize) );
667*3117ece4Schristos         inBuff.src = CNBuffer;
668*3117ece4Schristos         inBuff.size = inSize;
669*3117ece4Schristos         inBuff.pos = 0;
670*3117ece4Schristos         outBuff.dst = (char*)(compressedBuffer)+cSize;
671*3117ece4Schristos         outBuff.size = ZSTD_compressBound(inSize);
672*3117ece4Schristos         outBuff.pos = 0;
673*3117ece4Schristos         DISPLAYLEVEL(5, "compress1 ");
674*3117ece4Schristos         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
675*3117ece4Schristos         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
676*3117ece4Schristos         DISPLAYLEVEL(5, "end1 ");
677*3117ece4Schristos         if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;  /* error, or some data not flushed */
678*3117ece4Schristos     }
679*3117ece4Schristos     /* use 2 */
680*3117ece4Schristos     {   size_t const inSize = 1025;   /* will not continue, because tables auto-adjust and are therefore different size */
681*3117ece4Schristos         DISPLAYLEVEL(5, "use2 ");
682*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
683*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 19) );
684*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, inSize) );
685*3117ece4Schristos         inBuff.src = CNBuffer;
686*3117ece4Schristos         inBuff.size = inSize;
687*3117ece4Schristos         inBuff.pos = 0;
688*3117ece4Schristos         outBuff.dst = (char*)(compressedBuffer)+cSize;
689*3117ece4Schristos         outBuff.size = ZSTD_compressBound(inSize);
690*3117ece4Schristos         outBuff.pos = 0;
691*3117ece4Schristos         DISPLAYLEVEL(5, "compress2 ");
692*3117ece4Schristos         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
693*3117ece4Schristos         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
694*3117ece4Schristos         DISPLAYLEVEL(5, "end2 ");
695*3117ece4Schristos         if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;   /* error, or some data not flushed */
696*3117ece4Schristos     }
697*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
698*3117ece4Schristos 
699*3117ece4Schristos     /* Decompression single pass with empty frame */
700*3117ece4Schristos     cSize = ZSTD_compress(compressedBuffer, compressedBufferSize, NULL, 0, 1);
701*3117ece4Schristos     CHECK_Z(cSize);
702*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() single pass on empty frame : ", testNb++);
703*3117ece4Schristos     {   ZSTD_DCtx* dctx = ZSTD_createDCtx();
704*3117ece4Schristos         size_t const dctxSize = ZSTD_sizeof_DCtx(dctx);
705*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
706*3117ece4Schristos 
707*3117ece4Schristos         outBuff.dst = decodedBuffer;
708*3117ece4Schristos         outBuff.pos = 0;
709*3117ece4Schristos         outBuff.size = CNBufferSize;
710*3117ece4Schristos 
711*3117ece4Schristos         inBuff.src = compressedBuffer;
712*3117ece4Schristos         inBuff.size = cSize;
713*3117ece4Schristos         inBuff.pos = 0;
714*3117ece4Schristos         {   size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
715*3117ece4Schristos             CHECK_Z(r);
716*3117ece4Schristos             CHECK(r != 0, "Entire frame must be decompressed");
717*3117ece4Schristos             CHECK(outBuff.pos != 0, "Wrong size!");
718*3117ece4Schristos             CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
719*3117ece4Schristos         }
720*3117ece4Schristos         CHECK(dctxSize != ZSTD_sizeof_DCtx(dctx), "No buffers allocated");
721*3117ece4Schristos         ZSTD_freeDCtx(dctx);
722*3117ece4Schristos     }
723*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
724*3117ece4Schristos 
725*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : maxBlockSize = 2KB : ", testNb++);
726*3117ece4Schristos     {
727*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
728*3117ece4Schristos         size_t singlePassSize, streamingSize, streaming2KSize;
729*3117ece4Schristos 
730*3117ece4Schristos         {
731*3117ece4Schristos             ZSTD_CCtx* cctx = ZSTD_createCCtx();
732*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
733*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 18));
734*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, 0));
735*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 2048));
736*3117ece4Schristos             cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize);
737*3117ece4Schristos             CHECK_Z(cSize);
738*3117ece4Schristos             ZSTD_freeCCtx(cctx);
739*3117ece4Schristos         }
740*3117ece4Schristos 
741*3117ece4Schristos         CHECK_Z(ZSTD_decompressDCtx(dctx, decodedBuffer, CNBufferSize, compressedBuffer, cSize));
742*3117ece4Schristos         singlePassSize = ZSTD_sizeof_DCtx(dctx);
743*3117ece4Schristos         CHECK_Z(singlePassSize);
744*3117ece4Schristos 
745*3117ece4Schristos         inBuff.src = compressedBuffer;
746*3117ece4Schristos         inBuff.size = cSize;
747*3117ece4Schristos 
748*3117ece4Schristos         outBuff.dst = decodedBuffer;
749*3117ece4Schristos         outBuff.size = decodedBufferSize;
750*3117ece4Schristos 
751*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_maxBlockSize, 2048));
752*3117ece4Schristos         inBuff.pos = 0;
753*3117ece4Schristos         outBuff.pos = 0;
754*3117ece4Schristos         {
755*3117ece4Schristos             size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
756*3117ece4Schristos             CHECK_Z(r);
757*3117ece4Schristos             CHECK(r != 0, "Entire frame must be decompressed");
758*3117ece4Schristos         }
759*3117ece4Schristos         streaming2KSize = ZSTD_sizeof_DCtx(dctx);
760*3117ece4Schristos         CHECK_Z(streaming2KSize);
761*3117ece4Schristos 
762*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
763*3117ece4Schristos         inBuff.pos = 0;
764*3117ece4Schristos         outBuff.pos = 0;
765*3117ece4Schristos         {
766*3117ece4Schristos             size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
767*3117ece4Schristos             CHECK_Z(r);
768*3117ece4Schristos             CHECK(r != 0, "Entire frame must be decompressed");
769*3117ece4Schristos         }
770*3117ece4Schristos         streamingSize = ZSTD_sizeof_DCtx(dctx);
771*3117ece4Schristos         CHECK_Z(streamingSize);
772*3117ece4Schristos 
773*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_maxBlockSize, 1024));
774*3117ece4Schristos         inBuff.pos = 0;
775*3117ece4Schristos         outBuff.pos = 0;
776*3117ece4Schristos         CHECK(!ZSTD_isError(ZSTD_decompressStream(dctx, &outBuff, &inBuff)), "decompression must fail");
777*3117ece4Schristos 
778*3117ece4Schristos         CHECK(streamingSize < singlePassSize + (1 << 18) + 3 * ZSTD_BLOCKSIZE_MAX, "Streaming doesn't use the right amount of memory");
779*3117ece4Schristos         CHECK(streamingSize != streaming2KSize + 3 * (ZSTD_BLOCKSIZE_MAX - 2048), "ZSTD_d_blockSizeMax didn't save the right amount of memory");
780*3117ece4Schristos         DISPLAYLEVEL(3, "| %zu | %zu | %zu | ", singlePassSize, streaming2KSize, streamingSize);
781*3117ece4Schristos 
782*3117ece4Schristos         ZSTD_freeDCtx(dctx);
783*3117ece4Schristos     }
784*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
785*3117ece4Schristos 
786*3117ece4Schristos     /* Decompression with ZSTD_d_stableOutBuffer */
787*3117ece4Schristos     cSize = ZSTD_compress(compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize, 1);
788*3117ece4Schristos     CHECK_Z(cSize);
789*3117ece4Schristos     {   ZSTD_DCtx* dctx = ZSTD_createDCtx();
790*3117ece4Schristos         size_t const dctxSize0 = ZSTD_sizeof_DCtx(dctx);
791*3117ece4Schristos         size_t dctxSize1;
792*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
793*3117ece4Schristos 
794*3117ece4Schristos         outBuff.dst = decodedBuffer;
795*3117ece4Schristos         outBuff.pos = 0;
796*3117ece4Schristos         outBuff.size = CNBufferSize;
797*3117ece4Schristos 
798*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() single pass : ", testNb++);
799*3117ece4Schristos         inBuff.src = compressedBuffer;
800*3117ece4Schristos         inBuff.size = cSize;
801*3117ece4Schristos         inBuff.pos = 0;
802*3117ece4Schristos         {   size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
803*3117ece4Schristos             CHECK_Z(r);
804*3117ece4Schristos             CHECK(r != 0, "Entire frame must be decompressed");
805*3117ece4Schristos             CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
806*3117ece4Schristos             CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
807*3117ece4Schristos         }
808*3117ece4Schristos         CHECK(dctxSize0 != ZSTD_sizeof_DCtx(dctx), "No buffers allocated");
809*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
810*3117ece4Schristos 
811*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer : ", testNb++);
812*3117ece4Schristos         outBuff.pos = 0;
813*3117ece4Schristos         inBuff.pos = 0;
814*3117ece4Schristos         inBuff.size = 0;
815*3117ece4Schristos         while (inBuff.pos < cSize) {
816*3117ece4Schristos             inBuff.size += MIN(cSize - inBuff.pos, 1 + (FUZ_rand(&coreSeed) & 15));
817*3117ece4Schristos             CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
818*3117ece4Schristos         }
819*3117ece4Schristos         CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
820*3117ece4Schristos         CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
821*3117ece4Schristos         dctxSize1 = ZSTD_sizeof_DCtx(dctx);
822*3117ece4Schristos         CHECK(!(dctxSize0 < dctxSize1), "Input buffer allocated");
823*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
824*3117ece4Schristos 
825*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer too small : ", testNb++);
826*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
827*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
828*3117ece4Schristos         inBuff.src = compressedBuffer;
829*3117ece4Schristos         inBuff.size = cSize;
830*3117ece4Schristos         inBuff.pos = 0;
831*3117ece4Schristos         outBuff.pos = 0;
832*3117ece4Schristos         outBuff.size = CNBufferSize - 1;
833*3117ece4Schristos         {   size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
834*3117ece4Schristos             CHECK(ZSTD_getErrorCode(r) != ZSTD_error_dstSize_tooSmall, "Must error but got %s", ZSTD_getErrorName(r));
835*3117ece4Schristos         }
836*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
837*3117ece4Schristos 
838*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() stable out buffer modified : ", testNb++);
839*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
840*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 1));
841*3117ece4Schristos         inBuff.src = compressedBuffer;
842*3117ece4Schristos         inBuff.size = cSize - 1;
843*3117ece4Schristos         inBuff.pos = 0;
844*3117ece4Schristos         outBuff.pos = 0;
845*3117ece4Schristos         outBuff.size = CNBufferSize;
846*3117ece4Schristos         CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
847*3117ece4Schristos         ++inBuff.size;
848*3117ece4Schristos         outBuff.pos = 0;
849*3117ece4Schristos         {   size_t const r = ZSTD_decompressStream(dctx, &outBuff, &inBuff);
850*3117ece4Schristos             CHECK(ZSTD_getErrorCode(r) != ZSTD_error_dstBuffer_wrong, "Must error but got %s", ZSTD_getErrorName(r));
851*3117ece4Schristos         }
852*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
853*3117ece4Schristos 
854*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() buffered output : ", testNb++);
855*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
856*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_stableOutBuffer, 0));
857*3117ece4Schristos         outBuff.pos = 0;
858*3117ece4Schristos         inBuff.pos = 0;
859*3117ece4Schristos         inBuff.size = 0;
860*3117ece4Schristos         while (inBuff.pos < cSize) {
861*3117ece4Schristos             inBuff.size += MIN(cSize - inBuff.pos, 1 + (FUZ_rand(&coreSeed) & 15));
862*3117ece4Schristos             CHECK_Z(ZSTD_decompressStream(dctx, &outBuff, &inBuff));
863*3117ece4Schristos         }
864*3117ece4Schristos         CHECK(outBuff.pos != CNBufferSize, "Wrong size!");
865*3117ece4Schristos         CHECK(memcmp(CNBuffer, outBuff.dst, CNBufferSize) != 0, "Corruption!");
866*3117ece4Schristos         CHECK(!(dctxSize1 < ZSTD_sizeof_DCtx(dctx)), "Output buffer allocated");
867*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
868*3117ece4Schristos 
869*3117ece4Schristos         ZSTD_freeDCtx(dctx);
870*3117ece4Schristos     }
871*3117ece4Schristos 
872*3117ece4Schristos     /* Compression with ZSTD_c_stable{In,Out}Buffer */
873*3117ece4Schristos     {   ZSTD_CCtx* const cctx = ZSTD_createCCtx();
874*3117ece4Schristos         ZSTD_inBuffer in;
875*3117ece4Schristos         ZSTD_outBuffer out;
876*3117ece4Schristos         size_t cctxSize1;
877*3117ece4Schristos         size_t cctxSize2;
878*3117ece4Schristos         assert(cctx != NULL);
879*3117ece4Schristos         in.src = CNBuffer;
880*3117ece4Schristos         in.size = CNBufferSize;
881*3117ece4Schristos         out.dst = compressedBuffer;
882*3117ece4Schristos         out.size = compressedBufferSize;
883*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
884*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compress2() uses stable input and output : ", testNb++);
885*3117ece4Schristos         CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize));
886*3117ece4Schristos         CHECK(!(cSize < ZSTD_compressBound(CNBufferSize)), "cSize too large for test");
887*3117ece4Schristos         CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, cSize + 4, CNBuffer, CNBufferSize));
888*3117ece4Schristos         CHECK_Z(cctxSize1 = ZSTD_sizeof_CCtx(cctx));
889*3117ece4Schristos         /* @cctxSize2 : sizeof_CCtx when doing full streaming (no stable in/out) */
890*3117ece4Schristos         {   ZSTD_CCtx* const cctx2 = ZSTD_createCCtx();
891*3117ece4Schristos             assert(cctx2 != NULL);
892*3117ece4Schristos             in.pos = out.pos = 0;
893*3117ece4Schristos             CHECK_Z(ZSTD_compressStream2(cctx2, &out, &in, ZSTD_e_continue));
894*3117ece4Schristos             CHECK(!(ZSTD_compressStream2(cctx2, &out, &in, ZSTD_e_end) == 0), "Not finished");
895*3117ece4Schristos             CHECK_Z(cctxSize2 = ZSTD_sizeof_CCtx(cctx2));
896*3117ece4Schristos             ZSTD_freeCCtx(cctx2);
897*3117ece4Schristos         }
898*3117ece4Schristos         /* @cctxSize1 : sizeof_CCtx when doing single-shot compression (no streaming) */
899*3117ece4Schristos         {   ZSTD_CCtx* const cctx1 = ZSTD_createCCtx();
900*3117ece4Schristos             ZSTD_parameters params = ZSTD_getParams(0, CNBufferSize, 0);
901*3117ece4Schristos             size_t cSize3;
902*3117ece4Schristos             assert(cctx1 != NULL);
903*3117ece4Schristos             params.fParams.checksumFlag = 1;
904*3117ece4Schristos             cSize3 = ZSTD_compress_advanced(cctx1, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize, NULL, 0, params);
905*3117ece4Schristos             CHECK_Z(cSize3);
906*3117ece4Schristos             CHECK(!(cSize == cSize3), "Must be same compressed size");
907*3117ece4Schristos             CHECK(!(cctxSize1 == ZSTD_sizeof_CCtx(cctx1)), "Must be same CCtx size");
908*3117ece4Schristos             ZSTD_freeCCtx(cctx1);
909*3117ece4Schristos         }
910*3117ece4Schristos         CHECK(!(cctxSize1 < cctxSize2), "Stable buffers means less allocated size");
911*3117ece4Schristos         CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
912*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
913*3117ece4Schristos 
914*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compress2() doesn't modify user parameters : ", testNb++);
915*3117ece4Schristos         {   int stableInBuffer;
916*3117ece4Schristos             int stableOutBuffer;
917*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableInBuffer, &stableInBuffer));
918*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableOutBuffer, &stableOutBuffer));
919*3117ece4Schristos             CHECK(!(stableInBuffer == 0), "Modified");
920*3117ece4Schristos             CHECK(!(stableOutBuffer == 0), "Modified");
921*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
922*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
923*3117ece4Schristos             CHECK_Z(cSize = ZSTD_compress2(cctx, compressedBuffer, compressedBufferSize, CNBuffer, CNBufferSize));
924*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableInBuffer, &stableInBuffer));
925*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_stableOutBuffer, &stableOutBuffer));
926*3117ece4Schristos             CHECK(!(stableInBuffer == 1), "Modified");
927*3117ece4Schristos             CHECK(!(stableOutBuffer == 1), "Modified");
928*3117ece4Schristos         }
929*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
930*3117ece4Schristos 
931*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer and ZSTD_c_stableOutBuffer : ", testNb++);
932*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
933*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
934*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
935*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
936*3117ece4Schristos         in.pos = out.pos = 0;
937*3117ece4Schristos         CHECK(!(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end) == 0), "Not finished");
938*3117ece4Schristos         CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
939*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
940*3117ece4Schristos 
941*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer and ZSTD_c_stableOutBuffer allocated size : ", testNb++);
942*3117ece4Schristos         {   size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
943*3117ece4Schristos             CHECK(!(cctxSize1 == cctxSize), "Must be the same size as single pass");
944*3117ece4Schristos         }
945*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
946*3117ece4Schristos 
947*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer only : ", testNb++);
948*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
949*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
950*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1));
951*3117ece4Schristos         in.pos = out.pos = 0;
952*3117ece4Schristos         out.size = cSize / 4;
953*3117ece4Schristos         for (;;) {
954*3117ece4Schristos             size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
955*3117ece4Schristos             CHECK_Z(ret);
956*3117ece4Schristos             if (ret == 0)
957*3117ece4Schristos                 break;
958*3117ece4Schristos             out.size = MIN(out.size + cSize / 4, compressedBufferSize);
959*3117ece4Schristos         }
960*3117ece4Schristos         CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
961*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
962*3117ece4Schristos 
963*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableInBuffer modify buffer : ", testNb++);
964*3117ece4Schristos         in.pos = out.pos = 0;
965*3117ece4Schristos         out.size = cSize / 4;
966*3117ece4Schristos         CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end));
967*3117ece4Schristos         in.src = (char const*)in.src + in.pos;
968*3117ece4Schristos         in.size -= in.pos;
969*3117ece4Schristos         in.pos = 0;
970*3117ece4Schristos         {   size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end);
971*3117ece4Schristos             CHECK(!ZSTD_isError(ret), "Must error");
972*3117ece4Schristos             CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_stabilityCondition_notRespected), "Must be this error");
973*3117ece4Schristos         }
974*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
975*3117ece4Schristos 
976*3117ece4Schristos         /* stableSrc + streaming */
977*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_c_stableInBuffer compatibility with compressStream, flushStream and endStream : ", testNb++);
978*3117ece4Schristos         CHECK_Z( ZSTD_initCStream(cctx, 1) );
979*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1) );
980*3117ece4Schristos         {   ZSTD_inBuffer inBuf;
981*3117ece4Schristos             ZSTD_outBuffer outBuf;
982*3117ece4Schristos             const size_t nonZeroStartPos = 18;
983*3117ece4Schristos             const size_t inputSize = 500;
984*3117ece4Schristos             inBuf.src = CNBuffer;
985*3117ece4Schristos             inBuf.size = 100;
986*3117ece4Schristos             inBuf.pos = nonZeroStartPos;
987*3117ece4Schristos             outBuf.dst = (char*)(compressedBuffer)+cSize;
988*3117ece4Schristos             outBuf.size = ZSTD_compressBound(inputSize);
989*3117ece4Schristos             outBuf.pos = 0;
990*3117ece4Schristos             CHECK_Z( ZSTD_compressStream(cctx, &outBuf, &inBuf) );
991*3117ece4Schristos             inBuf.size = 200;
992*3117ece4Schristos             CHECK_Z( ZSTD_compressStream(cctx, &outBuf, &inBuf) );
993*3117ece4Schristos             CHECK_Z( ZSTD_flushStream(cctx, &outBuf) );
994*3117ece4Schristos             inBuf.size = nonZeroStartPos + inputSize;
995*3117ece4Schristos             CHECK_Z( ZSTD_compressStream(cctx, &outBuf, &inBuf) );
996*3117ece4Schristos             CHECK(ZSTD_endStream(cctx, &outBuf) != 0, "compression should be successful and fully flushed");
997*3117ece4Schristos             {   const void* const realSrcStart = (const char*)inBuf.src + nonZeroStartPos;
998*3117ece4Schristos                 void* const verifBuf = (char*)outBuf.dst + outBuf.pos;
999*3117ece4Schristos                 const size_t decSize = ZSTD_decompress(verifBuf, inputSize, outBuf.dst, outBuf.pos);
1000*3117ece4Schristos                 CHECK_Z(decSize);
1001*3117ece4Schristos                 CHECK(decSize != inputSize, "regenerated %zu bytes, instead of %zu", decSize, inputSize);
1002*3117ece4Schristos                 CHECK(memcmp(realSrcStart, verifBuf, inputSize) != 0, "regenerated data different from original");
1003*3117ece4Schristos         }   }
1004*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1005*3117ece4Schristos 
1006*3117ece4Schristos         /* stableSrc + streaming */
1007*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_c_stableInBuffer compatibility with compressStream2, using different end directives : ", testNb++);
1008*3117ece4Schristos         CHECK_Z( ZSTD_initCStream(cctx, 1) );
1009*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableInBuffer, 1) );
1010*3117ece4Schristos         {   ZSTD_inBuffer inBuf;
1011*3117ece4Schristos             ZSTD_outBuffer outBuf;
1012*3117ece4Schristos             const size_t nonZeroStartPos = 18;
1013*3117ece4Schristos             const size_t inputSize = 500;
1014*3117ece4Schristos             inBuf.src = CNBuffer;
1015*3117ece4Schristos             inBuf.size = 100;
1016*3117ece4Schristos             inBuf.pos = nonZeroStartPos;
1017*3117ece4Schristos             outBuf.dst = (char*)(compressedBuffer)+cSize;
1018*3117ece4Schristos             outBuf.size = ZSTD_compressBound(inputSize);
1019*3117ece4Schristos             outBuf.pos = 0;
1020*3117ece4Schristos             CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_continue) );
1021*3117ece4Schristos             inBuf.size = 200;
1022*3117ece4Schristos             CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_continue) );
1023*3117ece4Schristos             CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_flush) );
1024*3117ece4Schristos             inBuf.size = nonZeroStartPos + inputSize;
1025*3117ece4Schristos             CHECK_Z( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_continue) );
1026*3117ece4Schristos             CHECK( ZSTD_compressStream2(cctx, &outBuf, &inBuf, ZSTD_e_end) != 0, "compression should be successful and fully flushed");
1027*3117ece4Schristos             {   const void* const realSrcStart = (const char*)inBuf.src + nonZeroStartPos;
1028*3117ece4Schristos                 void* const verifBuf = (char*)outBuf.dst + outBuf.pos;
1029*3117ece4Schristos                 const size_t decSize = ZSTD_decompress(verifBuf, inputSize, outBuf.dst, outBuf.pos);
1030*3117ece4Schristos                 CHECK_Z(decSize);
1031*3117ece4Schristos                 CHECK(decSize != inputSize, "regenerated %zu bytes, instead of %zu", decSize, inputSize);
1032*3117ece4Schristos                 CHECK(memcmp(realSrcStart, verifBuf, inputSize) != 0, "regenerated data different from original");
1033*3117ece4Schristos         }   }
1034*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1035*3117ece4Schristos 
1036*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableInBuffer: context size : ", testNb++);
1037*3117ece4Schristos         {   size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
1038*3117ece4Schristos             DISPLAYLEVEL(4, "cctxSize1=%zu; cctxSize=%zu; cctxSize2=%zu : ", cctxSize1, cctxSize, cctxSize2);
1039*3117ece4Schristos             CHECK(!(cctxSize1 < cctxSize), "Must be bigger than single-pass");
1040*3117ece4Schristos             CHECK(!(cctxSize < cctxSize2), "Must be smaller than streaming");
1041*3117ece4Schristos             cctxSize1 = cctxSize;
1042*3117ece4Schristos         }
1043*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1044*3117ece4Schristos 
1045*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableOutBuffer only : ", testNb++);
1046*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters));
1047*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1));
1048*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_stableOutBuffer, 1));
1049*3117ece4Schristos         in.src = CNBuffer;
1050*3117ece4Schristos         in.pos = out.pos = 0;
1051*3117ece4Schristos         in.size = MIN(CNBufferSize, 10);
1052*3117ece4Schristos         out.size = compressedBufferSize;
1053*3117ece4Schristos         CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_flush));
1054*3117ece4Schristos         in.pos = 0;
1055*3117ece4Schristos         in.size = CNBufferSize - in.size;
1056*3117ece4Schristos         CHECK(!(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_end) == 0), "Not finished");
1057*3117ece4Schristos         CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, out.pos));
1058*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1059*3117ece4Schristos 
1060*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() ZSTD_c_stableOutBuffer modify buffer : ", testNb++);
1061*3117ece4Schristos         in.pos = out.pos = 0;
1062*3117ece4Schristos         in.size = CNBufferSize;
1063*3117ece4Schristos         CHECK_Z(ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue));
1064*3117ece4Schristos         in.pos = out.pos = 0;
1065*3117ece4Schristos         {   size_t const ret = ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);
1066*3117ece4Schristos             CHECK(!ZSTD_isError(ret), "Must have errored");
1067*3117ece4Schristos             CHECK(!(ZSTD_getErrorCode(ret) == ZSTD_error_stabilityCondition_notRespected), "Must be this error");
1068*3117ece4Schristos         }
1069*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1070*3117ece4Schristos 
1071*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : ZSTD_compressStream2() with ZSTD_c_stableOutBuffer: context size : ", testNb++);
1072*3117ece4Schristos         {   size_t const cctxSize = ZSTD_sizeof_CCtx(cctx);
1073*3117ece4Schristos             DISPLAYLEVEL(4, "cctxSize1=%zu; cctxSize=%zu; cctxSize2=%zu : ", cctxSize1, cctxSize, cctxSize2);
1074*3117ece4Schristos             CHECK(!(cctxSize1 < cctxSize), "Must be bigger than single-pass and stableInBuffer");
1075*3117ece4Schristos             CHECK(!(cctxSize < cctxSize2), "Must be smaller than streaming");
1076*3117ece4Schristos         }
1077*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1078*3117ece4Schristos 
1079*3117ece4Schristos         ZSTD_freeCCtx(cctx);
1080*3117ece4Schristos     }
1081*3117ece4Schristos 
1082*3117ece4Schristos     /* CDict scenario */
1083*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : digested dictionary : ", testNb++);
1084*3117ece4Schristos     {   ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, 1 /*byRef*/ );
1085*3117ece4Schristos         size_t const initError = ZSTD_initCStream_usingCDict(zc, cdict);
1086*3117ece4Schristos         DISPLAYLEVEL(5, "ZSTD_initCStream_usingCDict result : %u ", (unsigned)initError);
1087*3117ece4Schristos         if (ZSTD_isError(initError)) goto _output_error;
1088*3117ece4Schristos         outBuff.dst = compressedBuffer;
1089*3117ece4Schristos         outBuff.size = compressedBufferSize;
1090*3117ece4Schristos         outBuff.pos = 0;
1091*3117ece4Schristos         inBuff.src = CNBuffer;
1092*3117ece4Schristos         inBuff.size = CNBufferSize;
1093*3117ece4Schristos         inBuff.pos = 0;
1094*3117ece4Schristos         DISPLAYLEVEL(5, "- starting ZSTD_compressStream ");
1095*3117ece4Schristos         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1096*3117ece4Schristos         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1097*3117ece4Schristos         {   size_t const r = ZSTD_endStream(zc, &outBuff);
1098*3117ece4Schristos             DISPLAYLEVEL(5, "- ZSTD_endStream result : %u ", (unsigned)r);
1099*3117ece4Schristos             if (r != 0) goto _output_error;  /* error, or some data not flushed */
1100*3117ece4Schristos         }
1101*3117ece4Schristos         cSize = outBuff.pos;
1102*3117ece4Schristos         ZSTD_freeCDict(cdict);
1103*3117ece4Schristos         DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
1104*3117ece4Schristos     }
1105*3117ece4Schristos 
1106*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : check CStream size : ", testNb++);
1107*3117ece4Schristos     { size_t const s = ZSTD_sizeof_CStream(zc);
1108*3117ece4Schristos       if (ZSTD_isError(s)) goto _output_error;
1109*3117ece4Schristos       DISPLAYLEVEL(3, "OK (%u bytes) \n", (unsigned)s);
1110*3117ece4Schristos     }
1111*3117ece4Schristos 
1112*3117ece4Schristos     DISPLAYLEVEL(4, "test%3i : check Dictionary ID : ", testNb++);
1113*3117ece4Schristos     { unsigned const dID = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
1114*3117ece4Schristos       if (dID != dictID) goto _output_error;
1115*3117ece4Schristos       DISPLAYLEVEL(4, "OK (%u) \n", dID);
1116*3117ece4Schristos     }
1117*3117ece4Schristos 
1118*3117ece4Schristos     /* DDict scenario */
1119*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress %u bytes with digested dictionary : ", testNb++, (unsigned)CNBufferSize);
1120*3117ece4Schristos     {   ZSTD_DDict* const ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1121*3117ece4Schristos         size_t const initError = ZSTD_initDStream_usingDDict(zd, ddict);
1122*3117ece4Schristos         if (ZSTD_isError(initError)) goto _output_error;
1123*3117ece4Schristos         outBuff.dst = decodedBuffer;
1124*3117ece4Schristos         outBuff.size = CNBufferSize;
1125*3117ece4Schristos         outBuff.pos = 0;
1126*3117ece4Schristos         inBuff.src = compressedBuffer;
1127*3117ece4Schristos         inBuff.size = cSize;
1128*3117ece4Schristos         inBuff.pos = 0;
1129*3117ece4Schristos         { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1130*3117ece4Schristos           if (r != 0) goto _output_error; }  /* should reach end of frame == 0; otherwise, some data left, or an error */
1131*3117ece4Schristos         if (outBuff.pos != CNBufferSize) goto _output_error;   /* should regenerate the same amount */
1132*3117ece4Schristos         if (inBuff.pos != inBuff.size) goto _output_error;   /* should have read the entire frame */
1133*3117ece4Schristos         ZSTD_freeDDict(ddict);
1134*3117ece4Schristos         DISPLAYLEVEL(3, "OK \n");
1135*3117ece4Schristos     }
1136*3117ece4Schristos 
1137*3117ece4Schristos     /* Memory restriction */
1138*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : maxWindowSize < frame requirement : ", testNb++);
1139*3117ece4Schristos     ZSTD_initDStream_usingDict(zd, CNBuffer, dictSize);
1140*3117ece4Schristos     CHECK_Z( ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, 10) );  /* too small limit */
1141*3117ece4Schristos     outBuff.dst = decodedBuffer;
1142*3117ece4Schristos     outBuff.size = CNBufferSize;
1143*3117ece4Schristos     outBuff.pos = 0;
1144*3117ece4Schristos     inBuff.src = compressedBuffer;
1145*3117ece4Schristos     inBuff.size = cSize;
1146*3117ece4Schristos     inBuff.pos = 0;
1147*3117ece4Schristos     { size_t const r = ZSTD_decompressStream(zd, &outBuff, &inBuff);
1148*3117ece4Schristos       if (!ZSTD_isError(r)) goto _output_error;  /* must fail : frame requires > 100 bytes */
1149*3117ece4Schristos       DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r)); }
1150*3117ece4Schristos     ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters);   /* leave zd in good shape for next tests */
1151*3117ece4Schristos 
1152*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : dictionary source size and level : ", testNb++);
1153*3117ece4Schristos     {   ZSTD_DCtx* const dctx = ZSTD_createDCtx();
1154*3117ece4Schristos         int const maxLevel = 16;   /* first level with zstd_opt */
1155*3117ece4Schristos         int level;
1156*3117ece4Schristos         assert(maxLevel < ZSTD_maxCLevel());
1157*3117ece4Schristos         CHECK_Z( ZSTD_DCtx_loadDictionary_byReference(dctx, dictionary.start, dictionary.filled) );
1158*3117ece4Schristos         for (level = 1; level <= maxLevel; ++level) {
1159*3117ece4Schristos             ZSTD_CDict* const cdict = ZSTD_createCDict(dictionary.start, dictionary.filled, level);
1160*3117ece4Schristos             size_t const maxSize = MIN(1 MB, CNBufferSize);
1161*3117ece4Schristos             size_t size;
1162*3117ece4Schristos             for (size = 512; size <= maxSize; size <<= 1) {
1163*3117ece4Schristos                 U64 const crcOrig = XXH64(CNBuffer, size, 0);
1164*3117ece4Schristos                 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
1165*3117ece4Schristos                 ZSTD_parameters savedParams;
1166*3117ece4Schristos                 getCCtxParams(cctx, &savedParams);
1167*3117ece4Schristos                 outBuff.dst = compressedBuffer;
1168*3117ece4Schristos                 outBuff.size = compressedBufferSize;
1169*3117ece4Schristos                 outBuff.pos = 0;
1170*3117ece4Schristos                 inBuff.src = CNBuffer;
1171*3117ece4Schristos                 inBuff.size = size;
1172*3117ece4Schristos                 inBuff.pos = 0;
1173*3117ece4Schristos                 CHECK_Z(ZSTD_CCtx_refCDict(cctx, cdict));
1174*3117ece4Schristos                 CHECK_Z(ZSTD_compressStream2(cctx, &outBuff, &inBuff, ZSTD_e_end));
1175*3117ece4Schristos                 CHECK(badParameters(cctx, savedParams), "Bad CCtx params");
1176*3117ece4Schristos                 if (inBuff.pos != inBuff.size) goto _output_error;
1177*3117ece4Schristos                 {   ZSTD_outBuffer decOut = {decodedBuffer, size, 0};
1178*3117ece4Schristos                     ZSTD_inBuffer decIn = {outBuff.dst, outBuff.pos, 0};
1179*3117ece4Schristos                     CHECK_Z( ZSTD_decompressStream(dctx, &decOut, &decIn) );
1180*3117ece4Schristos                     if (decIn.pos != decIn.size) goto _output_error;
1181*3117ece4Schristos                     if (decOut.pos != size) goto _output_error;
1182*3117ece4Schristos                     {   U64 const crcDec = XXH64(decOut.dst, decOut.pos, 0);
1183*3117ece4Schristos                         if (crcDec != crcOrig) goto _output_error;
1184*3117ece4Schristos                 }   }
1185*3117ece4Schristos                 ZSTD_freeCCtx(cctx);
1186*3117ece4Schristos             }
1187*3117ece4Schristos             ZSTD_freeCDict(cdict);
1188*3117ece4Schristos         }
1189*3117ece4Schristos         ZSTD_freeDCtx(dctx);
1190*3117ece4Schristos     }
1191*3117ece4Schristos     DISPLAYLEVEL(3, "OK\n");
1192*3117ece4Schristos 
1193*3117ece4Schristos     ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1194*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dictionary.start, dictionary.filled) );
1195*3117ece4Schristos     cSize = ZSTD_compress2(zc, compressedBuffer, compressedBufferSize, CNBuffer, MIN(CNBufferSize, 100 KB));
1196*3117ece4Schristos     CHECK_Z(cSize);
1197*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with dictionary : ", testNb++);
1198*3117ece4Schristos     {
1199*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
1200*3117ece4Schristos         /* We should fail to decompress without a dictionary. */
1201*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1202*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1203*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1204*3117ece4Schristos             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1205*3117ece4Schristos             if (!ZSTD_isError(ret)) goto _output_error;
1206*3117ece4Schristos         }
1207*3117ece4Schristos         /* We should succeed to decompress with the dictionary. */
1208*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1209*3117ece4Schristos         CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
1210*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1211*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1212*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1213*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1214*3117ece4Schristos         }
1215*3117ece4Schristos         /* The dictionary should persist across calls. */
1216*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1217*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1218*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1219*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1220*3117ece4Schristos         }
1221*3117ece4Schristos         /* The dictionary should not be cleared by ZSTD_reset_session_only. */
1222*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
1223*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1224*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1225*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1226*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1227*3117ece4Schristos         }
1228*3117ece4Schristos         /* When we reset the context the dictionary is cleared. */
1229*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1230*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1231*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1232*3117ece4Schristos             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1233*3117ece4Schristos             if (!ZSTD_isError(ret)) goto _output_error;
1234*3117ece4Schristos         }
1235*3117ece4Schristos         ZSTD_freeDCtx(dctx);
1236*3117ece4Schristos     }
1237*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1238*3117ece4Schristos 
1239*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_resetDStream() with dictionary : ", testNb++);
1240*3117ece4Schristos     {
1241*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
1242*3117ece4Schristos         /* We should succeed to decompress with the dictionary. */
1243*3117ece4Schristos         ZSTD_resetDStream(dctx);
1244*3117ece4Schristos         CHECK_Z( ZSTD_DCtx_loadDictionary(dctx, dictionary.start, dictionary.filled) );
1245*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1246*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1247*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1248*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1249*3117ece4Schristos         }
1250*3117ece4Schristos         /* The dictionary should not be cleared by ZSTD_resetDStream(). */
1251*3117ece4Schristos         ZSTD_resetDStream(dctx);
1252*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1253*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1254*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1255*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1256*3117ece4Schristos         }
1257*3117ece4Schristos         /* The dictionary should be cleared by ZSTD_initDStream(). */
1258*3117ece4Schristos         CHECK_Z( ZSTD_initDStream(dctx) );
1259*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1260*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1261*3117ece4Schristos             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1262*3117ece4Schristos             if (!ZSTD_isError(ret)) goto _output_error;
1263*3117ece4Schristos         }
1264*3117ece4Schristos         ZSTD_freeDCtx(dctx);
1265*3117ece4Schristos     }
1266*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1267*3117ece4Schristos 
1268*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressStream() with ddict : ", testNb++);
1269*3117ece4Schristos     {
1270*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
1271*3117ece4Schristos         ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1272*3117ece4Schristos         /* We should succeed to decompress with the ddict. */
1273*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1274*3117ece4Schristos         CHECK_Z( ZSTD_DCtx_refDDict(dctx, ddict) );
1275*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1276*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1277*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1278*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1279*3117ece4Schristos         }
1280*3117ece4Schristos         /* The ddict should persist across calls. */
1281*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1282*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1283*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1284*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1285*3117ece4Schristos         }
1286*3117ece4Schristos         /* When we reset the context the ddict is cleared. */
1287*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1288*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1289*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1290*3117ece4Schristos             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1291*3117ece4Schristos             if (!ZSTD_isError(ret)) goto _output_error;
1292*3117ece4Schristos         }
1293*3117ece4Schristos         ZSTD_freeDCtx(dctx);
1294*3117ece4Schristos         ZSTD_freeDDict(ddict);
1295*3117ece4Schristos     }
1296*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1297*3117ece4Schristos 
1298*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_decompressDCtx() with prefix : ", testNb++);
1299*3117ece4Schristos     {
1300*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
1301*3117ece4Schristos         /* We should succeed to decompress with the prefix. */
1302*3117ece4Schristos         ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters);
1303*3117ece4Schristos         CHECK_Z( ZSTD_DCtx_refPrefix_advanced(dctx, dictionary.start, dictionary.filled, ZSTD_dct_auto) );
1304*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1305*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1306*3117ece4Schristos             if (ZSTD_decompressStream(dctx, &out, &in) != 0) goto _output_error;
1307*3117ece4Schristos             if (in.pos != in.size) goto _output_error;
1308*3117ece4Schristos         }
1309*3117ece4Schristos         /* The prefix should be cleared after the first compression. */
1310*3117ece4Schristos         {   ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1311*3117ece4Schristos             ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1312*3117ece4Schristos             size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
1313*3117ece4Schristos             if (!ZSTD_isError(ret)) goto _output_error;
1314*3117ece4Schristos         }
1315*3117ece4Schristos         ZSTD_freeDCtx(dctx);
1316*3117ece4Schristos     }
1317*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1318*3117ece4Schristos 
1319*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_initDStream*() with dictionary : ", testNb++);
1320*3117ece4Schristos     {
1321*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
1322*3117ece4Schristos         ZSTD_DDict* ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1323*3117ece4Schristos         size_t ret;
1324*3117ece4Schristos         /* We should succeed to decompress with the dictionary. */
1325*3117ece4Schristos         CHECK_Z( ZSTD_initDStream_usingDict(dctx, dictionary.start, dictionary.filled) );
1326*3117ece4Schristos         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1327*3117ece4Schristos         /* The dictionary should persist across calls. */
1328*3117ece4Schristos         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1329*3117ece4Schristos         /* We should succeed to decompress with the ddict. */
1330*3117ece4Schristos         CHECK_Z( ZSTD_initDStream_usingDDict(dctx, ddict) );
1331*3117ece4Schristos         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1332*3117ece4Schristos         /* The ddict should persist across calls. */
1333*3117ece4Schristos         CHECK_Z( ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize) );
1334*3117ece4Schristos         /* When we reset the context the ddict is cleared. */
1335*3117ece4Schristos         CHECK_Z( ZSTD_initDStream(dctx) );
1336*3117ece4Schristos         ret = ZSTD_decompressDCtx(dctx, decodedBuffer, decodedBufferSize, compressedBuffer, cSize);
1337*3117ece4Schristos         if (!ZSTD_isError(ret)) goto _output_error;
1338*3117ece4Schristos         ZSTD_freeDCtx(dctx);
1339*3117ece4Schristos         ZSTD_freeDDict(ddict);
1340*3117ece4Schristos     }
1341*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1342*3117ece4Schristos 
1343*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_usingCDict_advanced with masked dictID : ", testNb++);
1344*3117ece4Schristos     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, CNBufferSize, dictionary.filled);
1345*3117ece4Schristos         ZSTD_frameParameters const fParams = { 1 /* contentSize */, 1 /* checksum */, 1 /* noDictID */};
1346*3117ece4Schristos         ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_auto, cParams, ZSTD_defaultCMem);
1347*3117ece4Schristos         size_t const initError = ZSTD_initCStream_usingCDict_advanced(zc, cdict, fParams, CNBufferSize);
1348*3117ece4Schristos         if (ZSTD_isError(initError)) goto _output_error;
1349*3117ece4Schristos         outBuff.dst = compressedBuffer;
1350*3117ece4Schristos         outBuff.size = compressedBufferSize;
1351*3117ece4Schristos         outBuff.pos = 0;
1352*3117ece4Schristos         inBuff.src = CNBuffer;
1353*3117ece4Schristos         inBuff.size = CNBufferSize;
1354*3117ece4Schristos         inBuff.pos = 0;
1355*3117ece4Schristos         CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1356*3117ece4Schristos         if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
1357*3117ece4Schristos         { size_t const r = ZSTD_endStream(zc, &outBuff);
1358*3117ece4Schristos           if (r != 0) goto _output_error; }  /* error, or some data not flushed */
1359*3117ece4Schristos         cSize = outBuff.pos;
1360*3117ece4Schristos         ZSTD_freeCDict(cdict);
1361*3117ece4Schristos         DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
1362*3117ece4Schristos     }
1363*3117ece4Schristos 
1364*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : try retrieving dictID from frame : ", testNb++);
1365*3117ece4Schristos     {   U32 const did = ZSTD_getDictID_fromFrame(compressedBuffer, cSize);
1366*3117ece4Schristos         if (did != 0) goto _output_error;
1367*3117ece4Schristos     }
1368*3117ece4Schristos     DISPLAYLEVEL(3, "OK (not detected) \n");
1369*3117ece4Schristos 
1370*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress without dictionary : ", testNb++);
1371*3117ece4Schristos     {   size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
1372*3117ece4Schristos         if (!ZSTD_isError(r)) goto _output_error;  /* must fail : dictionary not used */
1373*3117ece4Schristos         DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
1374*3117ece4Schristos     }
1375*3117ece4Schristos 
1376*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : compress with ZSTD_CCtx_refPrefix : ", testNb++);
1377*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dictionary.start, dictionary.filled) );
1378*3117ece4Schristos     outBuff.dst = compressedBuffer;
1379*3117ece4Schristos     outBuff.size = compressedBufferSize;
1380*3117ece4Schristos     outBuff.pos = 0;
1381*3117ece4Schristos     inBuff.src = CNBuffer;
1382*3117ece4Schristos     inBuff.size = CNBufferSize;
1383*3117ece4Schristos     inBuff.pos = 0;
1384*3117ece4Schristos     CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
1385*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
1386*3117ece4Schristos     cSize = outBuff.pos;
1387*3117ece4Schristos     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
1388*3117ece4Schristos 
1389*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress with ZSTD_DCtx_refPrefix : ", testNb++);
1390*3117ece4Schristos     CHECK_Z( ZSTD_DCtx_refPrefix(zd, dictionary.start, dictionary.filled) );
1391*3117ece4Schristos     outBuff.dst = decodedBuffer;
1392*3117ece4Schristos     outBuff.size = CNBufferSize;
1393*3117ece4Schristos     outBuff.pos = 0;
1394*3117ece4Schristos     inBuff.src = compressedBuffer;
1395*3117ece4Schristos     inBuff.size = cSize;
1396*3117ece4Schristos     inBuff.pos = 0;
1397*3117ece4Schristos     CHECK_Z( ZSTD_decompressStream(zd, &outBuff, &inBuff) );
1398*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
1399*3117ece4Schristos     if (outBuff.pos != CNBufferSize) goto _output_error;  /* must regenerate whole input */
1400*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1401*3117ece4Schristos 
1402*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should fail): ", testNb++);
1403*3117ece4Schristos     {   size_t const r = ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize);
1404*3117ece4Schristos         if (!ZSTD_isError(r)) goto _output_error;  /* must fail : dictionary not used */
1405*3117ece4Schristos         DISPLAYLEVEL(3, "OK (%s)\n", ZSTD_getErrorName(r));
1406*3117ece4Schristos     }
1407*3117ece4Schristos 
1408*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : compress again with ZSTD_compressStream2 : ", testNb++);
1409*3117ece4Schristos     outBuff.dst = compressedBuffer;
1410*3117ece4Schristos     outBuff.size = compressedBufferSize;
1411*3117ece4Schristos     outBuff.pos = 0;
1412*3117ece4Schristos     inBuff.src = CNBuffer;
1413*3117ece4Schristos     inBuff.size = CNBufferSize;
1414*3117ece4Schristos     inBuff.pos = 0;
1415*3117ece4Schristos     CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
1416*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;  /* entire input should be consumed */
1417*3117ece4Schristos     cSize = outBuff.pos;
1418*3117ece4Schristos     DISPLAYLEVEL(3, "OK (%u bytes : %.2f%%)\n", (unsigned)cSize, (double)cSize/CNBufferSize*100);
1419*3117ece4Schristos 
1420*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress without dictionary (should work): ", testNb++);
1421*3117ece4Schristos     CHECK_Z( ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize) );
1422*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1423*3117ece4Schristos 
1424*3117ece4Schristos     /* Empty srcSize */
1425*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced with pledgedSrcSize=0 and dict : ", testNb++);
1426*3117ece4Schristos     {   ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
1427*3117ece4Schristos         params.fParams.contentSizeFlag = 1;
1428*3117ece4Schristos         CHECK_Z( ZSTD_initCStream_advanced(zc, dictionary.start, dictionary.filled, params, 0 /* pledgedSrcSize==0 means "empty" when params.fParams.contentSizeFlag is set */) );
1429*3117ece4Schristos     } /* cstream advanced shall write content size = 0 */
1430*3117ece4Schristos     outBuff.dst = compressedBuffer;
1431*3117ece4Schristos     outBuff.size = compressedBufferSize;
1432*3117ece4Schristos     outBuff.pos = 0;
1433*3117ece4Schristos     inBuff.src = CNBuffer;
1434*3117ece4Schristos     inBuff.size = 0;
1435*3117ece4Schristos     inBuff.pos = 0;
1436*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1437*3117ece4Schristos     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1438*3117ece4Schristos     cSize = outBuff.pos;
1439*3117ece4Schristos     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
1440*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1441*3117ece4Schristos 
1442*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : pledgedSrcSize == 0 behaves properly with ZSTD_initCStream_advanced : ", testNb++);
1443*3117ece4Schristos     {   ZSTD_parameters params = ZSTD_getParams(5, 0, 0);
1444*3117ece4Schristos         params.fParams.contentSizeFlag = 1;
1445*3117ece4Schristos         CHECK_Z( ZSTD_initCStream_advanced(zc, NULL, 0, params, 0) );
1446*3117ece4Schristos     } /* cstream advanced shall write content size = 0 */
1447*3117ece4Schristos     inBuff.src = CNBuffer;
1448*3117ece4Schristos     inBuff.size = 0;
1449*3117ece4Schristos     inBuff.pos = 0;
1450*3117ece4Schristos     outBuff.dst = compressedBuffer;
1451*3117ece4Schristos     outBuff.size = compressedBufferSize;
1452*3117ece4Schristos     outBuff.pos = 0;
1453*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1454*3117ece4Schristos     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1455*3117ece4Schristos     cSize = outBuff.pos;
1456*3117ece4Schristos     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != 0) goto _output_error;
1457*3117ece4Schristos 
1458*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
1459*3117ece4Schristos     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, ZSTD_CONTENTSIZE_UNKNOWN) );
1460*3117ece4Schristos     outBuff.dst = compressedBuffer;
1461*3117ece4Schristos     outBuff.size = compressedBufferSize;
1462*3117ece4Schristos     outBuff.pos = 0;
1463*3117ece4Schristos     inBuff.src = CNBuffer;
1464*3117ece4Schristos     inBuff.size = 0;
1465*3117ece4Schristos     inBuff.pos = 0;
1466*3117ece4Schristos     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
1467*3117ece4Schristos     if (ZSTD_endStream(zc, &outBuff) != 0) goto _output_error;
1468*3117ece4Schristos     cSize = outBuff.pos;
1469*3117ece4Schristos     if (ZSTD_findDecompressedSize(compressedBuffer, cSize) != ZSTD_CONTENTSIZE_UNKNOWN) goto _output_error;
1470*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1471*3117ece4Schristos 
1472*3117ece4Schristos     /* Basic multithreading compression test */
1473*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads : ", testNb++, COMPRESSIBLE_NOISE_LENGTH);
1474*3117ece4Schristos     {   int jobSize;
1475*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_getParameter(mtctx, ZSTD_c_jobSize, &jobSize));
1476*3117ece4Schristos         CHECK(jobSize != 0, "job size non-zero");
1477*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_getParameter(mtctx, ZSTD_c_jobSize, &jobSize));
1478*3117ece4Schristos         CHECK(jobSize != 0, "job size non-zero");
1479*3117ece4Schristos     }
1480*3117ece4Schristos     outBuff.dst = compressedBuffer;
1481*3117ece4Schristos     outBuff.size = compressedBufferSize;
1482*3117ece4Schristos     outBuff.pos = 0;
1483*3117ece4Schristos     inBuff.src = CNBuffer;
1484*3117ece4Schristos     inBuff.size = CNBufferSize;
1485*3117ece4Schristos     inBuff.pos = 0;
1486*3117ece4Schristos     {   size_t const compressResult = ZSTD_compressStream2(mtctx, &outBuff, &inBuff, ZSTD_e_end);
1487*3117ece4Schristos         if (compressResult != 0) goto _output_error;  /* compression must be completed in a single round */
1488*3117ece4Schristos     }
1489*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1490*3117ece4Schristos     {   size_t const compressedSize = ZSTD_findFrameCompressedSize(compressedBuffer, outBuff.pos);
1491*3117ece4Schristos         if (compressedSize != outBuff.pos) goto _output_error;  /* must be a full valid frame */
1492*3117ece4Schristos     }
1493*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1494*3117ece4Schristos 
1495*3117ece4Schristos     /* Complex multithreading + dictionary test */
1496*3117ece4Schristos     {   U32 const nbWorkers = 2;
1497*3117ece4Schristos         size_t const jobSize = 4 * 1 MB;
1498*3117ece4Schristos         size_t const srcSize = jobSize * nbWorkers;  /* we want each job to have predictable size */
1499*3117ece4Schristos         size_t const segLength = 2 KB;
1500*3117ece4Schristos         size_t const offset = 600 KB;   /* must be larger than window defined in cdict */
1501*3117ece4Schristos         size_t const start = jobSize + (offset-1);
1502*3117ece4Schristos         const BYTE* const srcToCopy = (const BYTE*)CNBuffer + start;
1503*3117ece4Schristos         BYTE* const dst = (BYTE*)CNBuffer + start - offset;
1504*3117ece4Schristos         DISPLAYLEVEL(3, "test%3i : compress %u bytes with multiple threads + dictionary : ", testNb++, (unsigned)srcSize);
1505*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, 3) );
1506*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers) );
1507*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_jobSize, jobSize) );
1508*3117ece4Schristos         assert(start > offset);
1509*3117ece4Schristos         assert(start + segLength < COMPRESSIBLE_NOISE_LENGTH);
1510*3117ece4Schristos         memcpy(dst, srcToCopy, segLength);   /* create a long repetition at long distance for job 2 */
1511*3117ece4Schristos         outBuff.dst = compressedBuffer;
1512*3117ece4Schristos         outBuff.size = compressedBufferSize;
1513*3117ece4Schristos         outBuff.pos = 0;
1514*3117ece4Schristos         inBuff.src = CNBuffer;
1515*3117ece4Schristos         inBuff.size = srcSize; assert(srcSize < COMPRESSIBLE_NOISE_LENGTH);
1516*3117ece4Schristos         inBuff.pos = 0;
1517*3117ece4Schristos     }
1518*3117ece4Schristos     {   ZSTD_compressionParameters const cParams = ZSTD_getCParams(1, 4 KB, dictionary.filled);   /* intentionally lies on estimatedSrcSize, to push cdict into targeting a small window size */
1519*3117ece4Schristos         ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
1520*3117ece4Schristos         DISPLAYLEVEL(5, "cParams.windowLog = %u : ", cParams.windowLog);
1521*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_refCDict(zc, cdict) );
1522*3117ece4Schristos         CHECK_Z( ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end) );
1523*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_refCDict(zc, NULL) );  /* do not keep a reference to cdict, as its lifetime ends */
1524*3117ece4Schristos         ZSTD_freeCDict(cdict);
1525*3117ece4Schristos     }
1526*3117ece4Schristos     if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1527*3117ece4Schristos     cSize = outBuff.pos;
1528*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1529*3117ece4Schristos 
1530*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress large frame created from multiple threads + dictionary : ", testNb++);
1531*3117ece4Schristos     {   ZSTD_DStream* const dstream = ZSTD_createDCtx();
1532*3117ece4Schristos         ZSTD_frameHeader zfh;
1533*3117ece4Schristos         ZSTD_getFrameHeader(&zfh, compressedBuffer, cSize);
1534*3117ece4Schristos         DISPLAYLEVEL(5, "frame windowsize = %u : ", (unsigned)zfh.windowSize);
1535*3117ece4Schristos         outBuff.dst = decodedBuffer;
1536*3117ece4Schristos         outBuff.size = CNBufferSize;
1537*3117ece4Schristos         outBuff.pos = 0;
1538*3117ece4Schristos         inBuff.src = compressedBuffer;
1539*3117ece4Schristos         inBuff.pos = 0;
1540*3117ece4Schristos         CHECK_Z( ZSTD_initDStream_usingDict(dstream, dictionary.start, dictionary.filled) );
1541*3117ece4Schristos         inBuff.size = 1;  /* avoid shortcut to single-pass mode */
1542*3117ece4Schristos         CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1543*3117ece4Schristos         inBuff.size = cSize;
1544*3117ece4Schristos         CHECK_Z( ZSTD_decompressStream(dstream, &outBuff, &inBuff) );
1545*3117ece4Schristos         if (inBuff.pos != inBuff.size) goto _output_error;   /* entire input should be consumed */
1546*3117ece4Schristos         ZSTD_freeDStream(dstream);
1547*3117ece4Schristos     }
1548*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1549*3117ece4Schristos 
1550*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : check dictionary FSE tables can represent every code : ", testNb++);
1551*3117ece4Schristos     {   unsigned const kMaxWindowLog = 24;
1552*3117ece4Schristos         unsigned value;
1553*3117ece4Schristos         ZSTD_compressionParameters cParams = ZSTD_getCParams(3, 1U << kMaxWindowLog, 1024);
1554*3117ece4Schristos         ZSTD_CDict* cdict;
1555*3117ece4Schristos         ZSTD_DDict* ddict;
1556*3117ece4Schristos         SEQ_stream seq = SEQ_initStream(0x87654321);
1557*3117ece4Schristos         SEQ_gen_type type;
1558*3117ece4Schristos         XXH64_state_t xxh;
1559*3117ece4Schristos 
1560*3117ece4Schristos         XXH64_reset(&xxh, 0);
1561*3117ece4Schristos         cParams.windowLog = kMaxWindowLog;
1562*3117ece4Schristos         cdict = ZSTD_createCDict_advanced(dictionary.start, dictionary.filled, ZSTD_dlm_byRef, ZSTD_dct_fullDict, cParams, ZSTD_defaultCMem);
1563*3117ece4Schristos         ddict = ZSTD_createDDict(dictionary.start, dictionary.filled);
1564*3117ece4Schristos 
1565*3117ece4Schristos         if (!cdict || !ddict) goto _output_error;
1566*3117ece4Schristos 
1567*3117ece4Schristos         ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
1568*3117ece4Schristos         ZSTD_resetDStream(zd);
1569*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1570*3117ece4Schristos         CHECK_Z(ZSTD_initDStream_usingDDict(zd, ddict));
1571*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, kMaxWindowLog));
1572*3117ece4Schristos         /* Test all values < 300 */
1573*3117ece4Schristos         for (value = 0; value < 300; ++value) {
1574*3117ece4Schristos             for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1575*3117ece4Schristos                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1576*3117ece4Schristos             }
1577*3117ece4Schristos         }
1578*3117ece4Schristos         /* Test values 2^8 to 2^17 */
1579*3117ece4Schristos         for (value = (1 << 8); value < (1 << 17); value <<= 1) {
1580*3117ece4Schristos             for (type = (SEQ_gen_type)0; type < SEQ_gen_max; ++type) {
1581*3117ece4Schristos                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value));
1582*3117ece4Schristos                 CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, type, value + (value >> 2)));
1583*3117ece4Schristos             }
1584*3117ece4Schristos         }
1585*3117ece4Schristos         /* Test offset values up to the max window log */
1586*3117ece4Schristos         for (value = 8; value <= kMaxWindowLog; ++value) {
1587*3117ece4Schristos             CHECK_Z(SEQ_generateRoundTrip(zc, zd, &xxh, &seq, SEQ_gen_of, (1U << value) - 1));
1588*3117ece4Schristos         }
1589*3117ece4Schristos 
1590*3117ece4Schristos         CHECK_Z(SEQ_roundTrip(zc, zd, &xxh, NULL, 0, ZSTD_e_end));
1591*3117ece4Schristos         CHECK(SEQ_digest(&seq) != XXH64_digest(&xxh), "SEQ XXH64 does not match");
1592*3117ece4Schristos 
1593*3117ece4Schristos         ZSTD_freeCDict(cdict);
1594*3117ece4Schristos         ZSTD_freeDDict(ddict);
1595*3117ece4Schristos     }
1596*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1597*3117ece4Schristos 
1598*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_srcSize sets requestedParams : ", testNb++);
1599*3117ece4Schristos     {   int level;
1600*3117ece4Schristos         CHECK_Z(ZSTD_initCStream_srcSize(zc, 11, ZSTD_CONTENTSIZE_UNKNOWN));
1601*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
1602*3117ece4Schristos         CHECK(level != 11, "Compression level does not match");
1603*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
1604*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, ZSTD_CONTENTSIZE_UNKNOWN) );
1605*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_compressionLevel, &level));
1606*3117ece4Schristos         CHECK(level != 11, "Compression level does not match");
1607*3117ece4Schristos     }
1608*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1609*3117ece4Schristos 
1610*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_initCStream_advanced sets requestedParams : ", testNb++);
1611*3117ece4Schristos     {   ZSTD_parameters const params = ZSTD_getParams(9, 0, 0);
1612*3117ece4Schristos         CHECK_Z(ZSTD_initCStream_advanced(zc, NULL, 0, params, ZSTD_CONTENTSIZE_UNKNOWN));
1613*3117ece4Schristos         CHECK(badParameters(zc, params), "Compression parameters do not match");
1614*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
1615*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, ZSTD_CONTENTSIZE_UNKNOWN) );
1616*3117ece4Schristos         CHECK(badParameters(zc, params), "Compression parameters do not match");
1617*3117ece4Schristos     }
1618*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1619*3117ece4Schristos 
1620*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_c_srcSizeHint bounds : ", testNb++);
1621*3117ece4Schristos     ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
1622*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_srcSizeHint, INT_MAX));
1623*3117ece4Schristos     {   int srcSizeHint;
1624*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_srcSizeHint, &srcSizeHint));
1625*3117ece4Schristos         CHECK(!(srcSizeHint == INT_MAX), "srcSizeHint doesn't match");
1626*3117ece4Schristos     }
1627*3117ece4Schristos     CHECK(!ZSTD_isError(ZSTD_CCtx_setParameter(zc, ZSTD_c_srcSizeHint, -1)), "Out of range doesn't error");
1628*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1629*3117ece4Schristos 
1630*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : ZSTD_lazy compress with hashLog = 29 and searchLog = 4 : ", testNb++);
1631*3117ece4Schristos     if (MEM_64bits()) {
1632*3117ece4Schristos         ZSTD_outBuffer out = { compressedBuffer, compressedBufferSize, 0 };
1633*3117ece4Schristos         ZSTD_inBuffer in = { CNBuffer, CNBufferSize, 0 };
1634*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1635*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_strategy, ZSTD_lazy));
1636*3117ece4Schristos         /* Force enable the row based match finder */
1637*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_useRowMatchFinder, ZSTD_ps_enable));
1638*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_searchLog, 4));
1639*3117ece4Schristos         /* Set windowLog to 29 so the hashLog doesn't get sized down */
1640*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_windowLog, 29));
1641*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_hashLog, 29));
1642*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
1643*3117ece4Schristos         /* Compress with continue first so the hashLog doesn't get sized down */
1644*3117ece4Schristos         CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_continue));
1645*3117ece4Schristos         CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_end));
1646*3117ece4Schristos         cSize = out.pos;
1647*3117ece4Schristos         CHECK_Z(ZSTD_decompress(decodedBuffer, CNBufferSize, compressedBuffer, cSize));
1648*3117ece4Schristos     }
1649*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1650*3117ece4Schristos 
1651*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Test offset == windowSize : ", testNb++);
1652*3117ece4Schristos     {
1653*3117ece4Schristos         int windowLog;
1654*3117ece4Schristos         int const kMaxWindowLog = bigTests ? 29 : 26;
1655*3117ece4Schristos         size_t const kNbSequences = 10000;
1656*3117ece4Schristos         size_t const kMaxSrcSize = (1u << kMaxWindowLog) + 10 * kNbSequences;
1657*3117ece4Schristos         char* src = calloc(kMaxSrcSize, 1);
1658*3117ece4Schristos         ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
1659*3117ece4Schristos         for (windowLog = ZSTD_WINDOWLOG_MIN; windowLog <= kMaxWindowLog; ++windowLog) {
1660*3117ece4Schristos             size_t const srcSize = ((size_t)1 << windowLog) + 10 * (kNbSequences - 1);
1661*3117ece4Schristos 
1662*3117ece4Schristos             sequences[0].offset = 32;
1663*3117ece4Schristos             sequences[0].litLength = 32;
1664*3117ece4Schristos             sequences[0].matchLength = (1u << windowLog) - 32;
1665*3117ece4Schristos             sequences[0].rep = 0;
1666*3117ece4Schristos             {
1667*3117ece4Schristos                 size_t i;
1668*3117ece4Schristos                 for (i = 1; i < kNbSequences; ++i) {
1669*3117ece4Schristos                     sequences[i].offset = (1u << windowLog) - (FUZ_rand(&seed) % 8);
1670*3117ece4Schristos                     sequences[i].litLength = FUZ_rand(&seed) & 7;
1671*3117ece4Schristos                     sequences[i].matchLength = 10 - sequences[i].litLength;
1672*3117ece4Schristos                     sequences[i].rep = 0;
1673*3117ece4Schristos                 }
1674*3117ece4Schristos             }
1675*3117ece4Schristos 
1676*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1677*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
1678*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_minMatch, 3));
1679*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_validateSequences, 1));
1680*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_windowLog, windowLog));
1681*3117ece4Schristos             assert(srcSize <= kMaxSrcSize);
1682*3117ece4Schristos             cSize = ZSTD_compressSequences(zc, compressedBuffer, compressedBufferSize, sequences, kNbSequences, src, srcSize);
1683*3117ece4Schristos             CHECK_Z(cSize);
1684*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters));
1685*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_windowLogMax, windowLog))
1686*3117ece4Schristos             {
1687*3117ece4Schristos                 ZSTD_inBuffer in = {compressedBuffer, cSize, 0};
1688*3117ece4Schristos                 size_t decompressedBytes = 0;
1689*3117ece4Schristos                 for (;;) {
1690*3117ece4Schristos                     ZSTD_outBuffer out = {decodedBuffer, decodedBufferSize, 0};
1691*3117ece4Schristos                     size_t const ret = ZSTD_decompressStream(zd, &out, &in);
1692*3117ece4Schristos                     CHECK_Z(ret);
1693*3117ece4Schristos                     CHECK(decompressedBytes + out.pos > srcSize, "Output too large");
1694*3117ece4Schristos                     CHECK(memcmp(out.dst, src + decompressedBytes, out.pos), "Corrupted");
1695*3117ece4Schristos                     decompressedBytes += out.pos;
1696*3117ece4Schristos                     if (ret == 0) {
1697*3117ece4Schristos                         break;
1698*3117ece4Schristos                     }
1699*3117ece4Schristos                 }
1700*3117ece4Schristos                 CHECK(decompressedBytes != srcSize, "Output wrong size");
1701*3117ece4Schristos             }
1702*3117ece4Schristos         }
1703*3117ece4Schristos         free(sequences);
1704*3117ece4Schristos         free(src);
1705*3117ece4Schristos     }
1706*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1707*3117ece4Schristos 
1708*3117ece4Schristos     /* Overlen overwriting window data bug */
1709*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : wildcopy doesn't overwrite potential match data : ", testNb++);
1710*3117ece4Schristos     {   /* This test has a window size of 1024 bytes and consists of 3 blocks:
1711*3117ece4Schristos             1. 'a' repeated 517 times
1712*3117ece4Schristos             2. 'b' repeated 516 times
1713*3117ece4Schristos             3. a compressed block with no literals and 3 sequence commands:
1714*3117ece4Schristos                 litlength = 0, offset = 24, match length = 24
1715*3117ece4Schristos                 litlength = 0, offset = 24, match length = 3 (this one creates an overlength write of length 2*WILDCOPY_OVERLENGTH - 3)
1716*3117ece4Schristos                 litlength = 0, offset = 1021, match length = 3 (this one will try to read from overwritten data if the buffer is too small) */
1717*3117ece4Schristos 
1718*3117ece4Schristos         const char* testCase =
1719*3117ece4Schristos             "\x28\xB5\x2F\xFD\x04\x00\x4C\x00\x00\x10\x61\x61\x01\x00\x00\x2A"
1720*3117ece4Schristos             "\x80\x05\x44\x00\x00\x08\x62\x01\x00\x00\x2A\x20\x04\x5D\x00\x00"
1721*3117ece4Schristos             "\x00\x03\x40\x00\x00\x64\x60\x27\xB0\xE0\x0C\x67\x62\xCE\xE0";
1722*3117ece4Schristos         ZSTD_DStream* const zds = ZSTD_createDStream();
1723*3117ece4Schristos         if (zds==NULL) goto _output_error;
1724*3117ece4Schristos 
1725*3117ece4Schristos         CHECK_Z( ZSTD_initDStream(zds) );
1726*3117ece4Schristos         inBuff.src = testCase;
1727*3117ece4Schristos         inBuff.size = 47;
1728*3117ece4Schristos         inBuff.pos = 0;
1729*3117ece4Schristos         outBuff.dst = decodedBuffer;
1730*3117ece4Schristos         outBuff.size = CNBufferSize;
1731*3117ece4Schristos         outBuff.pos = 0;
1732*3117ece4Schristos 
1733*3117ece4Schristos         while (inBuff.pos < inBuff.size) {
1734*3117ece4Schristos             CHECK_Z( ZSTD_decompressStream(zds, &outBuff, &inBuff) );
1735*3117ece4Schristos         }
1736*3117ece4Schristos 
1737*3117ece4Schristos         ZSTD_freeDStream(zds);
1738*3117ece4Schristos     }
1739*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1740*3117ece4Schristos 
1741*3117ece4Schristos     /* Small Sequence Section bug */
1742*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : decompress blocks with small sequences section : ", testNb++);
1743*3117ece4Schristos     {   /* This test consists of 3 blocks. Each block has one sequence.
1744*3117ece4Schristos             The sequence has literal length of 10, match length of 10 and offset of 10.
1745*3117ece4Schristos             The sequence value and compression mode for the blocks are following:
1746*3117ece4Schristos             The order of values are ll, ml, of.
1747*3117ece4Schristos               - First block  : (10, 7, 13) (rle, rle, rle)
1748*3117ece4Schristos                  - size of sequences section: 6 bytes (1 byte for nbSeq, 1 byte for encoding mode, 3 bytes for rle, 1 byte bitstream)
1749*3117ece4Schristos               - Second block : (10, 7, 1) (repeat, repeat, rle)
1750*3117ece4Schristos                  - size of sequences section: 4 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 bytes for rle, 1 byte bitstream)
1751*3117ece4Schristos               - Third block  : (10, 7, 1) (repeat, repeat, repeat)
1752*3117ece4Schristos                  - size of sequences section: 3 bytes (1 byte for nbSeq, 1 byte for encoding mode, 1 byte bitstream) */
1753*3117ece4Schristos 
1754*3117ece4Schristos         unsigned char compressed[] = {
1755*3117ece4Schristos             0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x3c, 0x35, 0x01, 0x00, 0xf0, 0x85, 0x08,
1756*3117ece4Schristos             0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1757*3117ece4Schristos             0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac,
1758*3117ece4Schristos             0x69, 0x94, 0x89, 0x1c, 0x03, 0x44, 0x0a, 0x07, 0x00, 0xb4, 0x04, 0x80,
1759*3117ece4Schristos             0x40, 0x0a, 0xa4
1760*3117ece4Schristos         };
1761*3117ece4Schristos         unsigned int compressedSize = 51;
1762*3117ece4Schristos         unsigned char decompressed[] = {
1763*3117ece4Schristos             0x85, 0x08, 0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x85, 0x08,
1764*3117ece4Schristos             0xc2, 0xc4, 0x70, 0xcf, 0xd7, 0xc0, 0x96, 0x7e, 0x4c, 0x6b, 0xa9, 0x8b,
1765*3117ece4Schristos             0xbc, 0xc5, 0xb6, 0xd9, 0x7f, 0x4c, 0x4c, 0x6b, 0xa9, 0x8b, 0xbc, 0xc5,
1766*3117ece4Schristos             0xb6, 0xd9, 0x7f, 0x4c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94,
1767*3117ece4Schristos             0x89, 0x1c, 0xf1, 0x05, 0xa6, 0x54, 0xef, 0xac, 0x69, 0x94, 0x89, 0x1c
1768*3117ece4Schristos         };
1769*3117ece4Schristos         unsigned int decompressedSize = 60;
1770*3117ece4Schristos 
1771*3117ece4Schristos         ZSTD_DStream* const zds = ZSTD_createDStream();
1772*3117ece4Schristos         if (zds==NULL) goto _output_error;
1773*3117ece4Schristos 
1774*3117ece4Schristos         CHECK_Z( ZSTD_initDStream(zds) );
1775*3117ece4Schristos         inBuff.src = compressed;
1776*3117ece4Schristos         inBuff.size = compressedSize;
1777*3117ece4Schristos         inBuff.pos = 0;
1778*3117ece4Schristos         outBuff.dst = decodedBuffer;
1779*3117ece4Schristos         outBuff.size = CNBufferSize;
1780*3117ece4Schristos         outBuff.pos = 0;
1781*3117ece4Schristos 
1782*3117ece4Schristos         CHECK(ZSTD_decompressStream(zds, &outBuff, &inBuff) != 0,
1783*3117ece4Schristos               "Decompress did not reach the end of frame");
1784*3117ece4Schristos         CHECK(inBuff.pos != inBuff.size, "Decompress did not fully consume input");
1785*3117ece4Schristos         CHECK(outBuff.pos != decompressedSize, "Decompressed size does not match");
1786*3117ece4Schristos         CHECK(memcmp(outBuff.dst, decompressed, decompressedSize) != 0,
1787*3117ece4Schristos               "Decompressed data does not match");
1788*3117ece4Schristos 
1789*3117ece4Schristos         ZSTD_freeDStream(zds);
1790*3117ece4Schristos     }
1791*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1792*3117ece4Schristos 
1793*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : raw block can be streamed: ", testNb++);
1794*3117ece4Schristos     {   size_t const inputSize = 10000;
1795*3117ece4Schristos         size_t const compCapacity = ZSTD_compressBound(inputSize);
1796*3117ece4Schristos         BYTE* const input = (BYTE*)malloc(inputSize);
1797*3117ece4Schristos         BYTE* const comp = (BYTE*)malloc(compCapacity);
1798*3117ece4Schristos         BYTE* const decomp = (BYTE*)malloc(inputSize);
1799*3117ece4Schristos 
1800*3117ece4Schristos         CHECK(input == NULL || comp == NULL || decomp == NULL, "failed to alloc buffers");
1801*3117ece4Schristos 
1802*3117ece4Schristos         RDG_genBuffer(input, inputSize, 0.0, 0.0, seed);
1803*3117ece4Schristos         {   size_t const compSize = ZSTD_compress(comp, compCapacity, input, inputSize, -(int)inputSize);
1804*3117ece4Schristos             ZSTD_inBuffer in = { comp, 0, 0 };
1805*3117ece4Schristos             ZSTD_outBuffer out = { decomp, 0, 0 };
1806*3117ece4Schristos             CHECK_Z(compSize);
1807*3117ece4Schristos             CHECK_Z( ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters) );
1808*3117ece4Schristos             while (in.size < compSize) {
1809*3117ece4Schristos                 in.size = MIN(in.size + 100, compSize);
1810*3117ece4Schristos                 while (in.pos < in.size) {
1811*3117ece4Schristos                     size_t const outPos = out.pos;
1812*3117ece4Schristos                     if (out.pos == out.size) {
1813*3117ece4Schristos                         out.size = MIN(out.size + 10, inputSize);
1814*3117ece4Schristos                     }
1815*3117ece4Schristos                     CHECK_Z( ZSTD_decompressStream(zd, &out, &in) );
1816*3117ece4Schristos                     CHECK(!(out.pos > outPos), "We are not streaming (no output generated)");
1817*3117ece4Schristos                 }
1818*3117ece4Schristos             }
1819*3117ece4Schristos             CHECK(in.pos != compSize, "Not all input consumed!");
1820*3117ece4Schristos             CHECK(out.pos != inputSize, "Not all output produced!");
1821*3117ece4Schristos         }
1822*3117ece4Schristos         CHECK(memcmp(input, decomp, inputSize), "round trip failed!");
1823*3117ece4Schristos 
1824*3117ece4Schristos         free(input);
1825*3117ece4Schristos         free(comp);
1826*3117ece4Schristos         free(decomp);
1827*3117ece4Schristos     }
1828*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1829*3117ece4Schristos 
1830*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : dictionary + uncompressible block + reusing tables checks offset table validity: ", testNb++);
1831*3117ece4Schristos     {   ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1832*3117ece4Schristos             dictionary.start, dictionary.filled,
1833*3117ece4Schristos             ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1834*3117ece4Schristos             ZSTD_getCParams(3, 0, dictionary.filled),
1835*3117ece4Schristos             ZSTD_defaultCMem);
1836*3117ece4Schristos         const size_t inbufsize = 2 * 128 * 1024; /* 2 blocks */
1837*3117ece4Schristos         const size_t outbufsize = ZSTD_compressBound(inbufsize);
1838*3117ece4Schristos         size_t inbufpos = 0;
1839*3117ece4Schristos         size_t cursegmentlen;
1840*3117ece4Schristos         BYTE *inbuf = (BYTE *)malloc(inbufsize);
1841*3117ece4Schristos         BYTE *outbuf = (BYTE *)malloc(outbufsize);
1842*3117ece4Schristos         BYTE *checkbuf = (BYTE *)malloc(inbufsize);
1843*3117ece4Schristos         size_t ret;
1844*3117ece4Schristos 
1845*3117ece4Schristos         CHECK(cdict == NULL, "failed to alloc cdict");
1846*3117ece4Schristos         CHECK(inbuf == NULL, "failed to alloc input buffer");
1847*3117ece4Schristos 
1848*3117ece4Schristos         /* first block is uncompressible */
1849*3117ece4Schristos         cursegmentlen = 128 * 1024;
1850*3117ece4Schristos         RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0., 0., seed);
1851*3117ece4Schristos         inbufpos += cursegmentlen;
1852*3117ece4Schristos 
1853*3117ece4Schristos         /* second block is compressible */
1854*3117ece4Schristos         cursegmentlen = 128 * 1024 - 256;
1855*3117ece4Schristos         RDG_genBuffer(inbuf + inbufpos, cursegmentlen, 0.05, 0., seed);
1856*3117ece4Schristos         inbufpos += cursegmentlen;
1857*3117ece4Schristos 
1858*3117ece4Schristos         /* and includes a very long backref */
1859*3117ece4Schristos         cursegmentlen = 128;
1860*3117ece4Schristos         memcpy(inbuf + inbufpos, (BYTE*)dictionary.start + 256, cursegmentlen);
1861*3117ece4Schristos         inbufpos += cursegmentlen;
1862*3117ece4Schristos 
1863*3117ece4Schristos         /* and includes a very long backref */
1864*3117ece4Schristos         cursegmentlen = 128;
1865*3117ece4Schristos         memcpy(inbuf + inbufpos, (BYTE*)dictionary.start + 128, cursegmentlen);
1866*3117ece4Schristos         inbufpos += cursegmentlen;
1867*3117ece4Schristos 
1868*3117ece4Schristos         ret = ZSTD_compress_usingCDict(zc, outbuf, outbufsize, inbuf, inbufpos, cdict);
1869*3117ece4Schristos         CHECK_Z(ret);
1870*3117ece4Schristos 
1871*3117ece4Schristos         ret = ZSTD_decompress_usingDict(zd, checkbuf, inbufsize, outbuf, ret, dictionary.start, dictionary.filled);
1872*3117ece4Schristos         CHECK_Z(ret);
1873*3117ece4Schristos 
1874*3117ece4Schristos         CHECK(memcmp(inbuf, checkbuf, inbufpos), "start and finish buffers don't match");
1875*3117ece4Schristos 
1876*3117ece4Schristos         ZSTD_freeCDict(cdict);
1877*3117ece4Schristos         free(inbuf);
1878*3117ece4Schristos         free(outbuf);
1879*3117ece4Schristos         free(checkbuf);
1880*3117ece4Schristos     }
1881*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1882*3117ece4Schristos 
1883*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : dictionary + small blocks + reusing tables checks offset table validity: ", testNb++);
1884*3117ece4Schristos     {   ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(
1885*3117ece4Schristos             dictionary.start, dictionary.filled,
1886*3117ece4Schristos             ZSTD_dlm_byRef, ZSTD_dct_fullDict,
1887*3117ece4Schristos             ZSTD_getCParams(3, 0, dictionary.filled),
1888*3117ece4Schristos             ZSTD_defaultCMem);
1889*3117ece4Schristos         ZSTD_outBuffer out = {compressedBuffer, compressedBufferSize, 0};
1890*3117ece4Schristos         int remainingInput = 256 * 1024;
1891*3117ece4Schristos         int offset;
1892*3117ece4Schristos 
1893*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1894*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_refCDict(zc, cdict));
1895*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, 1));
1896*3117ece4Schristos         /* Write a bunch of 6 byte blocks */
1897*3117ece4Schristos         while (remainingInput > 0) {
1898*3117ece4Schristos           char testBuffer[6] = "\xAA\xAA\xAA\xAA\xAA\xAA";
1899*3117ece4Schristos           const size_t kSmallBlockSize = sizeof(testBuffer);
1900*3117ece4Schristos           ZSTD_inBuffer in = {testBuffer, kSmallBlockSize, 0};
1901*3117ece4Schristos 
1902*3117ece4Schristos           CHECK_Z(ZSTD_compressStream2(zc, &out, &in, ZSTD_e_flush));
1903*3117ece4Schristos           CHECK(in.pos != in.size, "input not fully consumed");
1904*3117ece4Schristos           remainingInput -= kSmallBlockSize;
1905*3117ece4Schristos         }
1906*3117ece4Schristos         /* Write several very long offset matches into the dictionary */
1907*3117ece4Schristos         for (offset = 1024; offset >= 0; offset -= 128) {
1908*3117ece4Schristos           ZSTD_inBuffer in = {(BYTE*)dictionary.start + offset, 128, 0};
1909*3117ece4Schristos           ZSTD_EndDirective flush = offset > 0 ? ZSTD_e_continue : ZSTD_e_end;
1910*3117ece4Schristos           CHECK_Z(ZSTD_compressStream2(zc, &out, &in, flush));
1911*3117ece4Schristos           CHECK(in.pos != in.size, "input not fully consumed");
1912*3117ece4Schristos         }
1913*3117ece4Schristos         /* Ensure decompression works */
1914*3117ece4Schristos         CHECK_Z(ZSTD_decompress_usingDict(zd, decodedBuffer, CNBufferSize, out.dst, out.pos, dictionary.start, dictionary.filled));
1915*3117ece4Schristos 
1916*3117ece4Schristos         ZSTD_freeCDict(cdict);
1917*3117ece4Schristos     }
1918*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
1919*3117ece4Schristos 
1920*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Block-Level External Sequence Producer API: ", testNb++);
1921*3117ece4Schristos     {
1922*3117ece4Schristos         size_t const dstBufSize = ZSTD_compressBound(CNBufferSize);
1923*3117ece4Schristos         BYTE* const dstBuf = (BYTE*)malloc(dstBufSize);
1924*3117ece4Schristos         size_t const checkBufSize = CNBufferSize;
1925*3117ece4Schristos         BYTE* const checkBuf = (BYTE*)malloc(checkBufSize);
1926*3117ece4Schristos         int enableFallback;
1927*3117ece4Schristos         EMF_testCase sequenceProducerState;
1928*3117ece4Schristos 
1929*3117ece4Schristos         CHECK(dstBuf == NULL || checkBuf == NULL, "allocation failed");
1930*3117ece4Schristos 
1931*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
1932*3117ece4Schristos 
1933*3117ece4Schristos         /* Reference external matchfinder outside the test loop to
1934*3117ece4Schristos          * check that the reference is preserved across compressions */
1935*3117ece4Schristos         ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
1936*3117ece4Schristos 
1937*3117ece4Schristos         for (enableFallback = 0; enableFallback <= 1; enableFallback++) {
1938*3117ece4Schristos             size_t testCaseId;
1939*3117ece4Schristos             size_t const numTestCases = 9;
1940*3117ece4Schristos 
1941*3117ece4Schristos             EMF_testCase const testCases[] = {
1942*3117ece4Schristos                 EMF_ONE_BIG_SEQ,
1943*3117ece4Schristos                 EMF_LOTS_OF_SEQS,
1944*3117ece4Schristos                 EMF_ZERO_SEQS,
1945*3117ece4Schristos                 EMF_BIG_ERROR,
1946*3117ece4Schristos                 EMF_SMALL_ERROR,
1947*3117ece4Schristos                 EMF_INVALID_OFFSET,
1948*3117ece4Schristos                 EMF_INVALID_MATCHLEN,
1949*3117ece4Schristos                 EMF_INVALID_LITLEN,
1950*3117ece4Schristos                 EMF_INVALID_LAST_LITS
1951*3117ece4Schristos             };
1952*3117ece4Schristos 
1953*3117ece4Schristos             ZSTD_ErrorCode const errorCodes[] = {
1954*3117ece4Schristos                 ZSTD_error_no_error,
1955*3117ece4Schristos                 ZSTD_error_no_error,
1956*3117ece4Schristos                 ZSTD_error_sequenceProducer_failed,
1957*3117ece4Schristos                 ZSTD_error_sequenceProducer_failed,
1958*3117ece4Schristos                 ZSTD_error_sequenceProducer_failed,
1959*3117ece4Schristos                 ZSTD_error_externalSequences_invalid,
1960*3117ece4Schristos                 ZSTD_error_externalSequences_invalid,
1961*3117ece4Schristos                 ZSTD_error_externalSequences_invalid,
1962*3117ece4Schristos                 ZSTD_error_externalSequences_invalid
1963*3117ece4Schristos             };
1964*3117ece4Schristos 
1965*3117ece4Schristos             for (testCaseId = 0; testCaseId < numTestCases; testCaseId++) {
1966*3117ece4Schristos                 size_t res;
1967*3117ece4Schristos 
1968*3117ece4Schristos                 int const compressionShouldSucceed = (
1969*3117ece4Schristos                     (errorCodes[testCaseId] == ZSTD_error_no_error) ||
1970*3117ece4Schristos                     (enableFallback && errorCodes[testCaseId] == ZSTD_error_sequenceProducer_failed)
1971*3117ece4Schristos                 );
1972*3117ece4Schristos 
1973*3117ece4Schristos                 int const testWithSequenceValidation = (
1974*3117ece4Schristos                     testCases[testCaseId] == EMF_INVALID_OFFSET
1975*3117ece4Schristos                 );
1976*3117ece4Schristos 
1977*3117ece4Schristos                 sequenceProducerState = testCases[testCaseId];
1978*3117ece4Schristos 
1979*3117ece4Schristos                 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
1980*3117ece4Schristos                 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_validateSequences, testWithSequenceValidation));
1981*3117ece4Schristos                 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, enableFallback));
1982*3117ece4Schristos                 res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
1983*3117ece4Schristos 
1984*3117ece4Schristos                 if (compressionShouldSucceed) {
1985*3117ece4Schristos                     CHECK(ZSTD_isError(res), "EMF: Compression error: %s", ZSTD_getErrorName(res));
1986*3117ece4Schristos                     CHECK_Z(ZSTD_decompress(checkBuf, checkBufSize, dstBuf, res));
1987*3117ece4Schristos                     CHECK(memcmp(CNBuffer, checkBuf, CNBufferSize) != 0, "EMF: Corruption!");
1988*3117ece4Schristos                 } else {
1989*3117ece4Schristos                     CHECK(!ZSTD_isError(res), "EMF: Should have raised an error!");
1990*3117ece4Schristos                     CHECK(
1991*3117ece4Schristos                         ZSTD_getErrorCode(res) != errorCodes[testCaseId],
1992*3117ece4Schristos                         "EMF: Wrong error code: %s", ZSTD_getErrorName(res)
1993*3117ece4Schristos                     );
1994*3117ece4Schristos                 }
1995*3117ece4Schristos             }
1996*3117ece4Schristos 
1997*3117ece4Schristos             /* Test compression with external matchfinder + empty src buffer */
1998*3117ece4Schristos             {
1999*3117ece4Schristos                 size_t res;
2000*3117ece4Schristos                 sequenceProducerState = EMF_ZERO_SEQS;
2001*3117ece4Schristos                 ZSTD_CCtx_reset(zc, ZSTD_reset_session_only);
2002*3117ece4Schristos                 CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, enableFallback));
2003*3117ece4Schristos                 res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, 0);
2004*3117ece4Schristos                 CHECK(ZSTD_isError(res), "EMF: Compression error: %s", ZSTD_getErrorName(res));
2005*3117ece4Schristos                 CHECK(ZSTD_decompress(checkBuf, checkBufSize, dstBuf, res) != 0, "EMF: Empty src round trip failed!");
2006*3117ece4Schristos             }
2007*3117ece4Schristos         }
2008*3117ece4Schristos 
2009*3117ece4Schristos         /* Test that reset clears the external matchfinder */
2010*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
2011*3117ece4Schristos         sequenceProducerState = EMF_BIG_ERROR; /* ensure zstd will fail if the matchfinder wasn't cleared */
2012*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, 0));
2013*3117ece4Schristos         CHECK_Z(ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize));
2014*3117ece4Schristos 
2015*3117ece4Schristos         /* Test that registering mFinder == NULL clears the external matchfinder */
2016*3117ece4Schristos         ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
2017*3117ece4Schristos         ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
2018*3117ece4Schristos         sequenceProducerState = EMF_BIG_ERROR; /* ensure zstd will fail if the matchfinder wasn't cleared */
2019*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, 0));
2020*3117ece4Schristos         ZSTD_registerSequenceProducer(zc, NULL, NULL); /* clear the external matchfinder */
2021*3117ece4Schristos         CHECK_Z(ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize));
2022*3117ece4Schristos 
2023*3117ece4Schristos         /* Test that external matchfinder doesn't interact with older APIs */
2024*3117ece4Schristos         ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters);
2025*3117ece4Schristos         ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
2026*3117ece4Schristos         sequenceProducerState = EMF_BIG_ERROR; /* ensure zstd will fail if the matchfinder is used */
2027*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableSeqProducerFallback, 0));
2028*3117ece4Schristos         CHECK_Z(ZSTD_compressCCtx(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize, 3));
2029*3117ece4Schristos 
2030*3117ece4Schristos         /* Test that compression returns the correct error with LDM */
2031*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
2032*3117ece4Schristos         {
2033*3117ece4Schristos             size_t res;
2034*3117ece4Schristos             ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
2035*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_enableLongDistanceMatching, ZSTD_ps_enable));
2036*3117ece4Schristos             res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
2037*3117ece4Schristos             CHECK(!ZSTD_isError(res), "EMF: Should have raised an error!");
2038*3117ece4Schristos             CHECK(
2039*3117ece4Schristos                 ZSTD_getErrorCode(res) != ZSTD_error_parameter_combination_unsupported,
2040*3117ece4Schristos                 "EMF: Wrong error code: %s", ZSTD_getErrorName(res)
2041*3117ece4Schristos             );
2042*3117ece4Schristos         }
2043*3117ece4Schristos 
2044*3117ece4Schristos #ifdef ZSTD_MULTITHREAD
2045*3117ece4Schristos         /* Test that compression returns the correct error with nbWorkers > 0 */
2046*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_reset(zc, ZSTD_reset_session_and_parameters));
2047*3117ece4Schristos         {
2048*3117ece4Schristos             size_t res;
2049*3117ece4Schristos             ZSTD_registerSequenceProducer(zc, &sequenceProducerState, zstreamSequenceProducer);
2050*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, 1));
2051*3117ece4Schristos             res = ZSTD_compress2(zc, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
2052*3117ece4Schristos             CHECK(!ZSTD_isError(res), "EMF: Should have raised an error!");
2053*3117ece4Schristos             CHECK(
2054*3117ece4Schristos                 ZSTD_getErrorCode(res) != ZSTD_error_parameter_combination_unsupported,
2055*3117ece4Schristos                 "EMF: Wrong error code: %s", ZSTD_getErrorName(res)
2056*3117ece4Schristos             );
2057*3117ece4Schristos         }
2058*3117ece4Schristos #endif
2059*3117ece4Schristos 
2060*3117ece4Schristos         free(dstBuf);
2061*3117ece4Schristos         free(checkBuf);
2062*3117ece4Schristos     }
2063*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2064*3117ece4Schristos 
2065*3117ece4Schristos 
2066*3117ece4Schristos     /* Test maxBlockSize cctx param functionality */
2067*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Testing maxBlockSize PR#3418: ", testNb++);
2068*3117ece4Schristos     {
2069*3117ece4Schristos         ZSTD_CCtx* cctx = ZSTD_createCCtx();
2070*3117ece4Schristos 
2071*3117ece4Schristos         /* Quick test to make sure maxBlockSize bounds are enforced */
2072*3117ece4Schristos         assert(ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, ZSTD_BLOCKSIZE_MAX_MIN - 1)));
2073*3117ece4Schristos         assert(ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, ZSTD_BLOCKSIZE_MAX + 1)));
2074*3117ece4Schristos 
2075*3117ece4Schristos         /* Test maxBlockSize < windowSize and windowSize < maxBlockSize*/
2076*3117ece4Schristos         {
2077*3117ece4Schristos             size_t srcSize = 2 << 10;
2078*3117ece4Schristos             void* const src = CNBuffer;
2079*3117ece4Schristos             size_t dstSize = ZSTD_compressBound(srcSize);
2080*3117ece4Schristos             void* const dst1 = compressedBuffer;
2081*3117ece4Schristos             void* const dst2 = (BYTE*)compressedBuffer + dstSize;
2082*3117ece4Schristos             size_t size1, size2;
2083*3117ece4Schristos             void* const checkBuf = malloc(srcSize);
2084*3117ece4Schristos             memset(src, 'x', srcSize);
2085*3117ece4Schristos 
2086*3117ece4Schristos             /* maxBlockSize = 1KB */
2087*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 1u << 10));
2088*3117ece4Schristos             size1 = ZSTD_compress2(cctx, dst1, dstSize, src, srcSize);
2089*3117ece4Schristos 
2090*3117ece4Schristos             if (ZSTD_isError(size1)) goto _output_error;
2091*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst1, size1));
2092*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2093*3117ece4Schristos 
2094*3117ece4Schristos             /* maxBlockSize = 3KB */
2095*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 3u << 10));
2096*3117ece4Schristos             size2 = ZSTD_compress2(cctx, dst2, dstSize, src, srcSize);
2097*3117ece4Schristos 
2098*3117ece4Schristos             if (ZSTD_isError(size2)) goto _output_error;
2099*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst2, size2));
2100*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2101*3117ece4Schristos 
2102*3117ece4Schristos             assert(size1 - size2 == 4); /* We add another RLE block with header + character */
2103*3117ece4Schristos             assert(memcmp(dst1, dst2, size2) != 0); /* Compressed output should not be equal */
2104*3117ece4Schristos 
2105*3117ece4Schristos             /* maxBlockSize = 1KB, windowLog = 10 */
2106*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 1u << 10));
2107*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 10));
2108*3117ece4Schristos             size1 = ZSTD_compress2(cctx, dst1, dstSize, src, srcSize);
2109*3117ece4Schristos 
2110*3117ece4Schristos             if (ZSTD_isError(size1)) goto _output_error;
2111*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst1, size1));
2112*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2113*3117ece4Schristos 
2114*3117ece4Schristos             /* maxBlockSize = 3KB, windowLog = 10 */
2115*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 3u << 10));
2116*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, 10));
2117*3117ece4Schristos             size2 = ZSTD_compress2(cctx, dst2, dstSize, src, srcSize);
2118*3117ece4Schristos 
2119*3117ece4Schristos             if (ZSTD_isError(size2)) goto _output_error;
2120*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst2, size2));
2121*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2122*3117ece4Schristos 
2123*3117ece4Schristos             assert(size1 == size2);
2124*3117ece4Schristos             assert(memcmp(dst1, dst2, size1) == 0); /* Compressed output should be equal */
2125*3117ece4Schristos 
2126*3117ece4Schristos             free(checkBuf);
2127*3117ece4Schristos         }
2128*3117ece4Schristos 
2129*3117ece4Schristos         ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2130*3117ece4Schristos 
2131*3117ece4Schristos         /* Test maxBlockSize = 0 is valid */
2132*3117ece4Schristos         {   size_t srcSize = 256 << 10;
2133*3117ece4Schristos             void* const src = CNBuffer;
2134*3117ece4Schristos             size_t dstSize = ZSTD_compressBound(srcSize);
2135*3117ece4Schristos             void* const dst1 = compressedBuffer;
2136*3117ece4Schristos             void* const dst2 = (BYTE*)compressedBuffer + dstSize;
2137*3117ece4Schristos             size_t size1, size2;
2138*3117ece4Schristos             void* const checkBuf = malloc(srcSize);
2139*3117ece4Schristos 
2140*3117ece4Schristos             /* maxBlockSize = 0 */
2141*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, 0));
2142*3117ece4Schristos             size1 = ZSTD_compress2(cctx, dst1, dstSize, src, srcSize);
2143*3117ece4Schristos 
2144*3117ece4Schristos             if (ZSTD_isError(size1)) goto _output_error;
2145*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst1, size1));
2146*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2147*3117ece4Schristos 
2148*3117ece4Schristos             /* maxBlockSize = ZSTD_BLOCKSIZE_MAX */
2149*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_maxBlockSize, ZSTD_BLOCKSIZE_MAX));
2150*3117ece4Schristos             size2 = ZSTD_compress2(cctx, dst2, dstSize, src, srcSize);
2151*3117ece4Schristos 
2152*3117ece4Schristos             if (ZSTD_isError(size2)) goto _output_error;
2153*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst2, size2));
2154*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2155*3117ece4Schristos 
2156*3117ece4Schristos             assert(size1 == size2);
2157*3117ece4Schristos             assert(memcmp(dst1, dst2, size1) == 0); /* Compressed output should be equal */
2158*3117ece4Schristos             free(checkBuf);
2159*3117ece4Schristos         }
2160*3117ece4Schristos         ZSTD_freeCCtx(cctx);
2161*3117ece4Schristos     }
2162*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2163*3117ece4Schristos 
2164*3117ece4Schristos     /* Test Sequence Validation */
2165*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Testing sequence validation: ", testNb++);
2166*3117ece4Schristos     {
2167*3117ece4Schristos         ZSTD_CCtx* cctx = ZSTD_createCCtx();
2168*3117ece4Schristos 
2169*3117ece4Schristos         /* Test minMatch >= 4, matchLength < 4 */
2170*3117ece4Schristos         {
2171*3117ece4Schristos             size_t srcSize = 11;
2172*3117ece4Schristos             void* const src = CNBuffer;
2173*3117ece4Schristos             size_t dstSize = ZSTD_compressBound(srcSize);
2174*3117ece4Schristos             void* const dst = compressedBuffer;
2175*3117ece4Schristos             size_t const kNbSequences = 4;
2176*3117ece4Schristos             ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2177*3117ece4Schristos 
2178*3117ece4Schristos             memset(src, 'x', srcSize);
2179*3117ece4Schristos 
2180*3117ece4Schristos             sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
2181*3117ece4Schristos             sequences[1] = (ZSTD_Sequence) {1, 0, 3, 0};
2182*3117ece4Schristos             sequences[2] = (ZSTD_Sequence) {1, 0, 3, 0};
2183*3117ece4Schristos             sequences[3] = (ZSTD_Sequence) {0, 1, 0, 0};
2184*3117ece4Schristos 
2185*3117ece4Schristos             /* Test with sequence validation */
2186*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2187*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2188*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
2189*3117ece4Schristos 
2190*3117ece4Schristos             cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2191*3117ece4Schristos                                    sequences, kNbSequences,
2192*3117ece4Schristos                                    src, srcSize);
2193*3117ece4Schristos 
2194*3117ece4Schristos             CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2195*3117ece4Schristos             CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2196*3117ece4Schristos 
2197*3117ece4Schristos             ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2198*3117ece4Schristos 
2199*3117ece4Schristos             /* Test without sequence validation */
2200*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2201*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2202*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 0));
2203*3117ece4Schristos 
2204*3117ece4Schristos             cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2205*3117ece4Schristos                                    sequences, kNbSequences,
2206*3117ece4Schristos                                    src, srcSize);
2207*3117ece4Schristos 
2208*3117ece4Schristos             CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2209*3117ece4Schristos             CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2210*3117ece4Schristos 
2211*3117ece4Schristos             free(sequences);
2212*3117ece4Schristos         }
2213*3117ece4Schristos 
2214*3117ece4Schristos         ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2215*3117ece4Schristos 
2216*3117ece4Schristos 
2217*3117ece4Schristos         /* Test with no block delim */
2218*3117ece4Schristos         {
2219*3117ece4Schristos             size_t srcSize = 4;
2220*3117ece4Schristos             void* const src = CNBuffer;
2221*3117ece4Schristos             size_t dstSize = ZSTD_compressBound(srcSize);
2222*3117ece4Schristos             void* const dst = compressedBuffer;
2223*3117ece4Schristos             size_t const kNbSequences = 1;
2224*3117ece4Schristos             ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2225*3117ece4Schristos             void* const checkBuf = malloc(srcSize);
2226*3117ece4Schristos 
2227*3117ece4Schristos             memset(src, 'x', srcSize);
2228*3117ece4Schristos 
2229*3117ece4Schristos             sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
2230*3117ece4Schristos 
2231*3117ece4Schristos             /* Test with sequence validation */
2232*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 3));
2233*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_noBlockDelimiters));
2234*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
2235*3117ece4Schristos 
2236*3117ece4Schristos             cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2237*3117ece4Schristos                                    sequences, kNbSequences,
2238*3117ece4Schristos                                    src, srcSize);
2239*3117ece4Schristos 
2240*3117ece4Schristos             CHECK(ZSTD_isError(cSize), "Should not throw an error");
2241*3117ece4Schristos             CHECK_Z(ZSTD_decompress(checkBuf, srcSize, dst, cSize));
2242*3117ece4Schristos             CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2243*3117ece4Schristos 
2244*3117ece4Schristos             free(sequences);
2245*3117ece4Schristos             free(checkBuf);
2246*3117ece4Schristos         }
2247*3117ece4Schristos 
2248*3117ece4Schristos         ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2249*3117ece4Schristos 
2250*3117ece4Schristos         { /* Test case with two additional sequences */
2251*3117ece4Schristos             size_t srcSize = 19;
2252*3117ece4Schristos             void* const src = CNBuffer;
2253*3117ece4Schristos             size_t dstSize = ZSTD_compressBound(srcSize);
2254*3117ece4Schristos             void* const dst = compressedBuffer;
2255*3117ece4Schristos             size_t const kNbSequences = 7;
2256*3117ece4Schristos             ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2257*3117ece4Schristos 
2258*3117ece4Schristos             memset(src, 'x', srcSize);
2259*3117ece4Schristos 
2260*3117ece4Schristos             sequences[0] = (ZSTD_Sequence) {1, 1, 3, 0};
2261*3117ece4Schristos             sequences[1] = (ZSTD_Sequence) {1, 0, 3, 0};
2262*3117ece4Schristos             sequences[2] = (ZSTD_Sequence) {1, 0, 3, 0};
2263*3117ece4Schristos             sequences[3] = (ZSTD_Sequence) {1, 0, 3, 0};
2264*3117ece4Schristos             sequences[4] = (ZSTD_Sequence) {1, 0, 3, 0};
2265*3117ece4Schristos             sequences[5] = (ZSTD_Sequence) {1, 0, 3, 0};
2266*3117ece4Schristos             sequences[6] = (ZSTD_Sequence) {0, 0, 0, 0};
2267*3117ece4Schristos 
2268*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2269*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2270*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1));
2271*3117ece4Schristos 
2272*3117ece4Schristos             cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2273*3117ece4Schristos                                    sequences, kNbSequences,
2274*3117ece4Schristos                                    src, srcSize);
2275*3117ece4Schristos 
2276*3117ece4Schristos             CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2277*3117ece4Schristos             CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2278*3117ece4Schristos 
2279*3117ece4Schristos             ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
2280*3117ece4Schristos 
2281*3117ece4Schristos             /* Test without sequence validation */
2282*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, 5));
2283*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters));
2284*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 0));
2285*3117ece4Schristos 
2286*3117ece4Schristos             cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2287*3117ece4Schristos                                    sequences, kNbSequences,
2288*3117ece4Schristos                                    src, srcSize);
2289*3117ece4Schristos 
2290*3117ece4Schristos             CHECK(!ZSTD_isError(cSize), "Should throw an error"); /* maxNbSeq is too small and an assert will fail */
2291*3117ece4Schristos             CHECK(ZSTD_getErrorCode(cSize) != ZSTD_error_externalSequences_invalid, "Wrong error code: %s", ZSTD_getErrorName(cSize)); /* fails sequence validation */
2292*3117ece4Schristos 
2293*3117ece4Schristos             free(sequences);
2294*3117ece4Schristos         }
2295*3117ece4Schristos         ZSTD_freeCCtx(cctx);
2296*3117ece4Schristos     }
2297*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2298*3117ece4Schristos 
2299*3117ece4Schristos 
2300*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Testing large offset with small window size: ", testNb++);
2301*3117ece4Schristos     {
2302*3117ece4Schristos         ZSTD_CCtx* cctx = ZSTD_createCCtx();
2303*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
2304*3117ece4Schristos 
2305*3117ece4Schristos         /* Test large offset, small window size*/
2306*3117ece4Schristos         {
2307*3117ece4Schristos             size_t srcSize = 21;
2308*3117ece4Schristos             void* const src = CNBuffer;
2309*3117ece4Schristos             size_t dstSize = ZSTD_compressBound(srcSize);
2310*3117ece4Schristos             void* const dst = compressedBuffer;
2311*3117ece4Schristos             size_t const kNbSequences = 4;
2312*3117ece4Schristos             ZSTD_Sequence* sequences = malloc(sizeof(ZSTD_Sequence) * kNbSequences);
2313*3117ece4Schristos             void* const checkBuf = malloc(srcSize);
2314*3117ece4Schristos             const size_t largeDictSize = 1 << 25;
2315*3117ece4Schristos             ZSTD_CDict* cdict = NULL;
2316*3117ece4Schristos             ZSTD_DDict* ddict = NULL;
2317*3117ece4Schristos 
2318*3117ece4Schristos             /* Generate large dictionary */
2319*3117ece4Schristos             void* dictBuffer = calloc(largeDictSize, 1);
2320*3117ece4Schristos             ZSTD_compressionParameters cParams = ZSTD_getCParams(1, srcSize, largeDictSize);
2321*3117ece4Schristos             cParams.minMatch = ZSTD_MINMATCH_MIN;
2322*3117ece4Schristos             cParams.hashLog = ZSTD_HASHLOG_MIN;
2323*3117ece4Schristos             cParams.chainLog = ZSTD_CHAINLOG_MIN;
2324*3117ece4Schristos 
2325*3117ece4Schristos             cdict = ZSTD_createCDict_advanced(dictBuffer, largeDictSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, cParams, ZSTD_defaultCMem);
2326*3117ece4Schristos             ddict = ZSTD_createDDict_advanced(dictBuffer, largeDictSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, ZSTD_defaultCMem);
2327*3117ece4Schristos 
2328*3117ece4Schristos             ZSTD_CCtx_refCDict(cctx, cdict);
2329*3117ece4Schristos             ZSTD_DCtx_refDDict(dctx, ddict);
2330*3117ece4Schristos 
2331*3117ece4Schristos             sequences[0] = (ZSTD_Sequence) {3, 3, 3, 0};
2332*3117ece4Schristos             sequences[1] = (ZSTD_Sequence) {1 << 25, 0, 3, 0};
2333*3117ece4Schristos             sequences[2] = (ZSTD_Sequence) {1 << 25, 0, 9, 0};
2334*3117ece4Schristos             sequences[3] = (ZSTD_Sequence) {3, 0, 3, 0};
2335*3117ece4Schristos 
2336*3117ece4Schristos             cSize = ZSTD_compressSequences(cctx, dst, dstSize,
2337*3117ece4Schristos                                    sequences, kNbSequences,
2338*3117ece4Schristos                                    src, srcSize);
2339*3117ece4Schristos 
2340*3117ece4Schristos             CHECK(ZSTD_isError(cSize), "Should not throw an error");
2341*3117ece4Schristos 
2342*3117ece4Schristos             {
2343*3117ece4Schristos                 size_t dSize = ZSTD_decompressDCtx(dctx, checkBuf, srcSize, dst, cSize);
2344*3117ece4Schristos                 CHECK(ZSTD_isError(dSize), "Should not throw an error");
2345*3117ece4Schristos                 CHECK(memcmp(src, checkBuf, srcSize) != 0, "Corruption!");
2346*3117ece4Schristos             }
2347*3117ece4Schristos 
2348*3117ece4Schristos             free(sequences);
2349*3117ece4Schristos             free(checkBuf);
2350*3117ece4Schristos             free(dictBuffer);
2351*3117ece4Schristos             ZSTD_freeCDict(cdict);
2352*3117ece4Schristos             ZSTD_freeDDict(ddict);
2353*3117ece4Schristos         }
2354*3117ece4Schristos         ZSTD_freeCCtx(cctx);
2355*3117ece4Schristos         ZSTD_freeDCtx(dctx);
2356*3117ece4Schristos     }
2357*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2358*3117ece4Schristos 
2359*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Testing external sequence producer with static CCtx: ", testNb++);
2360*3117ece4Schristos     {
2361*3117ece4Schristos         size_t const dstBufSize = ZSTD_compressBound(CNBufferSize);
2362*3117ece4Schristos         BYTE* const dstBuf = (BYTE*)malloc(dstBufSize);
2363*3117ece4Schristos         size_t const checkBufSize = CNBufferSize;
2364*3117ece4Schristos         BYTE* const checkBuf = (BYTE*)malloc(checkBufSize);
2365*3117ece4Schristos         ZSTD_CCtx_params* params = ZSTD_createCCtxParams();
2366*3117ece4Schristos         ZSTD_CCtx* staticCCtx;
2367*3117ece4Schristos         void* cctxBuf;
2368*3117ece4Schristos         EMF_testCase seqProdState;
2369*3117ece4Schristos 
2370*3117ece4Schristos         CHECK_Z(ZSTD_CCtxParams_setParameter(params, ZSTD_c_validateSequences, 1));
2371*3117ece4Schristos         CHECK_Z(ZSTD_CCtxParams_setParameter(params, ZSTD_c_enableSeqProducerFallback, 0));
2372*3117ece4Schristos         ZSTD_CCtxParams_registerSequenceProducer(params, &seqProdState, zstreamSequenceProducer);
2373*3117ece4Schristos 
2374*3117ece4Schristos         {
2375*3117ece4Schristos             size_t const cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
2376*3117ece4Schristos             cctxBuf = malloc(cctxSize);
2377*3117ece4Schristos             staticCCtx = ZSTD_initStaticCCtx(cctxBuf, cctxSize);
2378*3117ece4Schristos             ZSTD_CCtx_setParametersUsingCCtxParams(staticCCtx, params);
2379*3117ece4Schristos         }
2380*3117ece4Schristos 
2381*3117ece4Schristos         // Check that compression with external sequence producer succeeds when expected
2382*3117ece4Schristos         seqProdState = EMF_LOTS_OF_SEQS;
2383*3117ece4Schristos         {
2384*3117ece4Schristos             size_t dResult;
2385*3117ece4Schristos             size_t const cResult = ZSTD_compress2(staticCCtx, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
2386*3117ece4Schristos             CHECK(ZSTD_isError(cResult), "EMF: Compression error: %s", ZSTD_getErrorName(cResult));
2387*3117ece4Schristos             dResult = ZSTD_decompress(checkBuf, checkBufSize, dstBuf, cResult);
2388*3117ece4Schristos             CHECK(ZSTD_isError(dResult), "EMF: Decompression error: %s", ZSTD_getErrorName(dResult));
2389*3117ece4Schristos             CHECK(dResult != CNBufferSize, "EMF: Corruption!");
2390*3117ece4Schristos             CHECK(memcmp(CNBuffer, checkBuf, CNBufferSize) != 0, "EMF: Corruption!");
2391*3117ece4Schristos         }
2392*3117ece4Schristos 
2393*3117ece4Schristos         // Check that compression with external sequence producer fails when expected
2394*3117ece4Schristos         seqProdState = EMF_BIG_ERROR;
2395*3117ece4Schristos         {
2396*3117ece4Schristos             size_t const cResult = ZSTD_compress2(staticCCtx, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
2397*3117ece4Schristos             CHECK(!ZSTD_isError(cResult), "EMF: Should have raised an error!");
2398*3117ece4Schristos             CHECK(
2399*3117ece4Schristos                 ZSTD_getErrorCode(cResult) != ZSTD_error_sequenceProducer_failed,
2400*3117ece4Schristos                 "EMF: Wrong error code: %s", ZSTD_getErrorName(cResult)
2401*3117ece4Schristos             );
2402*3117ece4Schristos         }
2403*3117ece4Schristos 
2404*3117ece4Schristos         free(dstBuf);
2405*3117ece4Schristos         free(checkBuf);
2406*3117ece4Schristos         free(cctxBuf);
2407*3117ece4Schristos         ZSTD_freeCCtxParams(params);
2408*3117ece4Schristos     }
2409*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2410*3117ece4Schristos 
2411*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Decoder should reject invalid frame header on legacy frames: ", testNb++);
2412*3117ece4Schristos     {
2413*3117ece4Schristos         const unsigned char compressed[] = { 0x26,0xb5,0x2f,0xfd,0x50,0x91,0xfd,0xd8,0xb5 };
2414*3117ece4Schristos         const size_t compressedSize = 9;
2415*3117ece4Schristos         size_t const dSize = ZSTD_decompress(NULL, 0, compressed, compressedSize);
2416*3117ece4Schristos         CHECK(!ZSTD_isError(dSize), "must reject when legacy frame header is invalid");
2417*3117ece4Schristos     }
2418*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2419*3117ece4Schristos 
2420*3117ece4Schristos     DISPLAYLEVEL(3, "test%3i : Test single-shot fallback for magicless mode: ", testNb++);
2421*3117ece4Schristos     {
2422*3117ece4Schristos         // Aquire resources
2423*3117ece4Schristos         size_t const srcSize = COMPRESSIBLE_NOISE_LENGTH;
2424*3117ece4Schristos         void* src = malloc(srcSize);
2425*3117ece4Schristos         size_t const dstSize = ZSTD_compressBound(srcSize);
2426*3117ece4Schristos         void* dst = malloc(dstSize);
2427*3117ece4Schristos         size_t const valSize = srcSize;
2428*3117ece4Schristos         void* val = malloc(valSize);
2429*3117ece4Schristos         ZSTD_inBuffer inBuf = { dst, dstSize, 0 };
2430*3117ece4Schristos         ZSTD_outBuffer outBuf = { val, valSize, 0 };
2431*3117ece4Schristos         ZSTD_CCtx* cctx = ZSTD_createCCtx();
2432*3117ece4Schristos         ZSTD_DCtx* dctx = ZSTD_createDCtx();
2433*3117ece4Schristos         CHECK(!src || !dst || !val || !dctx || !cctx, "memory allocation failure");
2434*3117ece4Schristos 
2435*3117ece4Schristos         // Write test data for decompression to dst
2436*3117ece4Schristos         RDG_genBuffer(src, srcSize, compressibility, 0.0, 0xdeadbeef);
2437*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_format, ZSTD_f_zstd1_magicless));
2438*3117ece4Schristos         CHECK_Z(ZSTD_compress2(cctx, dst, dstSize, src, srcSize));
2439*3117ece4Schristos 
2440*3117ece4Schristos         // Run decompression
2441*3117ece4Schristos         CHECK_Z(ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless));
2442*3117ece4Schristos         CHECK_Z(ZSTD_decompressStream(dctx, &outBuf, &inBuf));
2443*3117ece4Schristos 
2444*3117ece4Schristos         // Validate
2445*3117ece4Schristos         CHECK(outBuf.pos != srcSize, "decompressed size must match");
2446*3117ece4Schristos         CHECK(memcmp(src, val, srcSize) != 0, "decompressed data must match");
2447*3117ece4Schristos 
2448*3117ece4Schristos         // Cleanup
2449*3117ece4Schristos         free(src); free(dst); free(val);
2450*3117ece4Schristos         ZSTD_freeCCtx(cctx);
2451*3117ece4Schristos         ZSTD_freeDCtx(dctx);
2452*3117ece4Schristos     }
2453*3117ece4Schristos     DISPLAYLEVEL(3, "OK \n");
2454*3117ece4Schristos 
2455*3117ece4Schristos _end:
2456*3117ece4Schristos     FUZ_freeDictionary(dictionary);
2457*3117ece4Schristos     ZSTD_freeCStream(zc);
2458*3117ece4Schristos     ZSTD_freeDStream(zd);
2459*3117ece4Schristos     ZSTD_freeCCtx(mtctx);
2460*3117ece4Schristos     free(CNBuffer);
2461*3117ece4Schristos     free(compressedBuffer);
2462*3117ece4Schristos     free(decodedBuffer);
2463*3117ece4Schristos     return testResult;
2464*3117ece4Schristos 
2465*3117ece4Schristos _output_error:
2466*3117ece4Schristos     testResult = 1;
2467*3117ece4Schristos     DISPLAY("Error detected in Unit tests ! \n");
2468*3117ece4Schristos     goto _end;
2469*3117ece4Schristos }
2470*3117ece4Schristos 
2471*3117ece4Schristos 
2472*3117ece4Schristos /* ======   Fuzzer tests   ====== */
2473*3117ece4Schristos 
2474*3117ece4Schristos static size_t findDiff(const void* buf1, const void* buf2, size_t max)
2475*3117ece4Schristos {
2476*3117ece4Schristos     const BYTE* b1 = (const BYTE*)buf1;
2477*3117ece4Schristos     const BYTE* b2 = (const BYTE*)buf2;
2478*3117ece4Schristos     size_t u;
2479*3117ece4Schristos     for (u=0; u<max; u++) {
2480*3117ece4Schristos         if (b1[u] != b2[u]) break;
2481*3117ece4Schristos     }
2482*3117ece4Schristos     if (u==max) {
2483*3117ece4Schristos         DISPLAY("=> No difference detected within %u bytes \n", (unsigned)max);
2484*3117ece4Schristos         return u;
2485*3117ece4Schristos     }
2486*3117ece4Schristos     DISPLAY("Error at position %u / %u \n", (unsigned)u, (unsigned)max);
2487*3117ece4Schristos     if (u>=3)
2488*3117ece4Schristos         DISPLAY(" %02X %02X %02X ",
2489*3117ece4Schristos                 b1[u-3], b1[u-2], b1[u-1]);
2490*3117ece4Schristos     DISPLAY(" :%02X:  %02X %02X %02X %02X %02X \n",
2491*3117ece4Schristos             b1[u], b1[u+1], b1[u+2], b1[u+3], b1[u+4], b1[u+5]);
2492*3117ece4Schristos     if (u>=3)
2493*3117ece4Schristos         DISPLAY(" %02X %02X %02X ",
2494*3117ece4Schristos                 b2[u-3], b2[u-2], b2[u-1]);
2495*3117ece4Schristos     DISPLAY(" :%02X:  %02X %02X %02X %02X %02X \n",
2496*3117ece4Schristos             b2[u], b2[u+1], b2[u+2], b2[u+3], b2[u+4], b2[u+5]);
2497*3117ece4Schristos     return u;
2498*3117ece4Schristos }
2499*3117ece4Schristos 
2500*3117ece4Schristos static size_t FUZ_rLogLength(U32* seed, U32 logLength)
2501*3117ece4Schristos {
2502*3117ece4Schristos     size_t const lengthMask = ((size_t)1 << logLength) - 1;
2503*3117ece4Schristos     return (lengthMask+1) + (FUZ_rand(seed) & lengthMask);
2504*3117ece4Schristos }
2505*3117ece4Schristos 
2506*3117ece4Schristos static size_t FUZ_randomLength(U32* seed, U32 maxLog)
2507*3117ece4Schristos {
2508*3117ece4Schristos     U32 const logLength = FUZ_rand(seed) % maxLog;
2509*3117ece4Schristos     return FUZ_rLogLength(seed, logLength);
2510*3117ece4Schristos }
2511*3117ece4Schristos 
2512*3117ece4Schristos /* Return value in range minVal <= v <= maxVal */
2513*3117ece4Schristos static U32 FUZ_randomClampedLength(U32* seed, U32 minVal, U32 maxVal)
2514*3117ece4Schristos {
2515*3117ece4Schristos     U32 const mod = maxVal < minVal ? 1 : (maxVal + 1) - minVal;
2516*3117ece4Schristos     return (U32)((FUZ_rand(seed) % mod) + minVal);
2517*3117ece4Schristos }
2518*3117ece4Schristos 
2519*3117ece4Schristos static int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, int bigTests)
2520*3117ece4Schristos {
2521*3117ece4Schristos     U32 const maxSrcLog = bigTests ? 24 : 22;
2522*3117ece4Schristos     static const U32 maxSampleLog = 19;
2523*3117ece4Schristos     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
2524*3117ece4Schristos     BYTE* cNoiseBuffer[5];
2525*3117ece4Schristos     size_t const copyBufferSize = srcBufferSize + (1<<maxSampleLog);
2526*3117ece4Schristos     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
2527*3117ece4Schristos     size_t const cBufferSize = ZSTD_compressBound(srcBufferSize);
2528*3117ece4Schristos     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
2529*3117ece4Schristos     size_t const dstBufferSize = srcBufferSize;
2530*3117ece4Schristos     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
2531*3117ece4Schristos     U32 result = 0;
2532*3117ece4Schristos     unsigned testNb = 0;
2533*3117ece4Schristos     U32 coreSeed = seed;
2534*3117ece4Schristos     ZSTD_CStream* zc = ZSTD_createCStream();   /* will be re-created sometimes */
2535*3117ece4Schristos     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be re-created sometimes */
2536*3117ece4Schristos     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
2537*3117ece4Schristos     UTIL_time_t const startClock = UTIL_getTime();
2538*3117ece4Schristos     const BYTE* dict = NULL;  /* can keep same dict on 2 consecutive tests */
2539*3117ece4Schristos     size_t dictSize = 0;
2540*3117ece4Schristos     U32 oldTestLog = 0;
2541*3117ece4Schristos     U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel() : g_cLevelMax_smallTests;
2542*3117ece4Schristos 
2543*3117ece4Schristos     /* allocations */
2544*3117ece4Schristos     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
2545*3117ece4Schristos     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
2546*3117ece4Schristos     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
2547*3117ece4Schristos     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
2548*3117ece4Schristos     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
2549*3117ece4Schristos     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
2550*3117ece4Schristos            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
2551*3117ece4Schristos            "Not enough memory, fuzzer tests cancelled");
2552*3117ece4Schristos 
2553*3117ece4Schristos     /* Create initial samples */
2554*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
2555*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
2556*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
2557*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
2558*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
2559*3117ece4Schristos     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
2560*3117ece4Schristos     ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
2561*3117ece4Schristos 
2562*3117ece4Schristos     /* catch up testNb */
2563*3117ece4Schristos     for (testNb=1; testNb < startTest; testNb++)
2564*3117ece4Schristos         FUZ_rand(&coreSeed);
2565*3117ece4Schristos 
2566*3117ece4Schristos     /* test loop */
2567*3117ece4Schristos     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
2568*3117ece4Schristos         U32 lseed;
2569*3117ece4Schristos         const BYTE* srcBuffer;
2570*3117ece4Schristos         size_t totalTestSize, totalGenSize, cSize;
2571*3117ece4Schristos         XXH64_state_t xxhState;
2572*3117ece4Schristos         U64 crcOrig;
2573*3117ece4Schristos         U32 resetAllowed = 1;
2574*3117ece4Schristos         size_t maxTestSize;
2575*3117ece4Schristos 
2576*3117ece4Schristos         /* init */
2577*3117ece4Schristos         FUZ_rand(&coreSeed);
2578*3117ece4Schristos         lseed = coreSeed ^ prime32;
2579*3117ece4Schristos         if (nbTests >= testNb) {
2580*3117ece4Schristos             DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests);
2581*3117ece4Schristos         } else {
2582*3117ece4Schristos             DISPLAYUPDATE(2, "\r%6u        ", testNb);
2583*3117ece4Schristos         }
2584*3117ece4Schristos 
2585*3117ece4Schristos         /* states full reset (deliberately not synchronized) */
2586*3117ece4Schristos         /* some issues can only happen when reusing states */
2587*3117ece4Schristos         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
2588*3117ece4Schristos             ZSTD_freeCStream(zc);
2589*3117ece4Schristos             zc = ZSTD_createCStream();
2590*3117ece4Schristos             CHECK(zc==NULL, "ZSTD_createCStream : allocation error");
2591*3117ece4Schristos             resetAllowed=0;
2592*3117ece4Schristos         }
2593*3117ece4Schristos         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
2594*3117ece4Schristos             ZSTD_freeDStream(zd);
2595*3117ece4Schristos             zd = ZSTD_createDStream();
2596*3117ece4Schristos             CHECK(zd==NULL, "ZSTD_createDStream : allocation error");
2597*3117ece4Schristos             CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) );  /* ensure at least one init */
2598*3117ece4Schristos         }
2599*3117ece4Schristos 
2600*3117ece4Schristos         /* srcBuffer selection [0-4] */
2601*3117ece4Schristos         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
2602*3117ece4Schristos             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
2603*3117ece4Schristos             else {
2604*3117ece4Schristos                 buffNb >>= 3;
2605*3117ece4Schristos                 if (buffNb & 7) {
2606*3117ece4Schristos                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
2607*3117ece4Schristos                     buffNb = tnb[buffNb >> 3];
2608*3117ece4Schristos                 } else {
2609*3117ece4Schristos                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
2610*3117ece4Schristos                     buffNb = tnb[buffNb >> 3];
2611*3117ece4Schristos             }   }
2612*3117ece4Schristos             srcBuffer = cNoiseBuffer[buffNb];
2613*3117ece4Schristos         }
2614*3117ece4Schristos 
2615*3117ece4Schristos         /* compression init */
2616*3117ece4Schristos         if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
2617*3117ece4Schristos             && oldTestLog /* at least one test happened */ && resetAllowed) {
2618*3117ece4Schristos             maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
2619*3117ece4Schristos             maxTestSize = MIN(maxTestSize, srcBufferSize-16);
2620*3117ece4Schristos             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2621*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
2622*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2623*3117ece4Schristos             }
2624*3117ece4Schristos         } else {
2625*3117ece4Schristos             U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
2626*3117ece4Schristos             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
2627*3117ece4Schristos             U32 const cLevelCandidate = ( FUZ_rand(&lseed) %
2628*3117ece4Schristos                                 (ZSTD_maxCLevel() -
2629*3117ece4Schristos                                 (MAX(testLog, dictLog) / 3)))
2630*3117ece4Schristos                                  + 1;
2631*3117ece4Schristos             U32 const cLevel = MIN(cLevelCandidate, cLevelMax);
2632*3117ece4Schristos             maxTestSize = FUZ_rLogLength(&lseed, testLog);
2633*3117ece4Schristos             oldTestLog = testLog;
2634*3117ece4Schristos             /* random dictionary selection */
2635*3117ece4Schristos             dictSize  = ((FUZ_rand(&lseed)&7)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
2636*3117ece4Schristos             {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2637*3117ece4Schristos                 dict = srcBuffer + dictStart;
2638*3117ece4Schristos             }
2639*3117ece4Schristos             {   U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2640*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_reset(zc, ZSTD_reset_session_only) );
2641*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_compressionLevel, cLevel) );
2642*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_checksumFlag, FUZ_rand(&lseed) & 1) );
2643*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_contentSizeFlag, FUZ_rand(&lseed) & 1) );
2644*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setParameter(zc, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1) );
2645*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2646*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
2647*3117ece4Schristos         }   }
2648*3117ece4Schristos 
2649*3117ece4Schristos         /* multi-segments compression test */
2650*3117ece4Schristos         XXH64_reset(&xxhState, 0);
2651*3117ece4Schristos         {   ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
2652*3117ece4Schristos             cSize=0;
2653*3117ece4Schristos             totalTestSize=0;
2654*3117ece4Schristos             while(totalTestSize < maxTestSize) {
2655*3117ece4Schristos                 /* compress random chunks into randomly sized dst buffers */
2656*3117ece4Schristos                 {   size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2657*3117ece4Schristos                     size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
2658*3117ece4Schristos                     size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
2659*3117ece4Schristos                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2660*3117ece4Schristos                     size_t const dstBuffSize = MIN(cBufferSize - cSize, randomDstSize);
2661*3117ece4Schristos                     ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
2662*3117ece4Schristos                     outBuff.size = outBuff.pos + dstBuffSize;
2663*3117ece4Schristos 
2664*3117ece4Schristos                     CHECK_Z( ZSTD_compressStream(zc, &outBuff, &inBuff) );
2665*3117ece4Schristos 
2666*3117ece4Schristos                     XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
2667*3117ece4Schristos                     memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
2668*3117ece4Schristos                     totalTestSize += inBuff.pos;
2669*3117ece4Schristos                 }
2670*3117ece4Schristos 
2671*3117ece4Schristos                 /* random flush operation, to mess around */
2672*3117ece4Schristos                 if ((FUZ_rand(&lseed) & 15) == 0) {
2673*3117ece4Schristos                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2674*3117ece4Schristos                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
2675*3117ece4Schristos                     outBuff.size = outBuff.pos + adjustedDstSize;
2676*3117ece4Schristos                     CHECK_Z( ZSTD_flushStream(zc, &outBuff) );
2677*3117ece4Schristos             }   }
2678*3117ece4Schristos 
2679*3117ece4Schristos             /* final frame epilogue */
2680*3117ece4Schristos             {   size_t remainingToFlush = (size_t)(-1);
2681*3117ece4Schristos                 while (remainingToFlush) {
2682*3117ece4Schristos                     size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2683*3117ece4Schristos                     size_t const adjustedDstSize = MIN(cBufferSize - cSize, randomDstSize);
2684*3117ece4Schristos                     outBuff.size = outBuff.pos + adjustedDstSize;
2685*3117ece4Schristos                     remainingToFlush = ZSTD_endStream(zc, &outBuff);
2686*3117ece4Schristos                     CHECK (ZSTD_isError(remainingToFlush), "end error : %s", ZSTD_getErrorName(remainingToFlush));
2687*3117ece4Schristos             }   }
2688*3117ece4Schristos             crcOrig = XXH64_digest(&xxhState);
2689*3117ece4Schristos             cSize = outBuff.pos;
2690*3117ece4Schristos         }
2691*3117ece4Schristos 
2692*3117ece4Schristos         /* multi - fragments decompression test */
2693*3117ece4Schristos         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
2694*3117ece4Schristos             CHECK_Z ( ZSTD_resetDStream(zd) );
2695*3117ece4Schristos         } else {
2696*3117ece4Schristos             CHECK_Z ( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
2697*3117ece4Schristos         }
2698*3117ece4Schristos         {   size_t decompressionResult = 1;
2699*3117ece4Schristos             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
2700*3117ece4Schristos             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2701*3117ece4Schristos             for (totalGenSize = 0 ; decompressionResult ; ) {
2702*3117ece4Schristos                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2703*3117ece4Schristos                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2704*3117ece4Schristos                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
2705*3117ece4Schristos                 inBuff.size = inBuff.pos + readCSrcSize;
2706*3117ece4Schristos                 outBuff.size = outBuff.pos + dstBuffSize;
2707*3117ece4Schristos                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
2708*3117ece4Schristos                 if (ZSTD_getErrorCode(decompressionResult) == ZSTD_error_checksum_wrong) {
2709*3117ece4Schristos                     DISPLAY("checksum error : \n");
2710*3117ece4Schristos                     findDiff(copyBuffer, dstBuffer, totalTestSize);
2711*3117ece4Schristos                 }
2712*3117ece4Schristos                 CHECK( ZSTD_isError(decompressionResult), "decompression error : %s",
2713*3117ece4Schristos                        ZSTD_getErrorName(decompressionResult) );
2714*3117ece4Schristos             }
2715*3117ece4Schristos             CHECK (decompressionResult != 0, "frame not fully decoded");
2716*3117ece4Schristos             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)",
2717*3117ece4Schristos                     (unsigned)outBuff.pos, (unsigned)totalTestSize);
2718*3117ece4Schristos             CHECK (inBuff.pos != cSize, "compressed data should be fully read")
2719*3117ece4Schristos             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
2720*3117ece4Schristos                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
2721*3117ece4Schristos                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
2722*3117ece4Schristos         }   }
2723*3117ece4Schristos 
2724*3117ece4Schristos         /*=====   noisy/erroneous src decompression test   =====*/
2725*3117ece4Schristos 
2726*3117ece4Schristos         /* add some noise */
2727*3117ece4Schristos         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
2728*3117ece4Schristos             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
2729*3117ece4Schristos                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
2730*3117ece4Schristos                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
2731*3117ece4Schristos                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
2732*3117ece4Schristos                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
2733*3117ece4Schristos                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
2734*3117ece4Schristos         }   }
2735*3117ece4Schristos 
2736*3117ece4Schristos         /* try decompression on noisy data */
2737*3117ece4Schristos         CHECK_Z( ZSTD_initDStream(zd_noise) );   /* note : no dictionary */
2738*3117ece4Schristos         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
2739*3117ece4Schristos             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
2740*3117ece4Schristos             while (outBuff.pos < dstBufferSize) {
2741*3117ece4Schristos                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
2742*3117ece4Schristos                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
2743*3117ece4Schristos                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
2744*3117ece4Schristos                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
2745*3117ece4Schristos                 outBuff.size = outBuff.pos + adjustedDstSize;
2746*3117ece4Schristos                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
2747*3117ece4Schristos                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
2748*3117ece4Schristos                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
2749*3117ece4Schristos                     /* No forward progress possible */
2750*3117ece4Schristos                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
2751*3117ece4Schristos     }   }   }   }
2752*3117ece4Schristos     DISPLAY("\r%u fuzzer tests completed   \n", testNb);
2753*3117ece4Schristos 
2754*3117ece4Schristos _cleanup:
2755*3117ece4Schristos     ZSTD_freeCStream(zc);
2756*3117ece4Schristos     ZSTD_freeDStream(zd);
2757*3117ece4Schristos     ZSTD_freeDStream(zd_noise);
2758*3117ece4Schristos     free(cNoiseBuffer[0]);
2759*3117ece4Schristos     free(cNoiseBuffer[1]);
2760*3117ece4Schristos     free(cNoiseBuffer[2]);
2761*3117ece4Schristos     free(cNoiseBuffer[3]);
2762*3117ece4Schristos     free(cNoiseBuffer[4]);
2763*3117ece4Schristos     free(copyBuffer);
2764*3117ece4Schristos     free(cBuffer);
2765*3117ece4Schristos     free(dstBuffer);
2766*3117ece4Schristos     return result;
2767*3117ece4Schristos 
2768*3117ece4Schristos _output_error:
2769*3117ece4Schristos     result = 1;
2770*3117ece4Schristos     goto _cleanup;
2771*3117ece4Schristos }
2772*3117ece4Schristos 
2773*3117ece4Schristos /** If useOpaqueAPI, sets param in cctxParams.
2774*3117ece4Schristos  *  Otherwise, sets the param in zc. */
2775*3117ece4Schristos static size_t setCCtxParameter(ZSTD_CCtx* zc, ZSTD_CCtx_params* cctxParams,
2776*3117ece4Schristos                                ZSTD_cParameter param, unsigned value,
2777*3117ece4Schristos                                int useOpaqueAPI)
2778*3117ece4Schristos {
2779*3117ece4Schristos     if (useOpaqueAPI) {
2780*3117ece4Schristos         return ZSTD_CCtxParams_setParameter(cctxParams, param, value);
2781*3117ece4Schristos     } else {
2782*3117ece4Schristos         return ZSTD_CCtx_setParameter(zc, param, value);
2783*3117ece4Schristos     }
2784*3117ece4Schristos }
2785*3117ece4Schristos 
2786*3117ece4Schristos /* Tests for ZSTD_compress_generic() API */
2787*3117ece4Schristos static int fuzzerTests_newAPI(U32 seed, int nbTests, int startTest,
2788*3117ece4Schristos                               double compressibility, int bigTests)
2789*3117ece4Schristos {
2790*3117ece4Schristos     U32 const maxSrcLog = bigTests ? 24 : 22;
2791*3117ece4Schristos     static const U32 maxSampleLog = 19;
2792*3117ece4Schristos     size_t const srcBufferSize = (size_t)1<<maxSrcLog;
2793*3117ece4Schristos     BYTE* cNoiseBuffer[5];
2794*3117ece4Schristos     size_t const copyBufferSize= srcBufferSize + (1<<maxSampleLog);
2795*3117ece4Schristos     BYTE*  const copyBuffer = (BYTE*)malloc (copyBufferSize);
2796*3117ece4Schristos     size_t const cBufferSize   = ZSTD_compressBound(srcBufferSize);
2797*3117ece4Schristos     BYTE*  const cBuffer = (BYTE*)malloc (cBufferSize);
2798*3117ece4Schristos     size_t const dstBufferSize = srcBufferSize;
2799*3117ece4Schristos     BYTE*  const dstBuffer = (BYTE*)malloc (dstBufferSize);
2800*3117ece4Schristos     U32 result = 0;
2801*3117ece4Schristos     int testNb = 0;
2802*3117ece4Schristos     U32 coreSeed = seed;
2803*3117ece4Schristos     ZSTD_CCtx* zc = ZSTD_createCCtx();   /* will be reset sometimes */
2804*3117ece4Schristos     ZSTD_DStream* zd = ZSTD_createDStream();   /* will be reset sometimes */
2805*3117ece4Schristos     ZSTD_DStream* const zd_noise = ZSTD_createDStream();
2806*3117ece4Schristos     UTIL_time_t const startClock = UTIL_getTime();
2807*3117ece4Schristos     const BYTE* dict = NULL;   /* can keep same dict on 2 consecutive tests */
2808*3117ece4Schristos     size_t dictSize = 0;
2809*3117ece4Schristos     U32 oldTestLog = 0;
2810*3117ece4Schristos     U32 windowLogMalus = 0;   /* can survive between 2 loops */
2811*3117ece4Schristos     U32 const cLevelMax = bigTests ? (U32)ZSTD_maxCLevel()-1 : g_cLevelMax_smallTests;
2812*3117ece4Schristos     U32 const nbThreadsMax = bigTests ? 4 : 2;
2813*3117ece4Schristos     ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();
2814*3117ece4Schristos 
2815*3117ece4Schristos     /* allocations */
2816*3117ece4Schristos     cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize);
2817*3117ece4Schristos     cNoiseBuffer[1] = (BYTE*)malloc (srcBufferSize);
2818*3117ece4Schristos     cNoiseBuffer[2] = (BYTE*)malloc (srcBufferSize);
2819*3117ece4Schristos     cNoiseBuffer[3] = (BYTE*)malloc (srcBufferSize);
2820*3117ece4Schristos     cNoiseBuffer[4] = (BYTE*)malloc (srcBufferSize);
2821*3117ece4Schristos     CHECK (!cNoiseBuffer[0] || !cNoiseBuffer[1] || !cNoiseBuffer[2] || !cNoiseBuffer[3] || !cNoiseBuffer[4] ||
2822*3117ece4Schristos            !copyBuffer || !dstBuffer || !cBuffer || !zc || !zd || !zd_noise ,
2823*3117ece4Schristos            "Not enough memory, fuzzer tests cancelled");
2824*3117ece4Schristos 
2825*3117ece4Schristos     /* Create initial samples */
2826*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[0], srcBufferSize, 0.00, 0., coreSeed);    /* pure noise */
2827*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[1], srcBufferSize, 0.05, 0., coreSeed);    /* barely compressible */
2828*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[2], srcBufferSize, compressibility, 0., coreSeed);
2829*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[3], srcBufferSize, 0.95, 0., coreSeed);    /* highly compressible */
2830*3117ece4Schristos     RDG_genBuffer(cNoiseBuffer[4], srcBufferSize, 1.00, 0., coreSeed);    /* sparse content */
2831*3117ece4Schristos     memset(copyBuffer, 0x65, copyBufferSize);                             /* make copyBuffer considered initialized */
2832*3117ece4Schristos     CHECK_Z( ZSTD_initDStream_usingDict(zd, NULL, 0) );   /* ensure at least one init */
2833*3117ece4Schristos 
2834*3117ece4Schristos     /* catch up testNb */
2835*3117ece4Schristos     for (testNb=1; testNb < startTest; testNb++)
2836*3117ece4Schristos         FUZ_rand(&coreSeed);
2837*3117ece4Schristos 
2838*3117ece4Schristos     /* test loop */
2839*3117ece4Schristos     for ( ; (testNb <= nbTests) || (UTIL_clockSpanMicro(startClock) < g_clockTime) ; testNb++ ) {
2840*3117ece4Schristos         U32 lseed;
2841*3117ece4Schristos         int opaqueAPI;
2842*3117ece4Schristos         const BYTE* srcBuffer;
2843*3117ece4Schristos         size_t totalTestSize, totalGenSize, cSize;
2844*3117ece4Schristos         XXH64_state_t xxhState;
2845*3117ece4Schristos         U64 crcOrig;
2846*3117ece4Schristos         U32 resetAllowed = 1;
2847*3117ece4Schristos         size_t maxTestSize;
2848*3117ece4Schristos         ZSTD_parameters savedParams;
2849*3117ece4Schristos         int isRefPrefix = 0;
2850*3117ece4Schristos         U64 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
2851*3117ece4Schristos 
2852*3117ece4Schristos         /* init */
2853*3117ece4Schristos         if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u    ", testNb, nbTests); }
2854*3117ece4Schristos         else { DISPLAYUPDATE(2, "\r%6u          ", testNb); }
2855*3117ece4Schristos         FUZ_rand(&coreSeed);
2856*3117ece4Schristos         lseed = coreSeed ^ prime32;
2857*3117ece4Schristos         DISPLAYLEVEL(5, " ***  Test %u  *** \n", testNb);
2858*3117ece4Schristos         opaqueAPI = FUZ_rand(&lseed) & 1;
2859*3117ece4Schristos 
2860*3117ece4Schristos         /* states full reset (deliberately not synchronized) */
2861*3117ece4Schristos         /* some issues can only happen when reusing states */
2862*3117ece4Schristos         if ((FUZ_rand(&lseed) & 0xFF) == 131) {
2863*3117ece4Schristos             DISPLAYLEVEL(5, "Creating new context \n");
2864*3117ece4Schristos             ZSTD_freeCCtx(zc);
2865*3117ece4Schristos             zc = ZSTD_createCCtx();
2866*3117ece4Schristos             CHECK(zc == NULL, "ZSTD_createCCtx allocation error");
2867*3117ece4Schristos             resetAllowed = 0;
2868*3117ece4Schristos         }
2869*3117ece4Schristos         if ((FUZ_rand(&lseed) & 0xFF) == 132) {
2870*3117ece4Schristos             ZSTD_freeDStream(zd);
2871*3117ece4Schristos             zd = ZSTD_createDStream();
2872*3117ece4Schristos             CHECK(zd == NULL, "ZSTD_createDStream allocation error");
2873*3117ece4Schristos             ZSTD_initDStream_usingDict(zd, NULL, 0);  /* ensure at least one init */
2874*3117ece4Schristos         }
2875*3117ece4Schristos 
2876*3117ece4Schristos         /* srcBuffer selection [0-4] */
2877*3117ece4Schristos         {   U32 buffNb = FUZ_rand(&lseed) & 0x7F;
2878*3117ece4Schristos             if (buffNb & 7) buffNb=2;   /* most common : compressible (P) */
2879*3117ece4Schristos             else {
2880*3117ece4Schristos                 buffNb >>= 3;
2881*3117ece4Schristos                 if (buffNb & 7) {
2882*3117ece4Schristos                     const U32 tnb[2] = { 1, 3 };   /* barely/highly compressible */
2883*3117ece4Schristos                     buffNb = tnb[buffNb >> 3];
2884*3117ece4Schristos                 } else {
2885*3117ece4Schristos                     const U32 tnb[2] = { 0, 4 };   /* not compressible / sparse */
2886*3117ece4Schristos                     buffNb = tnb[buffNb >> 3];
2887*3117ece4Schristos             }   }
2888*3117ece4Schristos             srcBuffer = cNoiseBuffer[buffNb];
2889*3117ece4Schristos         }
2890*3117ece4Schristos 
2891*3117ece4Schristos         /* compression init */
2892*3117ece4Schristos         CHECK_Z( ZSTD_CCtx_loadDictionary(zc, NULL, 0) );   /* cancel previous dict /*/
2893*3117ece4Schristos         if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */
2894*3117ece4Schristos           && oldTestLog   /* at least one test happened */
2895*3117ece4Schristos           && resetAllowed) {
2896*3117ece4Schristos             /* just set a compression level */
2897*3117ece4Schristos             maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2);
2898*3117ece4Schristos             if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1;
2899*3117ece4Schristos             {   int const compressionLevel = (FUZ_rand(&lseed) % 5) + 1;
2900*3117ece4Schristos                 DISPLAYLEVEL(5, "t%u : compression level : %i \n", testNb, compressionLevel);
2901*3117ece4Schristos                 CHECK_Z (setCCtxParameter(zc, cctxParams, ZSTD_c_compressionLevel, compressionLevel, opaqueAPI) );
2902*3117ece4Schristos             }
2903*3117ece4Schristos         } else {
2904*3117ece4Schristos             U32 const testLog = FUZ_rand(&lseed) % maxSrcLog;
2905*3117ece4Schristos             U32 const dictLog = FUZ_rand(&lseed) % maxSrcLog;
2906*3117ece4Schristos             U32 const cLevelCandidate = (FUZ_rand(&lseed) %
2907*3117ece4Schristos                                (ZSTD_maxCLevel() -
2908*3117ece4Schristos                                (MAX(testLog, dictLog) / 2))) +
2909*3117ece4Schristos                                1;
2910*3117ece4Schristos             int const cLevel = MIN(cLevelCandidate, cLevelMax);
2911*3117ece4Schristos             DISPLAYLEVEL(5, "t%i: base cLevel : %u \n", testNb, cLevel);
2912*3117ece4Schristos             maxTestSize = FUZ_rLogLength(&lseed, testLog);
2913*3117ece4Schristos             DISPLAYLEVEL(5, "t%i: maxTestSize : %u \n", testNb, (unsigned)maxTestSize);
2914*3117ece4Schristos             oldTestLog = testLog;
2915*3117ece4Schristos             /* random dictionary selection */
2916*3117ece4Schristos             dictSize  = ((FUZ_rand(&lseed)&63)==1) ? FUZ_rLogLength(&lseed, dictLog) : 0;
2917*3117ece4Schristos             {   size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize);
2918*3117ece4Schristos                 dict = srcBuffer + dictStart;
2919*3117ece4Schristos                 if (!dictSize) dict=NULL;
2920*3117ece4Schristos             }
2921*3117ece4Schristos             pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? ZSTD_CONTENTSIZE_UNKNOWN : maxTestSize;
2922*3117ece4Schristos             {   ZSTD_compressionParameters cParams = ZSTD_getCParams(cLevel, pledgedSrcSize, dictSize);
2923*3117ece4Schristos                 const U32 windowLogMax = bigTests ? 24 : 20;
2924*3117ece4Schristos                 const U32 searchLogMax = bigTests ? 15 : 13;
2925*3117ece4Schristos                 if (dictSize)
2926*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: with dictionary of size : %zu \n", testNb, dictSize);
2927*3117ece4Schristos 
2928*3117ece4Schristos                 /* mess with compression parameters */
2929*3117ece4Schristos                 cParams.windowLog += (FUZ_rand(&lseed) & 3) - 1;
2930*3117ece4Schristos                 cParams.windowLog = MIN(windowLogMax, cParams.windowLog);
2931*3117ece4Schristos                 cParams.hashLog += (FUZ_rand(&lseed) & 3) - 1;
2932*3117ece4Schristos                 cParams.chainLog += (FUZ_rand(&lseed) & 3) - 1;
2933*3117ece4Schristos                 cParams.searchLog += (FUZ_rand(&lseed) & 3) - 1;
2934*3117ece4Schristos                 cParams.searchLog = MIN(searchLogMax, cParams.searchLog);
2935*3117ece4Schristos                 cParams.minMatch += (FUZ_rand(&lseed) & 3) - 1;
2936*3117ece4Schristos                 cParams.targetLength = (U32)((cParams.targetLength + 1 ) * (0.5 + ((double)(FUZ_rand(&lseed) & 127) / 128)));
2937*3117ece4Schristos                 cParams = ZSTD_adjustCParams(cParams, pledgedSrcSize, dictSize);
2938*3117ece4Schristos 
2939*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
2940*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: windowLog : %u \n", testNb, cParams.windowLog);
2941*3117ece4Schristos                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_windowLog, cParams.windowLog, opaqueAPI) );
2942*3117ece4Schristos                     assert(cParams.windowLog >= ZSTD_WINDOWLOG_MIN);   /* guaranteed by ZSTD_adjustCParams() */
2943*3117ece4Schristos                     windowLogMalus = (cParams.windowLog - ZSTD_WINDOWLOG_MIN) / 5;
2944*3117ece4Schristos                 }
2945*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
2946*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: hashLog : %u \n", testNb, cParams.hashLog);
2947*3117ece4Schristos                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_hashLog, cParams.hashLog, opaqueAPI) );
2948*3117ece4Schristos                 }
2949*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
2950*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: chainLog : %u \n", testNb, cParams.chainLog);
2951*3117ece4Schristos                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_chainLog, cParams.chainLog, opaqueAPI) );
2952*3117ece4Schristos                 }
2953*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_searchLog, cParams.searchLog, opaqueAPI) );
2954*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_minMatch, cParams.minMatch, opaqueAPI) );
2955*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_targetLength, cParams.targetLength, opaqueAPI) );
2956*3117ece4Schristos 
2957*3117ece4Schristos                 /* mess with long distance matching parameters */
2958*3117ece4Schristos                 if (bigTests) {
2959*3117ece4Schristos                     if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_enableLongDistanceMatching, FUZ_randomClampedLength(&lseed, ZSTD_ps_auto, ZSTD_ps_disable), opaqueAPI) );
2960*3117ece4Schristos                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_ldmHashLog, FUZ_randomClampedLength(&lseed, ZSTD_HASHLOG_MIN, 23), opaqueAPI) );
2961*3117ece4Schristos                     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) );
2962*3117ece4Schristos                     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) );
2963*3117ece4Schristos                     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) );
2964*3117ece4Schristos                     if (FUZ_rand(&lseed) & 3) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_srcSizeHint, FUZ_randomClampedLength(&lseed, ZSTD_SRCSIZEHINT_MIN, ZSTD_SRCSIZEHINT_MAX), opaqueAPI) );
2965*3117ece4Schristos                 }
2966*3117ece4Schristos 
2967*3117ece4Schristos                 /* mess with frame parameters */
2968*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
2969*3117ece4Schristos                     int const checksumFlag = FUZ_rand(&lseed) & 1;
2970*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: frame checksum : %u \n", testNb, checksumFlag);
2971*3117ece4Schristos                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_checksumFlag, checksumFlag, opaqueAPI) );
2972*3117ece4Schristos                 }
2973*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_dictIDFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2974*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_contentSizeFlag, FUZ_rand(&lseed) & 1, opaqueAPI) );
2975*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
2976*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: pledgedSrcSize : %u \n", testNb, (unsigned)pledgedSrcSize);
2977*3117ece4Schristos                     CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
2978*3117ece4Schristos                 } else {
2979*3117ece4Schristos                     pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
2980*3117ece4Schristos                 }
2981*3117ece4Schristos 
2982*3117ece4Schristos                 /* multi-threading parameters. Only adjust occasionally for small tests. */
2983*3117ece4Schristos                 if (bigTests || (FUZ_rand(&lseed) & 0xF) == 0xF) {
2984*3117ece4Schristos                     U32 const nbThreadsCandidate = (FUZ_rand(&lseed) & 4) + 1;
2985*3117ece4Schristos                     U32 const nbThreadsAdjusted = (windowLogMalus < nbThreadsCandidate) ? nbThreadsCandidate - windowLogMalus : 1;
2986*3117ece4Schristos                     int const nbThreads = MIN(nbThreadsAdjusted, nbThreadsMax);
2987*3117ece4Schristos                     DISPLAYLEVEL(5, "t%i: nbThreads : %u \n", testNb, nbThreads);
2988*3117ece4Schristos                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_nbWorkers, nbThreads, opaqueAPI) );
2989*3117ece4Schristos                     if (nbThreads > 1) {
2990*3117ece4Schristos                         U32 const jobLog = FUZ_rand(&lseed) % (testLog+1);
2991*3117ece4Schristos                         CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_overlapLog, FUZ_rand(&lseed) % 10, opaqueAPI) );
2992*3117ece4Schristos                         CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_jobSize, (U32)FUZ_rLogLength(&lseed, jobLog), opaqueAPI) );
2993*3117ece4Schristos                     }
2994*3117ece4Schristos                 }
2995*3117ece4Schristos                 /* Enable rsyncable mode 1 in 4 times. */
2996*3117ece4Schristos                 {
2997*3117ece4Schristos                     int const rsyncable = (FUZ_rand(&lseed) % 4 == 0);
2998*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: rsyncable : %d \n", testNb, rsyncable);
2999*3117ece4Schristos                     setCCtxParameter(zc, cctxParams, ZSTD_c_rsyncable, rsyncable, opaqueAPI);
3000*3117ece4Schristos                 }
3001*3117ece4Schristos 
3002*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_forceMaxWindow, FUZ_rand(&lseed) & 1, opaqueAPI) );
3003*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_deterministicRefPrefix, FUZ_rand(&lseed) & 1, opaqueAPI) );
3004*3117ece4Schristos 
3005*3117ece4Schristos                 /* Set max block size parameters */
3006*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
3007*3117ece4Schristos                     int maxBlockSize = (int)(FUZ_rand(&lseed) % ZSTD_BLOCKSIZE_MAX);
3008*3117ece4Schristos                     maxBlockSize = MAX(1024, maxBlockSize);
3009*3117ece4Schristos                     CHECK_Z( setCCtxParameter(zc, cctxParams, ZSTD_c_maxBlockSize, maxBlockSize, opaqueAPI) );
3010*3117ece4Schristos                 }
3011*3117ece4Schristos 
3012*3117ece4Schristos                 /* Apply parameters */
3013*3117ece4Schristos                 if (opaqueAPI) {
3014*3117ece4Schristos                     DISPLAYLEVEL(5, "t%u: applying CCtxParams \n", testNb);
3015*3117ece4Schristos                     CHECK_Z (ZSTD_CCtx_setParametersUsingCCtxParams(zc, cctxParams) );
3016*3117ece4Schristos                 }
3017*3117ece4Schristos 
3018*3117ece4Schristos                 if (FUZ_rand(&lseed) & 1) {
3019*3117ece4Schristos                     if (FUZ_rand(&lseed) & 1) {
3020*3117ece4Schristos                         CHECK_Z( ZSTD_CCtx_loadDictionary(zc, dict, dictSize) );
3021*3117ece4Schristos                     } else {
3022*3117ece4Schristos                         CHECK_Z( ZSTD_CCtx_loadDictionary_byReference(zc, dict, dictSize) );
3023*3117ece4Schristos                     }
3024*3117ece4Schristos                 } else {
3025*3117ece4Schristos                     isRefPrefix = 1;
3026*3117ece4Schristos                     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
3027*3117ece4Schristos                 }
3028*3117ece4Schristos         }   }
3029*3117ece4Schristos 
3030*3117ece4Schristos         CHECK_Z(getCCtxParams(zc, &savedParams));
3031*3117ece4Schristos 
3032*3117ece4Schristos         /* multi-segments compression test */
3033*3117ece4Schristos         {   int iter;
3034*3117ece4Schristos             int const startSeed = lseed;
3035*3117ece4Schristos             XXH64_hash_t compressedCrcs[2];
3036*3117ece4Schristos             for (iter = 0; iter < 2; ++iter, lseed = startSeed) {
3037*3117ece4Schristos                 ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ;
3038*3117ece4Schristos                 int const singlePass = (FUZ_rand(&lseed) & 3) == 0;
3039*3117ece4Schristos                 int nbWorkers;
3040*3117ece4Schristos 
3041*3117ece4Schristos                 XXH64_reset(&xxhState, 0);
3042*3117ece4Schristos 
3043*3117ece4Schristos                 CHECK_Z( ZSTD_CCtx_setPledgedSrcSize(zc, pledgedSrcSize) );
3044*3117ece4Schristos                 if (isRefPrefix) {
3045*3117ece4Schristos                     DISPLAYLEVEL(6, "t%u: Reloading prefix\n", testNb);
3046*3117ece4Schristos                     /* Need to reload the prefix because it gets dropped after one compression */
3047*3117ece4Schristos                     CHECK_Z( ZSTD_CCtx_refPrefix(zc, dict, dictSize) );
3048*3117ece4Schristos                 }
3049*3117ece4Schristos 
3050*3117ece4Schristos                 /* Adjust number of workers occasionally - result must be deterministic independent of nbWorkers */
3051*3117ece4Schristos                 CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_nbWorkers, &nbWorkers));
3052*3117ece4Schristos                 if (nbWorkers > 0 && (FUZ_rand(&lseed) & 7) == 0) {
3053*3117ece4Schristos                     DISPLAYLEVEL(6, "t%u: Modify nbWorkers: %d -> %d \n", testNb, nbWorkers, nbWorkers + iter);
3054*3117ece4Schristos                     CHECK_Z(ZSTD_CCtx_setParameter(zc, ZSTD_c_nbWorkers, nbWorkers + iter));
3055*3117ece4Schristos                 }
3056*3117ece4Schristos 
3057*3117ece4Schristos                 if (singlePass) {
3058*3117ece4Schristos                     ZSTD_inBuffer inBuff = { srcBuffer, maxTestSize, 0 };
3059*3117ece4Schristos                     CHECK_Z(ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end));
3060*3117ece4Schristos                     DISPLAYLEVEL(6, "t%u: Single pass compression: consumed %u bytes ; produced %u bytes \n",
3061*3117ece4Schristos                         testNb, (unsigned)inBuff.pos, (unsigned)outBuff.pos);
3062*3117ece4Schristos                     CHECK(inBuff.pos != inBuff.size, "Input not consumed!");
3063*3117ece4Schristos                     crcOrig = XXH64(srcBuffer, maxTestSize, 0);
3064*3117ece4Schristos                     totalTestSize = maxTestSize;
3065*3117ece4Schristos                 } else {
3066*3117ece4Schristos                     outBuff.size = 0;
3067*3117ece4Schristos                     for (totalTestSize=0 ; (totalTestSize < maxTestSize) ; ) {
3068*3117ece4Schristos                         /* compress random chunks into randomly sized dst buffers */
3069*3117ece4Schristos                         size_t const randomSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
3070*3117ece4Schristos                         size_t const srcSize = MIN(maxTestSize-totalTestSize, randomSrcSize);
3071*3117ece4Schristos                         size_t const srcStart = FUZ_rand(&lseed) % (srcBufferSize - srcSize);
3072*3117ece4Schristos                         ZSTD_EndDirective const flush = (FUZ_rand(&lseed) & 15) ? ZSTD_e_continue : ZSTD_e_flush;
3073*3117ece4Schristos                         ZSTD_inBuffer inBuff = { srcBuffer+srcStart, srcSize, 0 };
3074*3117ece4Schristos                         int forwardProgress;
3075*3117ece4Schristos                         do {
3076*3117ece4Schristos                             size_t const ipos = inBuff.pos;
3077*3117ece4Schristos                             size_t const opos = outBuff.pos;
3078*3117ece4Schristos                             size_t ret;
3079*3117ece4Schristos                             if (outBuff.pos == outBuff.size) {
3080*3117ece4Schristos                                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
3081*3117ece4Schristos                                 size_t const dstBuffSize = MIN(cBufferSize - outBuff.pos, randomDstSize);
3082*3117ece4Schristos                                 outBuff.size = outBuff.pos + dstBuffSize;
3083*3117ece4Schristos                             }
3084*3117ece4Schristos                             CHECK_Z( ret = ZSTD_compressStream2(zc, &outBuff, &inBuff, flush) );
3085*3117ece4Schristos                             DISPLAYLEVEL(6, "t%u: compress consumed %u bytes (total : %u) ; flush: %u (total : %u) \n",
3086*3117ece4Schristos                                 testNb, (unsigned)inBuff.pos, (unsigned)(totalTestSize + inBuff.pos), (unsigned)flush, (unsigned)outBuff.pos);
3087*3117ece4Schristos 
3088*3117ece4Schristos                             /* We've completed the flush */
3089*3117ece4Schristos                             if (flush == ZSTD_e_flush && ret == 0)
3090*3117ece4Schristos                                 break;
3091*3117ece4Schristos 
3092*3117ece4Schristos                             /* Ensure maximal forward progress for determinism */
3093*3117ece4Schristos                             forwardProgress = (inBuff.pos != ipos) || (outBuff.pos != opos);
3094*3117ece4Schristos                         } while (forwardProgress);
3095*3117ece4Schristos                         assert(inBuff.pos == inBuff.size);
3096*3117ece4Schristos 
3097*3117ece4Schristos                         XXH64_update(&xxhState, srcBuffer+srcStart, inBuff.pos);
3098*3117ece4Schristos                         memcpy(copyBuffer+totalTestSize, srcBuffer+srcStart, inBuff.pos);
3099*3117ece4Schristos                         totalTestSize += inBuff.pos;
3100*3117ece4Schristos                     }
3101*3117ece4Schristos 
3102*3117ece4Schristos                     /* final frame epilogue */
3103*3117ece4Schristos                     {   size_t remainingToFlush = 1;
3104*3117ece4Schristos                         while (remainingToFlush) {
3105*3117ece4Schristos                             ZSTD_inBuffer inBuff = { NULL, 0, 0 };
3106*3117ece4Schristos                             size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog+1);
3107*3117ece4Schristos                             size_t const adjustedDstSize = MIN(cBufferSize - outBuff.pos, randomDstSize);
3108*3117ece4Schristos                             outBuff.size = outBuff.pos + adjustedDstSize;
3109*3117ece4Schristos                             DISPLAYLEVEL(6, "t%u: End-flush into dst buffer of size %u \n", testNb, (unsigned)adjustedDstSize);
3110*3117ece4Schristos                             /* ZSTD_e_end guarantees maximal forward progress */
3111*3117ece4Schristos                             remainingToFlush = ZSTD_compressStream2(zc, &outBuff, &inBuff, ZSTD_e_end);
3112*3117ece4Schristos                             DISPLAYLEVEL(6, "t%u: Total flushed so far : %u bytes \n", testNb, (unsigned)outBuff.pos);
3113*3117ece4Schristos                             CHECK( ZSTD_isError(remainingToFlush),
3114*3117ece4Schristos                                 "ZSTD_compressStream2 w/ ZSTD_e_end error : %s",
3115*3117ece4Schristos                                 ZSTD_getErrorName(remainingToFlush) );
3116*3117ece4Schristos                     }   }
3117*3117ece4Schristos                     crcOrig = XXH64_digest(&xxhState);
3118*3117ece4Schristos                 }
3119*3117ece4Schristos                 cSize = outBuff.pos;
3120*3117ece4Schristos                 compressedCrcs[iter] = XXH64(cBuffer, cSize, 0);
3121*3117ece4Schristos                 DISPLAYLEVEL(5, "Frame completed : %zu bytes \n", cSize);
3122*3117ece4Schristos             }
3123*3117ece4Schristos             CHECK(!(compressedCrcs[0] == compressedCrcs[1]), "Compression is not deterministic!");
3124*3117ece4Schristos         }
3125*3117ece4Schristos 
3126*3117ece4Schristos         CHECK(badParameters(zc, savedParams), "CCtx params are wrong");
3127*3117ece4Schristos 
3128*3117ece4Schristos         /* multi - fragments decompression test */
3129*3117ece4Schristos         if (FUZ_rand(&lseed) & 1) {
3130*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_reset(zd, ZSTD_reset_session_and_parameters));
3131*3117ece4Schristos         }
3132*3117ece4Schristos         if (!dictSize /* don't reset if dictionary : could be different */ && (FUZ_rand(&lseed) & 1)) {
3133*3117ece4Schristos             DISPLAYLEVEL(5, "resetting DCtx (dict:%p) \n", (void const*)dict);
3134*3117ece4Schristos             CHECK_Z( ZSTD_resetDStream(zd) );
3135*3117ece4Schristos         } else {
3136*3117ece4Schristos             if (dictSize)
3137*3117ece4Schristos                 DISPLAYLEVEL(5, "using dictionary of size %zu \n", dictSize);
3138*3117ece4Schristos             CHECK_Z( ZSTD_initDStream_usingDict(zd, dict, dictSize) );
3139*3117ece4Schristos         }
3140*3117ece4Schristos         if (FUZ_rand(&lseed) & 1) {
3141*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_disableHuffmanAssembly, FUZ_rand(&lseed) & 1));
3142*3117ece4Schristos         }
3143*3117ece4Schristos         if (FUZ_rand(&lseed) & 1) {
3144*3117ece4Schristos             int maxBlockSize;
3145*3117ece4Schristos             CHECK_Z(ZSTD_CCtx_getParameter(zc, ZSTD_c_maxBlockSize, &maxBlockSize));
3146*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_maxBlockSize, maxBlockSize));
3147*3117ece4Schristos         } else {
3148*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_setParameter(zd, ZSTD_d_maxBlockSize, 0));
3149*3117ece4Schristos         }
3150*3117ece4Schristos         {   size_t decompressionResult = 1;
3151*3117ece4Schristos             ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
3152*3117ece4Schristos             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
3153*3117ece4Schristos             for (totalGenSize = 0 ; decompressionResult ; ) {
3154*3117ece4Schristos                 size_t const readCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
3155*3117ece4Schristos                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
3156*3117ece4Schristos                 size_t const dstBuffSize = MIN(dstBufferSize - totalGenSize, randomDstSize);
3157*3117ece4Schristos                 inBuff.size = inBuff.pos + readCSrcSize;
3158*3117ece4Schristos                 outBuff.size = outBuff.pos + dstBuffSize;
3159*3117ece4Schristos                 DISPLAYLEVEL(6, "decompression presented %u new bytes (pos:%u/%u)\n",
3160*3117ece4Schristos                                 (unsigned)readCSrcSize, (unsigned)inBuff.pos, (unsigned)cSize);
3161*3117ece4Schristos                 decompressionResult = ZSTD_decompressStream(zd, &outBuff, &inBuff);
3162*3117ece4Schristos                 DISPLAYLEVEL(6, "so far: consumed = %u, produced = %u \n",
3163*3117ece4Schristos                                 (unsigned)inBuff.pos, (unsigned)outBuff.pos);
3164*3117ece4Schristos                 if (ZSTD_isError(decompressionResult)) {
3165*3117ece4Schristos                     DISPLAY("ZSTD_decompressStream error : %s \n", ZSTD_getErrorName(decompressionResult));
3166*3117ece4Schristos                     findDiff(copyBuffer, dstBuffer, totalTestSize);
3167*3117ece4Schristos                 }
3168*3117ece4Schristos                 CHECK (ZSTD_isError(decompressionResult), "decompression error : %s", ZSTD_getErrorName(decompressionResult));
3169*3117ece4Schristos                 CHECK (inBuff.pos > cSize, "ZSTD_decompressStream consumes too much input : %u > %u ", (unsigned)inBuff.pos, (unsigned)cSize);
3170*3117ece4Schristos             }
3171*3117ece4Schristos             CHECK (inBuff.pos != cSize, "compressed data should be fully read (%u != %u)", (unsigned)inBuff.pos, (unsigned)cSize);
3172*3117ece4Schristos             CHECK (outBuff.pos != totalTestSize, "decompressed data : wrong size (%u != %u)", (unsigned)outBuff.pos, (unsigned)totalTestSize);
3173*3117ece4Schristos             {   U64 const crcDest = XXH64(dstBuffer, totalTestSize, 0);
3174*3117ece4Schristos                 if (crcDest!=crcOrig) findDiff(copyBuffer, dstBuffer, totalTestSize);
3175*3117ece4Schristos                 CHECK (crcDest!=crcOrig, "decompressed data corrupted");
3176*3117ece4Schristos         }   }
3177*3117ece4Schristos 
3178*3117ece4Schristos         /*=====   noisy/erroneous src decompression test   =====*/
3179*3117ece4Schristos 
3180*3117ece4Schristos         /* add some noise */
3181*3117ece4Schristos         {   U32 const nbNoiseChunks = (FUZ_rand(&lseed) & 7) + 2;
3182*3117ece4Schristos             U32 nn; for (nn=0; nn<nbNoiseChunks; nn++) {
3183*3117ece4Schristos                 size_t const randomNoiseSize = FUZ_randomLength(&lseed, maxSampleLog);
3184*3117ece4Schristos                 size_t const noiseSize  = MIN((cSize/3) , randomNoiseSize);
3185*3117ece4Schristos                 size_t const noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseSize);
3186*3117ece4Schristos                 size_t const cStart = FUZ_rand(&lseed) % (cSize - noiseSize);
3187*3117ece4Schristos                 memcpy(cBuffer+cStart, srcBuffer+noiseStart, noiseSize);
3188*3117ece4Schristos         }   }
3189*3117ece4Schristos 
3190*3117ece4Schristos         /* try decompression on noisy data */
3191*3117ece4Schristos         if (FUZ_rand(&lseed) & 1) {
3192*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_reset(zd_noise, ZSTD_reset_session_and_parameters));
3193*3117ece4Schristos         } else {
3194*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_reset(zd_noise, ZSTD_reset_session_only));
3195*3117ece4Schristos         }
3196*3117ece4Schristos         if (FUZ_rand(&lseed) & 1) {
3197*3117ece4Schristos             CHECK_Z(ZSTD_DCtx_setParameter(zd_noise, ZSTD_d_disableHuffmanAssembly, FUZ_rand(&lseed) & 1));
3198*3117ece4Schristos         }
3199*3117ece4Schristos         {   ZSTD_inBuffer  inBuff = { cBuffer, cSize, 0 };
3200*3117ece4Schristos             ZSTD_outBuffer outBuff= { dstBuffer, dstBufferSize, 0 };
3201*3117ece4Schristos             while (outBuff.pos < dstBufferSize) {
3202*3117ece4Schristos                 size_t const randomCSrcSize = FUZ_randomLength(&lseed, maxSampleLog);
3203*3117ece4Schristos                 size_t const randomDstSize = FUZ_randomLength(&lseed, maxSampleLog);
3204*3117ece4Schristos                 size_t const adjustedDstSize = MIN(dstBufferSize - outBuff.pos, randomDstSize);
3205*3117ece4Schristos                 size_t const adjustedCSrcSize = MIN(cSize - inBuff.pos, randomCSrcSize);
3206*3117ece4Schristos                 outBuff.size = outBuff.pos + adjustedDstSize;
3207*3117ece4Schristos                 inBuff.size  = inBuff.pos + adjustedCSrcSize;
3208*3117ece4Schristos                 {   size_t const decompressError = ZSTD_decompressStream(zd, &outBuff, &inBuff);
3209*3117ece4Schristos                     if (ZSTD_isError(decompressError)) break;   /* error correctly detected */
3210*3117ece4Schristos                     /* Good so far, but no more progress possible */
3211*3117ece4Schristos                     if (outBuff.pos < outBuff.size && inBuff.pos == cSize) break;
3212*3117ece4Schristos     }   }   }   }
3213*3117ece4Schristos     DISPLAY("\r%u fuzzer tests completed   \n", testNb-1);
3214*3117ece4Schristos 
3215*3117ece4Schristos _cleanup:
3216*3117ece4Schristos     ZSTD_freeCCtx(zc);
3217*3117ece4Schristos     ZSTD_freeDStream(zd);
3218*3117ece4Schristos     ZSTD_freeDStream(zd_noise);
3219*3117ece4Schristos     ZSTD_freeCCtxParams(cctxParams);
3220*3117ece4Schristos     free(cNoiseBuffer[0]);
3221*3117ece4Schristos     free(cNoiseBuffer[1]);
3222*3117ece4Schristos     free(cNoiseBuffer[2]);
3223*3117ece4Schristos     free(cNoiseBuffer[3]);
3224*3117ece4Schristos     free(cNoiseBuffer[4]);
3225*3117ece4Schristos     free(copyBuffer);
3226*3117ece4Schristos     free(cBuffer);
3227*3117ece4Schristos     free(dstBuffer);
3228*3117ece4Schristos     return result;
3229*3117ece4Schristos 
3230*3117ece4Schristos _output_error:
3231*3117ece4Schristos     result = 1;
3232*3117ece4Schristos     goto _cleanup;
3233*3117ece4Schristos }
3234*3117ece4Schristos 
3235*3117ece4Schristos /*-*******************************************************
3236*3117ece4Schristos *  Command line
3237*3117ece4Schristos *********************************************************/
3238*3117ece4Schristos static int FUZ_usage(const char* programName)
3239*3117ece4Schristos {
3240*3117ece4Schristos     DISPLAY( "Usage :\n");
3241*3117ece4Schristos     DISPLAY( "      %s [args]\n", programName);
3242*3117ece4Schristos     DISPLAY( "\n");
3243*3117ece4Schristos     DISPLAY( "Arguments :\n");
3244*3117ece4Schristos     DISPLAY( " -i#    : Number of tests (default:%u)\n", nbTestsDefault);
3245*3117ece4Schristos     DISPLAY( " -T#    : Max duration to run for. Overrides number of tests. (e.g. -T1m or -T60s for one minute)\n");
3246*3117ece4Schristos     DISPLAY( " -s#    : Select seed (default:prompt user)\n");
3247*3117ece4Schristos     DISPLAY( " -t#    : Select starting test number (default:0)\n");
3248*3117ece4Schristos     DISPLAY( " -P#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
3249*3117ece4Schristos     DISPLAY( " -v     : verbose\n");
3250*3117ece4Schristos     DISPLAY( " -p     : pause at the end\n");
3251*3117ece4Schristos     DISPLAY( " -h     : display help and exit\n");
3252*3117ece4Schristos     return 0;
3253*3117ece4Schristos }
3254*3117ece4Schristos 
3255*3117ece4Schristos typedef enum { simple_api, advanced_api } e_api;
3256*3117ece4Schristos 
3257*3117ece4Schristos int main(int argc, const char** argv)
3258*3117ece4Schristos {
3259*3117ece4Schristos     U32 seed = 0;
3260*3117ece4Schristos     int seedset = 0;
3261*3117ece4Schristos     int nbTests = nbTestsDefault;
3262*3117ece4Schristos     int testNb = 0;
3263*3117ece4Schristos     int proba = FUZ_COMPRESSIBILITY_DEFAULT;
3264*3117ece4Schristos     int result = 0;
3265*3117ece4Schristos     int mainPause = 0;
3266*3117ece4Schristos     int bigTests = (sizeof(size_t) == 8);
3267*3117ece4Schristos     e_api selected_api = simple_api;
3268*3117ece4Schristos     const char* const programName = argv[0];
3269*3117ece4Schristos     int argNb;
3270*3117ece4Schristos 
3271*3117ece4Schristos     /* Check command line */
3272*3117ece4Schristos     for(argNb=1; argNb<argc; argNb++) {
3273*3117ece4Schristos         const char* argument = argv[argNb];
3274*3117ece4Schristos         assert(argument != NULL);
3275*3117ece4Schristos 
3276*3117ece4Schristos         /* Parsing commands. Aggregated commands are allowed */
3277*3117ece4Schristos         if (argument[0]=='-') {
3278*3117ece4Schristos 
3279*3117ece4Schristos             if (!strcmp(argument, "--newapi")) { selected_api=advanced_api; testNb += !testNb; continue; }
3280*3117ece4Schristos             if (!strcmp(argument, "--no-big-tests")) { bigTests=0; continue; }
3281*3117ece4Schristos             if (!strcmp(argument, "--big-tests")) { bigTests=1; continue; }
3282*3117ece4Schristos 
3283*3117ece4Schristos             argument++;
3284*3117ece4Schristos             while (*argument!=0) {
3285*3117ece4Schristos                 switch(*argument)
3286*3117ece4Schristos                 {
3287*3117ece4Schristos                 case 'h':
3288*3117ece4Schristos                     return FUZ_usage(programName);
3289*3117ece4Schristos 
3290*3117ece4Schristos                 case 'v':
3291*3117ece4Schristos                     argument++;
3292*3117ece4Schristos                     g_displayLevel++;
3293*3117ece4Schristos                     break;
3294*3117ece4Schristos 
3295*3117ece4Schristos                 case 'q':
3296*3117ece4Schristos                     argument++;
3297*3117ece4Schristos                     g_displayLevel--;
3298*3117ece4Schristos                     break;
3299*3117ece4Schristos 
3300*3117ece4Schristos                 case 'p': /* pause at the end */
3301*3117ece4Schristos                     argument++;
3302*3117ece4Schristos                     mainPause = 1;
3303*3117ece4Schristos                     break;
3304*3117ece4Schristos 
3305*3117ece4Schristos                 case 'i':   /* limit tests by nb of iterations (default) */
3306*3117ece4Schristos                     argument++;
3307*3117ece4Schristos                     nbTests=0; g_clockTime=0;
3308*3117ece4Schristos                     while ((*argument>='0') && (*argument<='9')) {
3309*3117ece4Schristos                         nbTests *= 10;
3310*3117ece4Schristos                         nbTests += *argument - '0';
3311*3117ece4Schristos                         argument++;
3312*3117ece4Schristos                     }
3313*3117ece4Schristos                     break;
3314*3117ece4Schristos 
3315*3117ece4Schristos                 case 'T':   /* limit tests by time */
3316*3117ece4Schristos                     argument++;
3317*3117ece4Schristos                     nbTests=0; g_clockTime=0;
3318*3117ece4Schristos                     while ((*argument>='0') && (*argument<='9')) {
3319*3117ece4Schristos                         g_clockTime *= 10;
3320*3117ece4Schristos                         g_clockTime += *argument - '0';
3321*3117ece4Schristos                         argument++;
3322*3117ece4Schristos                     }
3323*3117ece4Schristos                     if (*argument=='m') {    /* -T1m == -T60 */
3324*3117ece4Schristos                         g_clockTime *=60, argument++;
3325*3117ece4Schristos                         if (*argument=='n') argument++; /* -T1mn == -T60 */
3326*3117ece4Schristos                     } else if (*argument=='s') argument++; /* -T10s == -T10 */
3327*3117ece4Schristos                     g_clockTime *= SEC_TO_MICRO;
3328*3117ece4Schristos                     break;
3329*3117ece4Schristos 
3330*3117ece4Schristos                 case 's':   /* manually select seed */
3331*3117ece4Schristos                     argument++;
3332*3117ece4Schristos                     seedset=1;
3333*3117ece4Schristos                     seed=0;
3334*3117ece4Schristos                     while ((*argument>='0') && (*argument<='9')) {
3335*3117ece4Schristos                         seed *= 10;
3336*3117ece4Schristos                         seed += *argument - '0';
3337*3117ece4Schristos                         argument++;
3338*3117ece4Schristos                     }
3339*3117ece4Schristos                     break;
3340*3117ece4Schristos 
3341*3117ece4Schristos                 case 't':   /* select starting test number */
3342*3117ece4Schristos                     argument++;
3343*3117ece4Schristos                     testNb=0;
3344*3117ece4Schristos                     while ((*argument>='0') && (*argument<='9')) {
3345*3117ece4Schristos                         testNb *= 10;
3346*3117ece4Schristos                         testNb += *argument - '0';
3347*3117ece4Schristos                         argument++;
3348*3117ece4Schristos                     }
3349*3117ece4Schristos                     break;
3350*3117ece4Schristos 
3351*3117ece4Schristos                 case 'P':   /* compressibility % */
3352*3117ece4Schristos                     argument++;
3353*3117ece4Schristos                     proba=0;
3354*3117ece4Schristos                     while ((*argument>='0') && (*argument<='9')) {
3355*3117ece4Schristos                         proba *= 10;
3356*3117ece4Schristos                         proba += *argument - '0';
3357*3117ece4Schristos                         argument++;
3358*3117ece4Schristos                     }
3359*3117ece4Schristos                     if (proba<0) proba=0;
3360*3117ece4Schristos                     if (proba>100) proba=100;
3361*3117ece4Schristos                     break;
3362*3117ece4Schristos 
3363*3117ece4Schristos                 default:
3364*3117ece4Schristos                     return FUZ_usage(programName);
3365*3117ece4Schristos                 }
3366*3117ece4Schristos     }   }   }   /* for(argNb=1; argNb<argc; argNb++) */
3367*3117ece4Schristos 
3368*3117ece4Schristos     /* Get Seed */
3369*3117ece4Schristos     DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING);
3370*3117ece4Schristos 
3371*3117ece4Schristos     if (!seedset) {
3372*3117ece4Schristos         time_t const t = time(NULL);
3373*3117ece4Schristos         U32 const h = XXH32(&t, sizeof(t), 1);
3374*3117ece4Schristos         seed = h % 10000;
3375*3117ece4Schristos     }
3376*3117ece4Schristos 
3377*3117ece4Schristos     DISPLAY("Seed = %u\n", (unsigned)seed);
3378*3117ece4Schristos     if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba);
3379*3117ece4Schristos 
3380*3117ece4Schristos     if (nbTests<=0) nbTests=1;
3381*3117ece4Schristos 
3382*3117ece4Schristos     if (testNb==0) {
3383*3117ece4Schristos         result = basicUnitTests(0, ((double)proba) / 100, bigTests);  /* constant seed for predictability */
3384*3117ece4Schristos     }
3385*3117ece4Schristos 
3386*3117ece4Schristos     if (!result) {
3387*3117ece4Schristos         switch(selected_api)
3388*3117ece4Schristos         {
3389*3117ece4Schristos         case simple_api :
3390*3117ece4Schristos             result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
3391*3117ece4Schristos             break;
3392*3117ece4Schristos         case advanced_api :
3393*3117ece4Schristos             result = fuzzerTests_newAPI(seed, nbTests, testNb, ((double)proba) / 100, bigTests);
3394*3117ece4Schristos             break;
3395*3117ece4Schristos         default :
3396*3117ece4Schristos             assert(0);   /* impossible */
3397*3117ece4Schristos         }
3398*3117ece4Schristos     }
3399*3117ece4Schristos 
3400*3117ece4Schristos     if (mainPause) {
3401*3117ece4Schristos         int unused;
3402*3117ece4Schristos         DISPLAY("Press Enter \n");
3403*3117ece4Schristos         unused = getchar();
3404*3117ece4Schristos         (void)unused;
3405*3117ece4Schristos     }
3406*3117ece4Schristos     return result;
3407*3117ece4Schristos }
3408