kusano 7d535a
/*
kusano 7d535a
    frameTest - test tool for lz4frame
kusano 7d535a
    Copyright (C) Yann Collet 2014-2015
kusano 7d535a
kusano 7d535a
    GPL v2 License
kusano 7d535a
kusano 7d535a
    This program is free software; you can redistribute it and/or modify
kusano 7d535a
    it under the terms of the GNU General Public License as published by
kusano 7d535a
    the Free Software Foundation; either version 2 of the License, or
kusano 7d535a
    (at your option) any later version.
kusano 7d535a
kusano 7d535a
    This program is distributed in the hope that it will be useful,
kusano 7d535a
    but WITHOUT ANY WARRANTY; without even the implied warranty of
kusano 7d535a
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
kusano 7d535a
    GNU General Public License for more details.
kusano 7d535a
kusano 7d535a
    You should have received a copy of the GNU General Public License along
kusano 7d535a
    with this program; if not, write to the Free Software Foundation, Inc.,
kusano 7d535a
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
kusano 7d535a
kusano 7d535a
    You can contact the author at :
kusano 7d535a
    - LZ4 source repository : https://github.com/Cyan4973/lz4
kusano 7d535a
    - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
kusano 7d535a
*/
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Compiler specific
kusano 7d535a
**************************************/
kusano 7d535a
#ifdef _MSC_VER    /* Visual Studio */
kusano 7d535a
#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */
kusano 7d535a
#  pragma warning(disable : 4146)        /* disable: C4146: minus unsigned expression */
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
/* S_ISREG & gettimeofday() are not supported by MSVC */
kusano 7d535a
#if defined(_MSC_VER) || defined(_WIN32)
kusano 7d535a
#  define FUZ_LEGACY_TIMER 1
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Includes
kusano 7d535a
**************************************/
kusano 7d535a
#include <stdlib.h>     /* malloc, free */</stdlib.h>
kusano 7d535a
#include <stdio.h>      /* fprintf */</stdio.h>
kusano 7d535a
#include <string.h>     /* strcmp */</string.h>
kusano 7d535a
#include "lz4frame_static.h"
kusano 7d535a
#include "xxhash.h"     /* XXH64 */
kusano 7d535a
kusano 7d535a
/* Use ftime() if gettimeofday() is not available on your target */
kusano 7d535a
#if defined(FUZ_LEGACY_TIMER)
kusano 7d535a
#  include <sys timeb.h="">   /* timeb, ftime */</sys>
kusano 7d535a
#else
kusano 7d535a
#  include <sys time.h="">    /* gettimeofday */</sys>
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Basic Types
kusano 7d535a
**************************************/
kusano 7d535a
#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   /* C99 */
kusano 7d535a
# include <stdint.h></stdint.h>
kusano 7d535a
typedef  uint8_t BYTE;
kusano 7d535a
typedef uint16_t U16;
kusano 7d535a
typedef uint32_t U32;
kusano 7d535a
typedef  int32_t S32;
kusano 7d535a
typedef uint64_t U64;
kusano 7d535a
#else
kusano 7d535a
typedef unsigned char       BYTE;
kusano 7d535a
typedef unsigned short      U16;
kusano 7d535a
typedef unsigned int        U32;
kusano 7d535a
typedef   signed int        S32;
kusano 7d535a
typedef unsigned long long  U64;
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* unoptimized version; solves endianess & alignment issues */
kusano 7d535a
static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
kusano 7d535a
{
kusano 7d535a
    BYTE* dstPtr = (BYTE*)dstVoidPtr;
kusano 7d535a
    dstPtr[0] = (BYTE)value32;
kusano 7d535a
    dstPtr[1] = (BYTE)(value32 >> 8);
kusano 7d535a
    dstPtr[2] = (BYTE)(value32 >> 16);
kusano 7d535a
    dstPtr[3] = (BYTE)(value32 >> 24);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Constants
kusano 7d535a
**************************************/
kusano 7d535a
#ifndef LZ4_VERSION
kusano 7d535a
#  define LZ4_VERSION ""
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U
kusano 7d535a
kusano 7d535a
#define KB *(1U<<10)
kusano 7d535a
#define MB *(1U<<20)
kusano 7d535a
#define GB *(1U<<30)
kusano 7d535a
kusano 7d535a
static const U32 nbTestsDefault = 256 KB;
kusano 7d535a
#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
kusano 7d535a
#define FUZ_COMPRESSIBILITY_DEFAULT 50
kusano 7d535a
static const U32 prime1 = 2654435761U;
kusano 7d535a
static const U32 prime2 = 2246822519U;
kusano 7d535a
kusano 7d535a
kusano 7d535a
kusano 7d535a
/**************************************
kusano 7d535a
*  Macros
kusano 7d535a
**************************************/
kusano 7d535a
#define DISPLAY(...)          fprintf(stderr, __VA_ARGS__)
kusano 7d535a
#define DISPLAYLEVEL(l, ...)  if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
kusano 7d535a
#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
kusano 7d535a
            if ((FUZ_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
kusano 7d535a
            { g_time = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
kusano 7d535a
            if (displayLevel>=4) fflush(stdout); } }
kusano 7d535a
static const U32 refreshRate = 150;
kusano 7d535a
static U32 g_time = 0;
kusano 7d535a
kusano 7d535a
kusano 7d535a
/*****************************************
kusano 7d535a
*  Local Parameters
kusano 7d535a
*****************************************/
kusano 7d535a
static U32 no_prompt = 0;
kusano 7d535a
static char* programName;
kusano 7d535a
static U32 displayLevel = 2;
kusano 7d535a
static U32 pause = 0;
kusano 7d535a
kusano 7d535a
kusano 7d535a
/*********************************************************
kusano 7d535a
*  Fuzzer functions
kusano 7d535a
*********************************************************/
kusano 7d535a
#if defined(FUZ_LEGACY_TIMER)
kusano 7d535a
kusano 7d535a
static U32 FUZ_GetMilliStart(void)
kusano 7d535a
{
kusano 7d535a
    struct timeb tb;
kusano 7d535a
    U32 nCount;
kusano 7d535a
    ftime( &tb );
kusano 7d535a
    nCount = (U32) (((tb.time & 0xFFFFF) * 1000) +  tb.millitm);
kusano 7d535a
    return nCount;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#else
kusano 7d535a
kusano 7d535a
static U32 FUZ_GetMilliStart(void)
kusano 7d535a
{
kusano 7d535a
    struct timeval tv;
kusano 7d535a
    U32 nCount;
kusano 7d535a
    gettimeofday(&tv, NULL);
kusano 7d535a
    nCount = (U32) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
kusano 7d535a
    return nCount;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
kusano 7d535a
static U32 FUZ_GetMilliSpan(U32 nTimeStart)
kusano 7d535a
{
kusano 7d535a
    U32 nCurrent = FUZ_GetMilliStart();
kusano 7d535a
    U32 nSpan = nCurrent - nTimeStart;
kusano 7d535a
    if (nTimeStart > nCurrent)
kusano 7d535a
        nSpan += 0x100000 * 1000;
kusano 7d535a
    return nSpan;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
#  define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
kusano 7d535a
unsigned int FUZ_rand(unsigned int* src)
kusano 7d535a
{
kusano 7d535a
    U32 rand32 = *src;
kusano 7d535a
    rand32 *= prime1;
kusano 7d535a
    rand32 += prime2;
kusano 7d535a
    rand32  = FUZ_rotl32(rand32, 13);
kusano 7d535a
    *src = rand32;
kusano 7d535a
    return rand32 >> 5;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
#define FUZ_RAND15BITS  (FUZ_rand(seed) & 0x7FFF)
kusano 7d535a
#define FUZ_RANDLENGTH  ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
kusano 7d535a
static void FUZ_fillCompressibleNoiseBuffer(void* buffer, unsigned bufferSize, double proba, U32* seed)
kusano 7d535a
{
kusano 7d535a
    BYTE* BBuffer = (BYTE*)buffer;
kusano 7d535a
    unsigned pos = 0;
kusano 7d535a
    U32 P32 = (U32)(32768 * proba);
kusano 7d535a
kusano 7d535a
    /* First Byte */
kusano 7d535a
    BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
kusano 7d535a
kusano 7d535a
    while (pos < bufferSize)
kusano 7d535a
    {
kusano 7d535a
        /* Select : Literal (noise) or copy (within 64K) */
kusano 7d535a
        if (FUZ_RAND15BITS < P32)
kusano 7d535a
        {
kusano 7d535a
            /* Copy (within 64K) */
kusano 7d535a
            unsigned match, end;
kusano 7d535a
            unsigned length = FUZ_RANDLENGTH + 4;
kusano 7d535a
            unsigned offset = FUZ_RAND15BITS + 1;
kusano 7d535a
            if (offset > pos) offset = pos;
kusano 7d535a
            if (pos + length > bufferSize) length = bufferSize - pos;
kusano 7d535a
            match = pos - offset;
kusano 7d535a
            end = pos + length;
kusano 7d535a
            while (pos < end) BBuffer[pos++] = BBuffer[match++];
kusano 7d535a
        }
kusano 7d535a
        else
kusano 7d535a
        {
kusano 7d535a
            /* Literal (noise) */
kusano 7d535a
            unsigned end;
kusano 7d535a
            unsigned length = FUZ_RANDLENGTH;
kusano 7d535a
            if (pos + length > bufferSize) length = bufferSize - pos;
kusano 7d535a
            end = pos + length;
kusano 7d535a
            while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
kusano 7d535a
        }
kusano 7d535a
    }
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static unsigned FUZ_highbit(U32 v32)
kusano 7d535a
{
kusano 7d535a
    unsigned nbBits = 0;
kusano 7d535a
    if (v32==0) return 0;
kusano 7d535a
    while (v32)
kusano 7d535a
    {
kusano 7d535a
        v32 >>= 1;
kusano 7d535a
        nbBits ++;
kusano 7d535a
    }
kusano 7d535a
    return nbBits;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
int basicTests(U32 seed, double compressibility)
kusano 7d535a
{
kusano 7d535a
    int testResult = 0;
kusano 7d535a
    void* CNBuffer;
kusano 7d535a
    void* compressedBuffer;
kusano 7d535a
    void* decodedBuffer;
kusano 7d535a
    U32 randState = seed;
kusano 7d535a
    size_t cSize, testSize;
kusano 7d535a
    LZ4F_preferences_t prefs;
kusano 7d535a
    LZ4F_decompressionContext_t dCtx = NULL;
kusano 7d535a
    LZ4F_compressionContext_t cctx = NULL;
kusano 7d535a
    U64 crcOrig;
kusano 7d535a
kusano 7d535a
    /* Create compressible test buffer */
kusano 7d535a
    memset(&prefs, 0, sizeof(prefs));
kusano 7d535a
    CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
kusano 7d535a
    compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
kusano 7d535a
    decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
kusano 7d535a
    FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
kusano 7d535a
    crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
kusano 7d535a
kusano 7d535a
    /* Trivial tests : one-step frame */
kusano 7d535a
    testSize = COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
    DISPLAYLEVEL(3, "Using NULL preferences : \n");
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Decompression test : \n");
kusano 7d535a
    {
kusano 7d535a
        size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
        size_t compressedBufferSize = cSize;
kusano 7d535a
        BYTE* op = (BYTE*)decodedBuffer;
kusano 7d535a
        BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
        BYTE* ip = (BYTE*)compressedBuffer;
kusano 7d535a
        BYTE* const iend = (BYTE*)compressedBuffer + cSize;
kusano 7d535a
        U64 crcDest;
kusano 7d535a
kusano 7d535a
        LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "Single Block : \n");
kusano 7d535a
        errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
kusano 7d535a
        if (crcDest != crcOrig) goto _output_error;
kusano 7d535a
        DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(4, "Reusing decompression context \n");
kusano 7d535a
        {
kusano 7d535a
            size_t iSize = compressedBufferSize - 4;
kusano 7d535a
            const BYTE* cBuff = (const BYTE*) compressedBuffer;
kusano 7d535a
            DISPLAYLEVEL(3, "Missing last 4 bytes : ");
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, cBuff, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            if (!errorCode) goto _output_error;
kusano 7d535a
            DISPLAYLEVEL(3, "indeed, request %u bytes \n", (unsigned)errorCode);
kusano 7d535a
            cBuff += iSize;
kusano 7d535a
            iSize = errorCode;
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, cBuff, &iSize, NULL);
kusano 7d535a
            if (errorCode != 0) goto _output_error;
kusano 7d535a
            crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
kusano 7d535a
            if (crcDest != crcOrig) goto _output_error;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        {
kusano 7d535a
            size_t oSize = 0;
kusano 7d535a
            size_t iSize = 0;
kusano 7d535a
            LZ4F_frameInfo_t fi;
kusano 7d535a
kusano 7d535a
            DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            DISPLAYLEVEL(3, " %u  \n", (unsigned)errorCode);
kusano 7d535a
kusano 7d535a
            DISPLAYLEVEL(3, "get FrameInfo on null input : ");
kusano 7d535a
            errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize);
kusano 7d535a
            if (errorCode != (size_t)-LZ4F_ERROR_frameHeader_incomplete) goto _output_error;
kusano 7d535a
            DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode));
kusano 7d535a
kusano 7d535a
            DISPLAYLEVEL(3, "get FrameInfo on not enough input : ");
kusano 7d535a
            iSize = 6;
kusano 7d535a
            errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize);
kusano 7d535a
            if (errorCode != (size_t)-LZ4F_ERROR_frameHeader_incomplete) goto _output_error;
kusano 7d535a
            DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode));
kusano 7d535a
            ip += iSize;
kusano 7d535a
kusano 7d535a
            DISPLAYLEVEL(3, "get FrameInfo on enough input : ");
kusano 7d535a
            iSize = 15 - iSize;
kusano 7d535a
            errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            DISPLAYLEVEL(3, " correctly decoded \n");
kusano 7d535a
            ip += iSize;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "Byte after byte : \n");
kusano 7d535a
        while (ip < iend)
kusano 7d535a
        {
kusano 7d535a
            size_t oSize = oend-op;
kusano 7d535a
            size_t iSize = 1;
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            op += oSize;
kusano 7d535a
            ip += iSize;
kusano 7d535a
        }
kusano 7d535a
        crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
kusano 7d535a
        if (crcDest != crcOrig) goto _output_error;
kusano 7d535a
        DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-(BYTE*)decodedBuffer), COMPRESSIBLE_NOISE_LENGTH);
kusano 7d535a
kusano 7d535a
        errorCode = LZ4F_freeDecompressionContext(dCtx);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Using 64 KB block : \n");
kusano 7d535a
    prefs.frameInfo.blockSizeID = LZ4F_max64KB;
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "without checksum : \n");
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Using 256 KB block : \n");
kusano 7d535a
    prefs.frameInfo.blockSizeID = LZ4F_max256KB;
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Decompression test : \n");
kusano 7d535a
    {
kusano 7d535a
        size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
        unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
kusano 7d535a
        BYTE* op = (BYTE*)decodedBuffer;
kusano 7d535a
        BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
        BYTE* ip = (BYTE*)compressedBuffer;
kusano 7d535a
        BYTE* const iend = (BYTE*)compressedBuffer + cSize;
kusano 7d535a
        U64 crcDest;
kusano 7d535a
kusano 7d535a
        LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "random segment sizes : \n");
