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