diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c index 1abc7df8b71..f25e5dc7c00 100644 --- a/tests/decodecorpus.c +++ b/tests/decodecorpus.c @@ -247,6 +247,12 @@ typedef enum { #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif +typedef enum { + lt_raw, + lt_rle, + lt_compressed, +} literalType_e; + /*-******************************************************* * Global variables (set from command line) *********************************************************/ @@ -259,7 +265,11 @@ U32 g_maxBlockSize = ZSTD_BLOCKSIZE_MAX; /* <= 128 KB */ struct { int contentSize; /* force the content size to be present */ -} opts; /* advanced options on generation */ + blockType_e *blockType; /* force specific block type */ + literalType_e *literalType; /* force specific literals type */ + int frame_header_only; /* generate only frame header */ + int no_magic; /* do not generate magic number */ +} opts; /* Generate and write a random frame header */ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) @@ -288,10 +298,19 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) { /* Generate random content size */ + int force_block_type = opts.blockType != NULL; size_t highBit; if (RAND(seed) & 7 && g_maxDecompressedSizeLog > 7) { /* do content of at least 128 bytes */ highBit = 1ULL << RAND_range(seed, 7, g_maxDecompressedSizeLog); + } else if (force_block_type) { + if ((RAND(seed) & 3) || (*(opts.blockType) == bt_rle)) { + /* do small content */ + highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1U << g_maxDecompressedSizeLog)); + } else { + /* 0 size frame */ + highBit = 0; + } } else if (RAND(seed) & 3) { /* do small content */ highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1U << g_maxDecompressedSizeLog)); @@ -324,8 +343,10 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) } /* write out the header */ - MEM_writeLE32(op + pos, ZSTD_MAGICNUMBER); - pos += 4; + if (!opts.no_magic) { + MEM_writeLE32(op + pos, ZSTD_MAGICNUMBER); + pos += 4; + } { /* @@ -370,8 +391,10 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) /* Write a literal block in either raw or RLE form, return the literals size */ static size_t writeLiteralsBlockSimple(U32* seed, frame_t* frame, size_t contentSize) { + int force_literal_type = opts.literalType != NULL; + int const type = (force_literal_type) ? *(opts.literalType) : RAND(seed) % 2; + BYTE* op = (BYTE*)frame->data; - int const type = RAND(seed) % 2; int const sizeFormatDesc = RAND(seed) % 8; size_t litSize; size_t maxLitSize = MIN(contentSize, g_maxBlockSize); @@ -619,8 +642,15 @@ static size_t writeLiteralsBlockCompressed(U32* seed, frame_t* frame, size_t con static size_t writeLiteralsBlock(U32* seed, frame_t* frame, size_t contentSize) { - /* only do compressed for larger segments to avoid compressibility issues */ - if (RAND(seed) & 7 && contentSize >= 64) { + int select_compressed = 0; + if (opts.literalType) { + select_compressed = *(opts.literalType) == lt_compressed; + } else { + /* only do compressed for larger segments to avoid compressibility issues */ + select_compressed = RAND(seed) & 7 && contentSize >= 64; + } + + if (select_compressed) { return writeLiteralsBlockCompressed(seed, frame, contentSize); } else { return writeLiteralsBlockSimple(seed, frame, contentSize); @@ -1034,7 +1064,8 @@ static size_t writeCompressedBlock(U32* seed, frame_t* frame, size_t contentSize static void writeBlock(U32* seed, frame_t* frame, size_t contentSize, int lastBlock, dictInfo info) { - int const blockTypeDesc = RAND(seed) % 8; + int force_block_type = opts.blockType != NULL; + int const blockTypeDesc = (force_block_type) ? *(opts.blockType) : RAND(seed) % 8; size_t blockSize; int blockType; @@ -1073,7 +1104,7 @@ static void writeBlock(U32* seed, frame_t* frame, size_t contentSize, frame->data = op; compressedSize = writeCompressedBlock(seed, frame, contentSize, info); - if (compressedSize >= contentSize) { /* compressed block must be strictly smaller than uncompressed one */ + if (compressedSize >= contentSize && !force_block_type) { /* compressed block must be strictly smaller than uncompressed one */ blockType = 0; memcpy(op, frame->src, contentSize); @@ -1244,7 +1275,11 @@ static U32 generateFrame(U32 seed, frame_t* fr, dictInfo info) DISPLAYLEVEL(3, "frame seed: %u\n", (unsigned)seed); initFrame(fr); + writeFrameHeader(&seed, fr, info); + if (opts.frame_header_only) + return seed; + writeBlocks(&seed, fr, info); writeChecksum(fr); @@ -1772,6 +1807,9 @@ static void advancedUsage(const char* programName) DISPLAY( " --max-block-size-log=# : max block size log, must be in range [2, 17]\n"); DISPLAY( " --max-content-size-log=# : max content size log, must be <= 20\n"); DISPLAY( " (this is ignored with gen-blocks)\n"); + DISPLAY( " --block-type=# : force certain block type (raw=0, rle=1, compressed=2)\n"); + DISPLAY( " --frame-header-only : dump only frame header\n"); + DISPLAY( " --no-magic : do not add magic number\n"); } /*! readU32FromChar() : @@ -1893,6 +1931,18 @@ int main(int argc, char** argv) U32 value = readU32FromChar(&argument); g_maxDecompressedSizeLog = MIN(MAX_DECOMPRESSED_SIZE_LOG, value); + } else if (longCommandWArg(&argument, "block-type=")) { + U32 value = readU32FromChar(&argument); + opts.blockType = malloc(sizeof(blockType_e)); + *(opts.blockType) = value; + } else if (longCommandWArg(&argument, "literal-type=")) { + U32 value = readU32FromChar(&argument); + opts.literalType = malloc(sizeof(literalType_e)); + *(opts.literalType) = value; + } else if (strcmp(argument, "frame-header-only") == 0) { + opts.frame_header_only = 1; + } else if (strcmp(argument, "no-magic") == 0) { + opts.no_magic = 1; } else { advancedUsage(argv[0]); return 1; @@ -1904,6 +1954,18 @@ int main(int argc, char** argv) return 1; } } } } /* for (argNb=1; argNb