kusano 7d535a
        while (ip < iend)
kusano 7d535a
        {
kusano 7d535a
            unsigned nbBits = FUZ_rand(&randState) % maxBits;
kusano 7d535a
            size_t iSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
            size_t oSize = oend-op;
kusano 7d535a
            if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
kusano 7d535a
            //DISPLAY("%7i : + %6i\n", (int)(ip-(BYTE*)compressedBuffer), (int)iSize);
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            op += oSize;
kusano 7d535a
            ip += iSize;
kusano 7d535a
        }
kusano 7d535a
        crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
kusano 7d535a
        if (crcDest != crcOrig) goto _output_error;
kusano 7d535a
        DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
kusano 7d535a
kusano 7d535a
        errorCode = LZ4F_freeDecompressionContext(dCtx);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "without checksum : \n");
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Using 1 MB block : \n");
kusano 7d535a
    prefs.frameInfo.blockSizeID = LZ4F_max1MB;
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "without checksum : \n");
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Using 4 MB block : \n");
kusano 7d535a
    prefs.frameInfo.blockSizeID = LZ4F_max4MB;
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "without checksum : \n");
kusano 7d535a
    prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
kusano 7d535a
    cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
kusano 7d535a
    if (LZ4F_isError(cSize)) goto _output_error;
