Home | History | Annotate | Download | only in programs
      1 /*
      2     frameTest - test tool for lz4frame
      3     Copyright (C) Yann Collet 2014
      4     GPL v2 License
      5 
      6     This program is free software; you can redistribute it and/or modify
      7     it under the terms of the GNU General Public License as published by
      8     the Free Software Foundation; either version 2 of the License, or
      9     (at your option) any later version.
     10 
     11     This program is distributed in the hope that it will be useful,
     12     but WITHOUT ANY WARRANTY; without even the implied warranty of
     13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14     GNU General Public License for more details.
     15 
     16     You should have received a copy of the GNU General Public License along
     17     with this program; if not, write to the Free Software Foundation, Inc.,
     18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     19 
     20     You can contact the author at :
     21     - LZ4 source repository : http://code.google.com/p/lz4/
     22     - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
     23 */
     24 
     25 /**************************************
     26   Compiler specific
     27 **************************************/
     28 #define _CRT_SECURE_NO_WARNINGS   // fgets
     29 #ifdef _MSC_VER    /* Visual Studio */
     30 #  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
     31 #  pragma warning(disable : 4146)        /* disable: C4146: minus unsigned expression */
     32 #endif
     33 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
     34 #ifdef __GNUC__
     35 #  pragma GCC diagnostic ignored "-Wmissing-braces"   /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
     36 #  pragma GCC diagnostic ignored "-Wmissing-field-initializers"   /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
     37 #endif
     38 
     39 
     40 /**************************************
     41   Includes
     42 **************************************/
     43 #include <stdlib.h>     // free
     44 #include <stdio.h>      // fgets, sscanf
     45 #include <sys/timeb.h>  // timeb
     46 #include <string.h>     // strcmp
     47 #include "lz4frame_static.h"
     48 #include "xxhash.h"     // XXH64
     49 
     50 
     51 /**************************************
     52    Basic Types
     53 **************************************/
     54 #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   /* C99 */
     55 # include <stdint.h>
     56 typedef  uint8_t BYTE;
     57 typedef uint16_t U16;
     58 typedef uint32_t U32;
     59 typedef  int32_t S32;
     60 typedef uint64_t U64;
     61 #else
     62 typedef unsigned char       BYTE;
     63 typedef unsigned short      U16;
     64 typedef unsigned int        U32;
     65 typedef   signed int        S32;
     66 typedef unsigned long long  U64;
     67 #endif
     68 
     69 
     70 /**************************************
     71  Constants
     72 **************************************/
     73 #ifndef LZ4_VERSION
     74 #  define LZ4_VERSION ""
     75 #endif
     76 
     77 #define KB *(1U<<10)
     78 #define MB *(1U<<20)
     79 #define GB *(1U<<30)
     80 
     81 static const U32 nbTestsDefault = 256 KB;
     82 #define COMPRESSIBLE_NOISE_LENGTH (2 MB)
     83 #define FUZ_COMPRESSIBILITY_DEFAULT 50
     84 static const U32 prime1 = 2654435761U;
     85 static const U32 prime2 = 2246822519U;
     86 
     87 
     88 
     89 /**************************************
     90   Macros
     91 **************************************/
     92 #define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
     93 #define DISPLAYLEVEL(l, ...)  if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
     94 #define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
     95             if ((FUZ_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
     96             { g_time = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
     97             if (displayLevel>=4) fflush(stdout); } }
     98 static const U32 refreshRate = 150;
     99 static U32 g_time = 0;
    100 
    101 
    102 /*****************************************
    103   Local Parameters
    104 *****************************************/
    105 static U32 no_prompt = 0;
    106 static char* programName;
    107 static U32 displayLevel = 2;
    108 static U32 pause = 0;
    109 
    110 
    111 /*********************************************************
    112   Fuzzer functions
    113 *********************************************************/
    114 static U32 FUZ_GetMilliStart(void)
    115 {
    116     struct timeb tb;
    117     U32 nCount;
    118     ftime( &tb );
    119     nCount = (U32) (((tb.time & 0xFFFFF) * 1000) +  tb.millitm);
    120     return nCount;
    121 }
    122 
    123 
    124 static U32 FUZ_GetMilliSpan(U32 nTimeStart)
    125 {
    126     U32 nCurrent = FUZ_GetMilliStart();
    127     U32 nSpan = nCurrent - nTimeStart;
    128     if (nTimeStart > nCurrent)
    129         nSpan += 0x100000 * 1000;
    130     return nSpan;
    131 }
    132 
    133 
    134 #  define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
    135 unsigned int FUZ_rand(unsigned int* src)
    136 {
    137     U32 rand32 = *src;
    138     rand32 *= prime1;
    139     rand32 += prime2;
    140     rand32  = FUZ_rotl32(rand32, 13);
    141     *src = rand32;
    142     return rand32 >> 5;
    143 }
    144 
    145 
    146 #define FUZ_RAND15BITS  (FUZ_rand(seed) & 0x7FFF)
    147 #define FUZ_RANDLENGTH  ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
    148 static void FUZ_fillCompressibleNoiseBuffer(void* buffer, unsigned bufferSize, double proba, U32* seed)
    149 {
    150     BYTE* BBuffer = (BYTE*)buffer;
    151     unsigned pos = 0;
    152     U32 P32 = (U32)(32768 * proba);
    153 
    154     // First Byte
    155     BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
    156 
    157     while (pos < bufferSize)
    158     {
    159         // Select : Literal (noise) or copy (within 64K)
    160         if (FUZ_RAND15BITS < P32)
    161         {
    162             // Copy (within 64K)
    163             unsigned match, end;
    164             unsigned length = FUZ_RANDLENGTH + 4;
    165             unsigned offset = FUZ_RAND15BITS + 1;
    166             if (offset > pos) offset = pos;
    167             if (pos + length > bufferSize) length = bufferSize - pos;
    168             match = pos - offset;
    169             end = pos + length;
    170             while (pos < end) BBuffer[pos++] = BBuffer[match++];
    171         }
    172         else
    173         {
    174             // Literal (noise)
    175             unsigned end;
    176             unsigned length = FUZ_RANDLENGTH;
    177             if (pos + length > bufferSize) length = bufferSize - pos;
    178             end = pos + length;
    179             while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
    180         }
    181     }
    182 }
    183 
    184 
    185 static unsigned FUZ_highbit(U32 v32)
    186 {
    187     unsigned nbBits = 0;
    188     if (v32==0) return 0;
    189     while (v32)
    190     {
    191         v32 >>= 1;
    192         nbBits ++;
    193     }
    194     return nbBits;
    195 }
    196 
    197 
    198 int basicTests(U32 seed, double compressibility)
    199 {
    200     int testResult = 0;
    201     void* CNBuffer;
    202     void* compressedBuffer;
    203     void* decodedBuffer;
    204     U32 randState = seed;
    205     size_t cSize, testSize;
    206     LZ4F_preferences_t prefs = { 0 };
    207     LZ4F_decompressionContext_t dCtx;
    208     U64 crcOrig;
    209 
    210     // Create compressible test buffer
    211     CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
    212     compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
    213     decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
    214     FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
    215     crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
    216 
    217     // Trivial tests : one-step frame
    218     testSize = COMPRESSIBLE_NOISE_LENGTH;
    219     DISPLAYLEVEL(3, "Using NULL preferences : \n");
    220     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
    221     if (LZ4F_isError(cSize)) goto _output_error;
    222     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    223 
    224     DISPLAYLEVEL(3, "Decompression test : \n");
    225     {
    226         size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
    227         size_t compressedBufferSize = cSize;
    228         BYTE* op = (BYTE*)decodedBuffer;
    229         BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
    230         BYTE* ip = (BYTE*)compressedBuffer;
    231         BYTE* const iend = (BYTE*)compressedBuffer + cSize;
    232         U64 crcDest;
    233 
    234         LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
    235         if (LZ4F_isError(errorCode)) goto _output_error;
    236 
    237         DISPLAYLEVEL(3, "Single Block : \n");
    238         errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
    239         crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
    240         if (crcDest != crcOrig) goto _output_error;
    241         DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
    242 
    243         DISPLAYLEVEL(3, "Byte after byte : \n");
    244         while (ip < iend)
    245         {
    246             size_t oSize = oend-op;
    247             size_t iSize = 1;
    248             //DISPLAY("%7i \n", (int)(ip-(BYTE*)compressedBuffer));
    249             errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
    250             if (LZ4F_isError(errorCode)) goto _output_error;
    251             op += oSize;
    252             ip += iSize;
    253         }
    254         crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
    255         if (crcDest != crcOrig) goto _output_error;
    256         DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
    257 
    258         errorCode = LZ4F_freeDecompressionContext(dCtx);
    259         if (LZ4F_isError(errorCode)) goto _output_error;
    260     }
    261 
    262     DISPLAYLEVEL(3, "Using 64 KB block : \n");
    263     prefs.frameInfo.blockSizeID = max64KB;
    264     prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
    265     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    266     if (LZ4F_isError(cSize)) goto _output_error;
    267     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    268 
    269     DISPLAYLEVEL(3, "without checksum : \n");
    270     prefs.frameInfo.contentChecksumFlag = noContentChecksum;
    271     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    272     if (LZ4F_isError(cSize)) goto _output_error;
    273     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    274 
    275     DISPLAYLEVEL(3, "Using 256 KB block : \n");
    276     prefs.frameInfo.blockSizeID = max256KB;
    277     prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
    278     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    279     if (LZ4F_isError(cSize)) goto _output_error;
    280     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    281 
    282     DISPLAYLEVEL(3, "Decompression test : \n");
    283     {
    284         size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
    285         unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
    286         BYTE* op = (BYTE*)decodedBuffer;
    287         BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
    288         BYTE* ip = (BYTE*)compressedBuffer;
    289         BYTE* const iend = (BYTE*)compressedBuffer + cSize;
    290         U64 crcDest;
    291 
    292         LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
    293         if (LZ4F_isError(errorCode)) goto _output_error;
    294 
    295         DISPLAYLEVEL(3, "random segment sizes : \n");
    296         while (ip < iend)
    297         {
    298             unsigned nbBits = FUZ_rand(&randState) % maxBits;
    299             size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
    300             size_t oSize = oend-op;
    301             if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
    302             //DISPLAY("%7i : + %6i\n", (int)(ip-(BYTE*)compressedBuffer), (int)iSize);
    303             errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
    304             if (LZ4F_isError(errorCode)) goto _output_error;
    305             op += oSize;
    306             ip += iSize;
    307         }
    308         crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
    309         if (crcDest != crcOrig) goto _output_error;
    310         DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
    311 
    312         errorCode = LZ4F_freeDecompressionContext(dCtx);
    313         if (LZ4F_isError(errorCode)) goto _output_error;
    314     }
    315 
    316     DISPLAYLEVEL(3, "without checksum : \n");
    317     prefs.frameInfo.contentChecksumFlag = noContentChecksum;
    318     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    319     if (LZ4F_isError(cSize)) goto _output_error;
    320     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    321 
    322     DISPLAYLEVEL(3, "Using 1 MB block : \n");
    323     prefs.frameInfo.blockSizeID = max1MB;
    324     prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
    325     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    326     if (LZ4F_isError(cSize)) goto _output_error;
    327     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    328 
    329     DISPLAYLEVEL(3, "without checksum : \n");
    330     prefs.frameInfo.contentChecksumFlag = noContentChecksum;
    331     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    332     if (LZ4F_isError(cSize)) goto _output_error;
    333     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    334 
    335     DISPLAYLEVEL(3, "Using 4 MB block : \n");
    336     prefs.frameInfo.blockSizeID = max4MB;
    337     prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
    338     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    339     if (LZ4F_isError(cSize)) goto _output_error;
    340     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    341 
    342     DISPLAYLEVEL(3, "without checksum : \n");
    343     prefs.frameInfo.contentChecksumFlag = noContentChecksum;
    344     cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
    345     if (LZ4F_isError(cSize)) goto _output_error;
    346     DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
    347 
    348     DISPLAY("Basic tests completed \n");
    349 _end:
    350     free(CNBuffer);
    351     free(compressedBuffer);
    352     free(decodedBuffer);
    353     return testResult;
    354 
    355 _output_error:
    356     testResult = 1;
    357     DISPLAY("Error detected ! \n");
    358     goto _end;
    359 }
    360 
    361 
    362 static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
    363 {
    364     int p=0;
    365     BYTE* b1=(BYTE*)buff1;
    366     BYTE* b2=(BYTE*)buff2;
    367     if (nonContiguous)
    368     {
    369         DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size);
    370         return;
    371     }
    372     while (b1[p]==b2[p]) p++;
    373     DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]);
    374 }
    375 
    376 
    377 static const U32 srcDataLength = 9 MB;  /* needs to be > 2x4MB to test large blocks */
    378 
    379 int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility)
    380 {
    381     unsigned testResult = 0;
    382     unsigned testNb = 0;
    383     void* srcBuffer = NULL;
    384     void* compressedBuffer = NULL;
    385     void* decodedBuffer = NULL;
    386     U32 coreRand = seed;
    387     LZ4F_decompressionContext_t dCtx = NULL;
    388     LZ4F_compressionContext_t cCtx = NULL;
    389     size_t result;
    390     XXH64_state_t xxh64;
    391 #   define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
    392                             DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); goto _output_error; }
    393 
    394     // Create buffers
    395     result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
    396     CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
    397     result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
    398     CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
    399     srcBuffer = malloc(srcDataLength);
    400     CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
    401     compressedBuffer = malloc(LZ4F_compressFrameBound(srcDataLength, NULL));
    402     CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
    403     decodedBuffer = malloc(srcDataLength);
    404     CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
    405     FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
    406 
    407     // jump to requested testNb
    408     for (testNb =0; testNb < startTest; testNb++) (void)FUZ_rand(&coreRand);   // sync randomizer
    409 
    410     // main fuzzer loop
    411     for ( ; testNb < nbTests; testNb++)
    412     {
    413         U32 randState = coreRand ^ prime1;
    414         unsigned BSId   = 4 + (FUZ_rand(&randState) & 3);
    415         unsigned BMId   = FUZ_rand(&randState) & 1;
    416         unsigned CCflag = FUZ_rand(&randState) & 1;
    417         unsigned autoflush = (FUZ_rand(&randState) & 7) == 2;
    418         LZ4F_preferences_t prefs = { 0 };
    419         LZ4F_compressOptions_t cOptions = { 0 };
    420         LZ4F_decompressOptions_t dOptions = { 0 };
    421         unsigned nbBits = (FUZ_rand(&randState) % (FUZ_highbit(srcDataLength-1) - 1)) + 1;
    422         size_t srcSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
    423         size_t srcStart = FUZ_rand(&randState) % (srcDataLength - srcSize);
    424         size_t cSize;
    425         U64 crcOrig, crcDecoded;
    426         LZ4F_preferences_t* prefsPtr = &prefs;
    427 
    428         (void)FUZ_rand(&coreRand);   // update rand seed
    429         prefs.frameInfo.blockMode = (blockMode_t)BMId;
    430         prefs.frameInfo.blockSizeID = (blockSizeID_t)BSId;
    431         prefs.frameInfo.contentChecksumFlag = (contentChecksum_t)CCflag;
    432         prefs.autoFlush = autoflush;
    433         prefs.compressionLevel = FUZ_rand(&randState) % 5;
    434         if ((FUZ_rand(&randState)&0xF) == 1) prefsPtr = NULL;
    435 
    436         DISPLAYUPDATE(2, "\r%5u   ", testNb);
    437         crcOrig = XXH64((BYTE*)srcBuffer+srcStart, (U32)srcSize, 1);
    438 
    439         if ((FUZ_rand(&randState)&0xF) == 2)
    440         {
    441             cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), (char*)srcBuffer + srcStart, srcSize, prefsPtr);
    442             CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
    443         }
    444         else
    445         {
    446             const BYTE* ip = (const BYTE*)srcBuffer + srcStart;
    447             const BYTE* const iend = ip + srcSize;
    448             BYTE* op = (BYTE*)compressedBuffer;
    449             BYTE* const oend = op + LZ4F_compressFrameBound(srcDataLength, NULL);
    450             unsigned maxBits = FUZ_highbit((U32)srcSize);
    451             result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr);
    452             CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
    453             op += result;
    454             while (ip < iend)
    455             {
    456                 unsigned nbBitsSeg = FUZ_rand(&randState) % maxBits;
    457                 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
    458                 size_t oSize = LZ4F_compressBound(iSize, prefsPtr);
    459                 unsigned forceFlush = ((FUZ_rand(&randState) & 3) == 1);
    460                 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
    461                 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
    462 
    463                 result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
    464                 CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
    465                 op += result;
    466                 ip += iSize;
    467 
    468                 if (forceFlush)
    469                 {
    470                     result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
    471                     CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
    472                     op += result;
    473                 }
    474             }
    475             result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
    476             CHECK(LZ4F_isError(result), "Compression completion failed (error %i)", (int)result);
    477             op += result;
    478             cSize = op-(BYTE*)compressedBuffer;
    479         }
    480 
    481         {
    482             const BYTE* ip = (const BYTE*)compressedBuffer;
    483             const BYTE* const iend = ip + cSize;
    484             BYTE* op = (BYTE*)decodedBuffer;
    485             BYTE* const oend = op + srcDataLength;
    486             unsigned maxBits = FUZ_highbit((U32)cSize);
    487             unsigned nonContiguousDst = (FUZ_rand(&randState) & 3) == 1;
    488             nonContiguousDst += FUZ_rand(&randState) & nonContiguousDst;   /* 0=>0; 1=>1,2 */
    489             XXH64_reset(&xxh64, 1);
    490             while (ip < iend)
    491             {
    492                 unsigned nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
    493                 unsigned nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
    494                 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1;
    495                 size_t oSize = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2;
    496                 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
    497                 if (oSize > (size_t)(oend-op)) oSize = oend-op;
    498                 dOptions.stableDst = FUZ_rand(&randState) & 1;
    499                 if (nonContiguousDst==2) dOptions.stableDst = 0;
    500                 //if (ip == compressedBuffer+62073)                    DISPLAY("oSize : %i : pos %i \n", (int)oSize, (int)(op-(BYTE*)decodedBuffer));
    501                 result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
    502                 //if (op+oSize >= (BYTE*)decodedBuffer+94727)                    DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
    503                 //if ((int)result<0)                    DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
    504                 if (result == (size_t)-ERROR_checksum_invalid) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
    505                 CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName((LZ4F_errorCode_t)result));
    506                 XXH64_update(&xxh64, op, (U32)oSize);
    507                 op += oSize;
    508                 ip += iSize;
    509                 op += nonContiguousDst;
    510                 if (nonContiguousDst==2) op = decodedBuffer;   // overwritten destination
    511             }
    512             CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
    513             crcDecoded = XXH64_digest(&xxh64);
    514             if (crcDecoded != crcOrig) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
    515             CHECK(crcDecoded != crcOrig, "Decompression corruption");
    516         }
    517     }
    518 
    519     DISPLAYLEVEL(2, "\rAll tests completed   \n");
    520 
    521 _end:
    522     LZ4F_freeDecompressionContext(dCtx);
    523     LZ4F_freeCompressionContext(cCtx);
    524     free(srcBuffer);
    525     free(compressedBuffer);
    526     free(decodedBuffer);
    527 
    528     if (pause)
    529     {
    530         DISPLAY("press enter to finish \n");
    531         getchar();
    532     }
    533     return testResult;
    534 
    535 _output_error:
    536     testResult = 1;
    537     goto _end;
    538 }
    539 
    540 
    541 int FUZ_usage(void)
    542 {
    543     DISPLAY( "Usage :\n");
    544     DISPLAY( "      %s [args]\n", programName);
    545     DISPLAY( "\n");
    546     DISPLAY( "Arguments :\n");
    547     DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
    548     DISPLAY( " -s#    : Select seed (default:prompt user)\n");
    549     DISPLAY( " -t#    : Select starting test number (default:0)\n");
    550     DISPLAY( " -p#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
    551     DISPLAY( " -v     : verbose\n");
    552     DISPLAY( " -h     : display help and exit\n");
    553     return 0;
    554 }
    555 
    556 
    557 int main(int argc, char** argv)
    558 {
    559     U32 seed=0;
    560     int seedset=0;
    561     int argNb;
    562     int nbTests = nbTestsDefault;
    563     int testNb = 0;
    564     int proba = FUZ_COMPRESSIBILITY_DEFAULT;
    565     int result=0;
    566 
    567     // Check command line
    568     programName = argv[0];
    569     for(argNb=1; argNb<argc; argNb++)
    570     {
    571         char* argument = argv[argNb];
    572 
    573         if(!argument) continue;   // Protection if argument empty
    574 
    575         // Decode command (note : aggregated commands are allowed)
    576         if (argument[0]=='-')
    577         {
    578             if (!strcmp(argument, "--no-prompt"))
    579             {
    580                 no_prompt=1;
    581                 seedset=1;
    582                 displayLevel=1;
    583                 continue;
    584             }
    585             argument++;
    586 
    587             while (*argument!=0)
    588             {
    589                 switch(*argument)
    590                 {
    591                 case 'h':
    592                     return FUZ_usage();
    593                 case 'v':
    594                     argument++;
    595                     displayLevel=4;
    596                     break;
    597                 case 'q':
    598                     argument++;
    599                     displayLevel--;
    600                     break;
    601                 case 'p': /* pause at the end */
    602                     argument++;
    603                     pause = 1;
    604                     break;
    605 
    606                 case 'i':
    607                     argument++;
    608                     nbTests=0;
    609                     while ((*argument>='0') && (*argument<='9'))
    610                     {
    611                         nbTests *= 10;
    612                         nbTests += *argument - '0';
    613                         argument++;
    614                     }
    615                     break;
    616                 case 's':
    617                     argument++;
    618                     seed=0;
    619                     seedset=1;
    620                     while ((*argument>='0') && (*argument<='9'))
    621                     {
    622                         seed *= 10;
    623                         seed += *argument - '0';
    624                         argument++;
    625                     }
    626                     break;
    627                 case 't':
    628                     argument++;
    629                     testNb=0;
    630                     while ((*argument>='0') && (*argument<='9'))
    631                     {
    632                         testNb *= 10;
    633                         testNb += *argument - '0';
    634                         argument++;
    635                     }
    636                     break;
    637                 case 'P':   /* compressibility % */
    638                     argument++;
    639                     proba=0;
    640                     while ((*argument>='0') && (*argument<='9'))
    641                     {
    642                         proba *= 10;
    643                         proba += *argument - '0';
    644                         argument++;
    645                     }
    646                     if (proba<0) proba=0;
    647                     if (proba>100) proba=100;
    648                     break;
    649                 default:
    650                     ;
    651                     return FUZ_usage();
    652                 }
    653             }
    654         }
    655     }
    656 
    657     // Get Seed
    658     printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
    659 
    660     if (!seedset) seed = FUZ_GetMilliStart() % 10000;
    661     printf("Seed = %u\n", seed);
    662     if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
    663 
    664     if (nbTests<=0) nbTests=1;
    665 
    666     if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
    667     if (result) return 1;
    668     return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
    669 }
    670