kusano 7d535a
    DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
kusano 7d535a
kusano 7d535a
    {
kusano 7d535a
        size_t errorCode;
kusano 7d535a
        BYTE* const ostart = (BYTE*)compressedBuffer;
kusano 7d535a
        BYTE* op = ostart;
kusano 7d535a
        errorCode = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "compress without frameSize : \n");
kusano 7d535a
        memset(&(prefs.frameInfo), 0, sizeof(prefs.frameInfo));
kusano 7d535a
        errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        op += errorCode;
kusano 7d535a
        errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        op += errorCode;
kusano 7d535a
        errorCode = LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "compress with frameSize : \n");
kusano 7d535a
        prefs.frameInfo.contentSize = testSize;
kusano 7d535a
        op = ostart;
kusano 7d535a
        errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        op += errorCode;
kusano 7d535a
        errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        op += errorCode;
kusano 7d535a
        errorCode = LZ4F_compressEnd(cctx, compressedBuffer, testSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)(op-ostart));
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "compress with wrong frameSize : \n");
kusano 7d535a
        prefs.frameInfo.contentSize = testSize+1;
kusano 7d535a
        op = ostart;
kusano 7d535a
        errorCode = LZ4F_compressBegin(cctx, compressedBuffer, testSize, &prefs);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        op += errorCode;
kusano 7d535a
        errorCode = LZ4F_compressUpdate(cctx, op, LZ4F_compressBound(testSize, &prefs), CNBuffer, testSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        op += errorCode;
kusano 7d535a
        errorCode = LZ4F_compressEnd(cctx, op, testSize, NULL);
kusano 7d535a
        if (LZ4F_isError(errorCode)) { DISPLAYLEVEL(3, "Error correctly detected : %s \n", LZ4F_getErrorName(errorCode)); }
kusano 7d535a
        else
kusano 7d535a
            goto _output_error;
kusano 7d535a
kusano 7d535a
        errorCode = LZ4F_freeCompressionContext(cctx);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
        cctx = NULL;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(3, "Skippable frame test : \n");
kusano 7d535a
    {
kusano 7d535a
        size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
        unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
kusano 7d535a
        BYTE* op = (BYTE*)decodedBuffer;
kusano 7d535a
        BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
kusano 7d535a
        BYTE* ip = (BYTE*)compressedBuffer;
kusano 7d535a
        BYTE* iend = (BYTE*)compressedBuffer + cSize + 8;
kusano 7d535a
kusano 7d535a
        LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
kusano 7d535a
        if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
kusano 7d535a
        /* generate skippable frame */
kusano 7d535a
        FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START);
kusano 7d535a
        FUZ_writeLE32(ip+4, (U32)cSize);
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "random segment sizes : \n");
kusano 7d535a
        while (ip < iend)
kusano 7d535a
        {
kusano 7d535a
            unsigned nbBits = FUZ_rand(&randState) % maxBits;
kusano 7d535a
            size_t iSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
            size_t oSize = oend-op;
kusano 7d535a
            if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            op += oSize;
kusano 7d535a
            ip += iSize;
kusano 7d535a
        }
kusano 7d535a
        DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)decodedBufferSize);
kusano 7d535a
kusano 7d535a
        /* generate zero-size skippable frame */
kusano 7d535a
        DISPLAYLEVEL(3, "zero-size skippable frame\n");
kusano 7d535a
        ip = (BYTE*)compressedBuffer;
kusano 7d535a
        op = (BYTE*)decodedBuffer;
kusano 7d535a
        FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+1);
kusano 7d535a
        FUZ_writeLE32(ip+4, 0);
kusano 7d535a
        iend = ip+8;
kusano 7d535a
kusano 7d535a
        while (ip < iend)
kusano 7d535a
        {
kusano 7d535a
            unsigned nbBits = FUZ_rand(&randState) % maxBits;
kusano 7d535a
            size_t iSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
            size_t oSize = oend-op;
kusano 7d535a
            if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            op += oSize;
kusano 7d535a
            ip += iSize;
kusano 7d535a
        }
kusano 7d535a
        DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
kusano 7d535a
kusano 7d535a
        DISPLAYLEVEL(3, "Skippable frame header complete in first call \n");
kusano 7d535a
        ip = (BYTE*)compressedBuffer;
kusano 7d535a
        op = (BYTE*)decodedBuffer;
kusano 7d535a
        FUZ_writeLE32(ip, LZ4F_MAGIC_SKIPPABLE_START+2);
kusano 7d535a
        FUZ_writeLE32(ip+4, 10);
kusano 7d535a
        iend = ip+18;
kusano 7d535a
        while (ip < iend)
kusano 7d535a
        {
kusano 7d535a
            size_t iSize = 10;
kusano 7d535a
            size_t oSize = 10;
kusano 7d535a
            if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
kusano 7d535a
            errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
kusano 7d535a
            if (LZ4F_isError(errorCode)) goto _output_error;
kusano 7d535a
            op += oSize;
kusano 7d535a
            ip += iSize;
kusano 7d535a
        }
kusano 7d535a
        DISPLAYLEVEL(3, "Skipped %i bytes \n", (int)(ip - (BYTE*)compressedBuffer - 8));
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    DISPLAY("Basic tests completed \n");
kusano 7d535a
_end:
kusano 7d535a
    free(CNBuffer);
kusano 7d535a
    free(compressedBuffer);
kusano 7d535a
    free(decodedBuffer);
kusano 7d535a
    LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
kusano 7d535a
    LZ4F_freeCompressionContext(cctx); cctx = NULL;
kusano 7d535a
    return testResult;
kusano 7d535a
kusano 7d535a
_output_error:
kusano 7d535a
    testResult = 1;
kusano 7d535a
    DISPLAY("Error detected ! \n");
kusano 7d535a
    goto _end;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
kusano 7d535a
{
kusano 7d535a
    int p=0;
kusano 7d535a
    const BYTE* b1=(const BYTE*)buff1;
kusano 7d535a
    const BYTE* b2=(const BYTE*)buff2;
kusano 7d535a
    if (nonContiguous)
kusano 7d535a
    {
kusano 7d535a
        DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size);
kusano 7d535a
        return;
kusano 7d535a
    }
kusano 7d535a
    while (b1[p]==b2[p]) p++;
kusano 7d535a
    DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static const U32 srcDataLength = 9 MB;  /* needs to be > 2x4MB to test large blocks */
kusano 7d535a
kusano 7d535a
int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration)
kusano 7d535a
{
kusano 7d535a
    unsigned testResult = 0;
kusano 7d535a
    unsigned testNb = 0;
kusano 7d535a
    void* srcBuffer = NULL;
kusano 7d535a
    void* compressedBuffer = NULL;
kusano 7d535a
    void* decodedBuffer = NULL;
kusano 7d535a
    U32 coreRand = seed;
kusano 7d535a
    LZ4F_decompressionContext_t dCtx = NULL;
kusano 7d535a
    LZ4F_compressionContext_t cCtx = NULL;
kusano 7d535a
    size_t result;
kusano 7d535a
    const U32 startTime = FUZ_GetMilliStart();
kusano 7d535a
    XXH64_state_t xxh64;
kusano 7d535a
#   define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
kusano 7d535a
                            DISPLAY(" (seed %u, test nb %u)  \n", seed, testNb); goto _output_error; }
kusano 7d535a
kusano 7d535a
kusano 7d535a
    /* Init */
kusano 7d535a
    duration *= 1000;
kusano 7d535a
kusano 7d535a
    /* Create buffers */
kusano 7d535a
    result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
kusano 7d535a
    CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
kusano 7d535a
    result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
kusano 7d535a
    CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
kusano 7d535a
    srcBuffer = malloc(srcDataLength);
kusano 7d535a
    CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
kusano 7d535a
    compressedBuffer = malloc(LZ4F_compressFrameBound(srcDataLength, NULL));
kusano 7d535a
    CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
kusano 7d535a
    decodedBuffer = calloc(1, srcDataLength);   /* calloc avoids decodedBuffer being considered "garbage" by scan-build */
kusano 7d535a
    CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
kusano 7d535a
    FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
kusano 7d535a
kusano 7d535a
    /* jump to requested testNb */
kusano 7d535a
    for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand);   // sync randomizer
kusano 7d535a
kusano 7d535a
    /* main fuzzer test loop */
kusano 7d535a
    for ( ; (testNb < nbTests) || (duration > FUZ_GetMilliSpan(startTime)) ; testNb++)
kusano 7d535a
    {
kusano 7d535a
        U32 randState = coreRand ^ prime1;
kusano 7d535a
        unsigned BSId   = 4 + (FUZ_rand(&randState) & 3);
kusano 7d535a
        unsigned BMId   = FUZ_rand(&randState) & 1;
kusano 7d535a
        unsigned CCflag = FUZ_rand(&randState) & 1;
kusano 7d535a
        unsigned autoflush = (FUZ_rand(&randState) & 7) == 2;
kusano 7d535a
        LZ4F_preferences_t prefs;
kusano 7d535a
        LZ4F_compressOptions_t cOptions;
kusano 7d535a
        LZ4F_decompressOptions_t dOptions;
kusano 7d535a
        unsigned nbBits = (FUZ_rand(&randState) % (FUZ_highbit(srcDataLength-1) - 1)) + 1;
kusano 7d535a
        size_t srcSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
        size_t srcStart = FUZ_rand(&randState) % (srcDataLength - srcSize);
kusano 7d535a
        U64 frameContentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0;
kusano 7d535a
        size_t cSize;
kusano 7d535a
        U64 crcOrig, crcDecoded;
kusano 7d535a
        LZ4F_preferences_t* prefsPtr = &prefs;
kusano 7d535a
kusano 7d535a
        (void)FUZ_rand(&coreRand);   /* update seed */
kusano 7d535a
        memset(&prefs, 0, sizeof(prefs));
kusano 7d535a
        memset(&cOptions, 0, sizeof(cOptions));
kusano 7d535a
        memset(&dOptions, 0, sizeof(dOptions));
kusano 7d535a
        prefs.frameInfo.blockMode = (LZ4F_blockMode_t)BMId;
kusano 7d535a
        prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)BSId;
kusano 7d535a
        prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)CCflag;
kusano 7d535a
        prefs.frameInfo.contentSize = frameContentSize;
kusano 7d535a
        prefs.autoFlush = autoflush;
kusano 7d535a
        prefs.compressionLevel = FUZ_rand(&randState) % 5;
kusano 7d535a
        if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL;
kusano 7d535a
kusano 7d535a
        DISPLAYUPDATE(2, "\r%5u   ", testNb);
kusano 7d535a
        crcOrig = XXH64((BYTE*)srcBuffer+srcStart, srcSize, 1);
kusano 7d535a
kusano 7d535a
        if ((FUZ_rand(&randState) & 0xFFF) == 0)
kusano 7d535a
        {
kusano 7d535a
            /* create a skippable frame (rare case) */
kusano 7d535a
            BYTE* op = (BYTE*)compressedBuffer;
kusano 7d535a
            FUZ_writeLE32(op, LZ4F_MAGIC_SKIPPABLE_START + (FUZ_rand(&randState) & 15));
kusano 7d535a
            FUZ_writeLE32(op+4, (U32)srcSize);
kusano 7d535a
            cSize = srcSize+8;
kusano 7d535a
        }
kusano 7d535a
        else if ((FUZ_rand(&randState) & 0xF) == 2)
kusano 7d535a
        {
kusano 7d535a
            cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), (char*)srcBuffer + srcStart, srcSize, prefsPtr);
kusano 7d535a
            CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
kusano 7d535a
        }
kusano 7d535a
        else
kusano 7d535a
        {
kusano 7d535a
            const BYTE* ip = (const BYTE*)srcBuffer + srcStart;
kusano 7d535a
            const BYTE* const iend = ip + srcSize;
kusano 7d535a
            BYTE* op = (BYTE*)compressedBuffer;
kusano 7d535a
            BYTE* const oend = op + LZ4F_compressFrameBound(srcDataLength, NULL);
kusano 7d535a
            unsigned maxBits = FUZ_highbit((U32)srcSize);
kusano 7d535a
            result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr);
kusano 7d535a
            CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
kusano 7d535a
            op += result;
kusano 7d535a
            while (ip < iend)
kusano 7d535a
            {
kusano 7d535a
                unsigned nbBitsSeg = FUZ_rand(&randState) % maxBits;
kusano 7d535a
                size_t iSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
                size_t oSize = LZ4F_compressBound(iSize, prefsPtr);
kusano 7d535a
                unsigned forceFlush = ((FUZ_rand(&randState) & 3) == 1);
kusano 7d535a
                if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
kusano 7d535a
                cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
kusano 7d535a
kusano 7d535a
                result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
kusano 7d535a
                CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
kusano 7d535a
                op += result;
kusano 7d535a
                ip += iSize;
kusano 7d535a
kusano 7d535a
                if (forceFlush)
kusano 7d535a
                {
kusano 7d535a
                    result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
kusano 7d535a
                    CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
kusano 7d535a
                    op += result;
kusano 7d535a
                }
kusano 7d535a
            }
kusano 7d535a
            result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
kusano 7d535a
            CHECK(LZ4F_isError(result), "Compression completion failed (error %i)", (int)result);
kusano 7d535a
            op += result;
kusano 7d535a
            cSize = op-(BYTE*)compressedBuffer;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        {
kusano 7d535a
            const BYTE* ip = (const BYTE*)compressedBuffer;
kusano 7d535a
            const BYTE* const iend = ip + cSize;
kusano 7d535a
            BYTE* op = (BYTE*)decodedBuffer;
kusano 7d535a
            BYTE* const oend = op + srcDataLength;
kusano 7d535a
            size_t totalOut = 0;
kusano 7d535a
            unsigned maxBits = FUZ_highbit((U32)cSize);
kusano 7d535a
            unsigned nonContiguousDst = (FUZ_rand(&randState) & 3) == 1;
kusano 7d535a
            nonContiguousDst += FUZ_rand(&randState) & nonContiguousDst;   /* 0=>0; 1=>1,2 */
kusano 7d535a
            XXH64_reset(&xxh64, 1);
kusano 7d535a
            if (maxBits < 3) maxBits = 3;
kusano 7d535a
            while (ip < iend)
kusano 7d535a
            {
kusano 7d535a
                unsigned nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
kusano 7d535a
                unsigned nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
kusano 7d535a
                size_t iSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
                size_t oSize = (FUZ_rand(&randState) & ((1<
kusano 7d535a
                if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
kusano 7d535a
                if (oSize > (size_t)(oend-op)) oSize = oend-op;
kusano 7d535a
                dOptions.stableDst = FUZ_rand(&randState) & 1;
kusano 7d535a
                if (nonContiguousDst==2) dOptions.stableDst = 0;
kusano 7d535a
                result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
kusano 7d535a
                if (result == (size_t)-LZ4F_ERROR_contentChecksum_invalid)
kusano 7d535a
                    locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
kusano 7d535a
                CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName((LZ4F_errorCode_t)result));
kusano 7d535a
                XXH64_update(&xxh64, op, (U32)oSize);
kusano 7d535a
                totalOut += oSize;
kusano 7d535a
                op += oSize;
kusano 7d535a
                ip += iSize;
kusano 7d535a
                op += nonContiguousDst;
kusano 7d535a
                if (nonContiguousDst==2) op = (BYTE*)decodedBuffer;   /* overwritten destination */
kusano 7d535a
            }
kusano 7d535a
            CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
kusano 7d535a
            if (totalOut)   /* otherwise, it's a skippable frame */
kusano 7d535a
            {
kusano 7d535a
                crcDecoded = XXH64_digest(&xxh64);
kusano 7d535a
                if (crcDecoded != crcOrig) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
kusano 7d535a
                CHECK(crcDecoded != crcOrig, "Decompression corruption");
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    DISPLAYLEVEL(2, "\rAll tests completed   \n");
kusano 7d535a
kusano 7d535a
_end:
kusano 7d535a
    LZ4F_freeDecompressionContext(dCtx);
kusano 7d535a
    LZ4F_freeCompressionContext(cCtx);
kusano 7d535a
    free(srcBuffer);
kusano 7d535a
    free(compressedBuffer);
kusano 7d535a
    free(decodedBuffer);
kusano 7d535a
kusano 7d535a
    if (pause)
kusano 7d535a
    {
kusano 7d535a
        DISPLAY("press enter to finish \n");
kusano 7d535a
        (void)getchar();
kusano 7d535a
    }
kusano 7d535a
    return testResult;
kusano 7d535a
kusano 7d535a
_output_error:
kusano 7d535a
    testResult = 1;
kusano 7d535a
    goto _end;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
int FUZ_usage(void)
kusano 7d535a
{
kusano 7d535a
    DISPLAY( "Usage :\n");
kusano 7d535a
    DISPLAY( "      %s [args]\n", programName);
kusano 7d535a
    DISPLAY( "\n");
kusano 7d535a
    DISPLAY( "Arguments :\n");
kusano 7d535a
    DISPLAY( " -i#    : Nb of tests (default:%u) \n", nbTestsDefault);
kusano 7d535a
    DISPLAY( " -T#    : Duration of tests, in seconds (default: use Nb of tests) \n");
kusano 7d535a
    DISPLAY( " -s#    : Select seed (default:prompt user)\n");
kusano 7d535a
    DISPLAY( " -t#    : Select starting test number (default:0)\n");
kusano 7d535a
    DISPLAY( " -p#    : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
kusano 7d535a
    DISPLAY( " -v     : verbose\n");
kusano 7d535a
    DISPLAY( " -h     : display help and exit\n");
kusano 7d535a
    return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
int main(int argc, char** argv)
kusano 7d535a
{
kusano 7d535a
    U32 seed=0;
kusano 7d535a
    int seedset=0;
kusano 7d535a
    int argNb;
kusano 7d535a
    int nbTests = nbTestsDefault;
kusano 7d535a
    int testNb = 0;
kusano 7d535a
    int proba = FUZ_COMPRESSIBILITY_DEFAULT;
kusano 7d535a
    int result=0;
kusano 7d535a
    U32 duration=0;
kusano 7d535a
kusano 7d535a
    /* Check command line */
kusano 7d535a
    programName = argv[0];
kusano 7d535a
    for(argNb=1; argNb
kusano 7d535a
    {
kusano 7d535a
        char* argument = argv[argNb];
kusano 7d535a
kusano 7d535a
        if(!argument) continue;   /* Protection if argument empty */
kusano 7d535a
kusano 7d535a
        /* Decode command (note : aggregated commands are allowed) */
kusano 7d535a
        if (argument[0]=='-')
kusano 7d535a
        {
kusano 7d535a
            if (!strcmp(argument, "--no-prompt"))
kusano 7d535a
            {
kusano 7d535a
                no_prompt=1;
kusano 7d535a
                seedset=1;
kusano 7d535a
                displayLevel=1;
kusano 7d535a
                continue;
kusano 7d535a
            }
kusano 7d535a
            argument++;
kusano 7d535a
kusano 7d535a
            while (*argument!=0)
kusano 7d535a
            {
kusano 7d535a
                switch(*argument)
kusano 7d535a
                {
kusano 7d535a
                case 'h':
kusano 7d535a
                    return FUZ_usage();
kusano 7d535a
                case 'v':
kusano 7d535a
                    argument++;
kusano 7d535a
                    displayLevel=4;
kusano 7d535a
                    break;
kusano 7d535a
                case 'q':
kusano 7d535a
                    argument++;
kusano 7d535a
                    displayLevel--;
kusano 7d535a
                    break;
kusano 7d535a
                case 'p': /* pause at the end */
kusano 7d535a
                    argument++;
kusano 7d535a
                    pause = 1;
kusano 7d535a
                    break;
kusano 7d535a
kusano 7d535a
                case 'i':
kusano 7d535a
                    argument++;
kusano 7d535a
                    nbTests=0; duration=0;
kusano 7d535a
                    while ((*argument>='0') && (*argument<='9'))
kusano 7d535a
                    {
kusano 7d535a
                        nbTests *= 10;
kusano 7d535a
                        nbTests += *argument - '0';
kusano 7d535a
                        argument++;
kusano 7d535a
                    }
kusano 7d535a
                    break;
kusano 7d535a
kusano 7d535a
                case 'T':
kusano 7d535a
                    argument++;
kusano 7d535a
                    nbTests = 0; duration = 0;
kusano 7d535a
                    for (;;)
kusano 7d535a
                    {
kusano 7d535a
                        switch(*argument)
kusano 7d535a
                        {
kusano 7d535a
                            case 'm': duration *= 60; argument++; continue;
kusano 7d535a
                            case 's':
kusano 7d535a
                            case 'n': argument++; continue;
kusano 7d535a
                            case '0':
kusano 7d535a
                            case '1':
kusano 7d535a
                            case '2':
kusano 7d535a
                            case '3':
kusano 7d535a
                            case '4':
kusano 7d535a
                            case '5':
kusano 7d535a
                            case '6':
kusano 7d535a
                            case '7':
kusano 7d535a
                            case '8':
kusano 7d535a
                            case '9': duration *= 10; duration += *argument++ - '0'; continue;
kusano 7d535a
                        }
kusano 7d535a
                        break;
kusano 7d535a
                    }
kusano 7d535a
                    break;
kusano 7d535a
kusano 7d535a
                case 's':
kusano 7d535a
                    argument++;
kusano 7d535a
                    seed=0;
kusano 7d535a
                    seedset=1;
kusano 7d535a
                    while ((*argument>='0') && (*argument<='9'))
kusano 7d535a
                    {
kusano 7d535a
                        seed *= 10;
kusano 7d535a
                        seed += *argument - '0';
kusano 7d535a
                        argument++;
kusano 7d535a
                    }
kusano 7d535a
                    break;
kusano 7d535a
                case 't':
kusano 7d535a
                    argument++;
kusano 7d535a
                    testNb=0;
kusano 7d535a
                    while ((*argument>='0') && (*argument<='9'))
kusano 7d535a
                    {
kusano 7d535a
                        testNb *= 10;
kusano 7d535a
                        testNb += *argument - '0';
kusano 7d535a
                        argument++;
kusano 7d535a
                    }
kusano 7d535a
                    break;
kusano 7d535a
                case 'P':   /* compressibility % */
kusano 7d535a
                    argument++;
kusano 7d535a
                    proba=0;
kusano 7d535a
                    while ((*argument>='0') && (*argument<='9'))
kusano 7d535a
                    {
kusano 7d535a
                        proba *= 10;
kusano 7d535a
                        proba += *argument - '0';
kusano 7d535a
                        argument++;
kusano 7d535a
                    }
kusano 7d535a
                    if (proba<0) proba=0;
kusano 7d535a
                    if (proba>100) proba=100;
kusano 7d535a
                    break;
kusano 7d535a
                default:
kusano 7d535a
                    ;
kusano 7d535a
                    return FUZ_usage();
kusano 7d535a
                }
kusano 7d535a
            }
kusano 7d535a
        }
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* Get Seed */
kusano 7d535a
    printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
kusano 7d535a
kusano 7d535a
    if (!seedset) seed = FUZ_GetMilliStart() % 10000;
kusano 7d535a
    printf("Seed = %u\n", seed);
kusano 7d535a
    if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
kusano 7d535a
kusano 7d535a
    if (nbTests<=0) nbTests=1;
kusano 7d535a
kusano 7d535a
    if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
kusano 7d535a
    if (result) return 1;
kusano 7d535a
    return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100, duration);
kusano 7d535a
}