2 * Copyright (c) 2017-present, Yann Collet, Facebook, Inc.
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
20 #include "zstd_internal.h"
22 #define ZDICT_STATIC_LINKING_ONLY
25 // Direct access to internal compression functions is required
26 #include "zstd_compress.c"
28 #define XXH_STATIC_LINKING_ONLY
29 #include "xxhash.h" /* XXH64 */
32 #define MIN(a, b) ((a) < (b) ? (a) : (b))
37 #define MAX_PATH PATH_MAX
43 /*-************************************
45 **************************************/
46 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
47 #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
48 static U32 g_displayLevel = 2;
50 #define DISPLAYUPDATE(...) \
52 if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || \
53 (g_displayLevel >= 4)) { \
54 g_displayClock = UTIL_getTime(); \
55 DISPLAY(__VA_ARGS__); \
56 if (g_displayLevel >= 4) fflush(stderr); \
60 static const U64 g_refreshRate = SEC_TO_MICRO / 6;
61 static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
63 #define CHECKERR(code) \
65 if (ZSTD_isError(code)) { \
66 DISPLAY("Error occurred while generating data: %s\n", \
67 ZSTD_getErrorName(code)); \
72 /*-*******************************************************
74 *********************************************************/
75 static unsigned RAND(unsigned* src)
77 #define RAND_rotl32(x,r) ((x << r) | (x >> (32 - r)))
78 static const U32 prime1 = 2654435761U;
79 static const U32 prime2 = 2246822519U;
83 rand32 = RAND_rotl32(rand32, 13);
85 return RAND_rotl32(rand32, 27);
89 #define DISTSIZE (8192)
91 /* Write `size` bytes into `ptr`, all of which are less than or equal to `maxSymb` */
92 static void RAND_bufferMaxSymb(U32* seed, void* ptr, size_t size, int maxSymb)
97 for (i = 0; i < size; i++) {
98 op[i] = (BYTE) (RAND(seed) % (maxSymb + 1));
102 /* Write `size` random bytes into `ptr` */
103 static void RAND_buffer(U32* seed, void* ptr, size_t size)
108 for (i = 0; i + 4 <= size; i += 4) {
109 MEM_writeLE32(op + i, RAND(seed));
111 for (; i < size; i++) {
112 op[i] = RAND(seed) & 0xff;
116 /* Write `size` bytes into `ptr` following the distribution `dist` */
117 static void RAND_bufferDist(U32* seed, BYTE* dist, void* ptr, size_t size)
122 for (i = 0; i < size; i++) {
123 op[i] = dist[RAND(seed) % DISTSIZE];
127 /* Generate a random distribution where the frequency of each symbol follows a
128 * geometric distribution defined by `weight`
129 * `dist` should have size at least `DISTSIZE` */
130 static void RAND_genDist(U32* seed, BYTE* dist, double weight)
133 size_t statesLeft = DISTSIZE;
134 BYTE symb = (BYTE) (RAND(seed) % 256);
135 BYTE step = (BYTE) ((RAND(seed) % 256) | 1); /* force it to be odd so it's relatively prime to 256 */
137 while (i < DISTSIZE) {
138 size_t states = ((size_t)(weight * statesLeft)) + 1;
140 for (j = 0; j < states && i < DISTSIZE; j++, i++) {
145 statesLeft -= states;
149 /* Generates a random number in the range [min, max) */
150 static inline U32 RAND_range(U32* seed, U32 min, U32 max)
152 return (RAND(seed) % (max-min)) + min;
155 #define ROUND(x) ((U32)(x + 0.5))
157 /* Generates a random number in an exponential distribution with mean `mean` */
158 static double RAND_exp(U32* seed, double mean)
160 double const u = RAND(seed) / (double) UINT_MAX;
161 return log(1-u) * (-mean);
164 /*-*******************************************************
165 * Constants and Structs
166 *********************************************************/
167 const char *BLOCK_TYPES[] = {"raw", "rle", "compressed"};
169 #define MAX_DECOMPRESSED_SIZE_LOG 20
170 #define MAX_DECOMPRESSED_SIZE (1ULL << MAX_DECOMPRESSED_SIZE_LOG)
172 #define MAX_WINDOW_LOG 22 /* Recommended support is 8MB, so limit to 4MB + mantissa */
174 #define MIN_SEQ_LEN (3)
175 #define MAX_NB_SEQ ((ZSTD_BLOCKSIZE_MAX + MIN_SEQ_LEN - 1) / MIN_SEQ_LEN)
177 BYTE CONTENT_BUFFER[MAX_DECOMPRESSED_SIZE];
178 BYTE FRAME_BUFFER[MAX_DECOMPRESSED_SIZE * 2];
179 BYTE LITERAL_BUFFER[ZSTD_BLOCKSIZE_MAX];
181 seqDef SEQUENCE_BUFFER[MAX_NB_SEQ];
182 BYTE SEQUENCE_LITERAL_BUFFER[ZSTD_BLOCKSIZE_MAX]; /* storeSeq expects a place to copy literals to */
183 BYTE SEQUENCE_LLCODE[ZSTD_BLOCKSIZE_MAX];
184 BYTE SEQUENCE_MLCODE[ZSTD_BLOCKSIZE_MAX];
185 BYTE SEQUENCE_OFCODE[ZSTD_BLOCKSIZE_MAX];
190 size_t contentSize; /* 0 means unknown (unless contentSize == windowSize == 0) */
191 unsigned windowSize; /* contentSize >= windowSize means single segment */
194 /* For repeat modes */
196 U32 rep[ZSTD_REP_NUM];
199 /* the distribution used in the previous block for repeat mode */
200 BYTE hufDist[DISTSIZE];
201 U32 hufTable [256]; /* HUF_CElt is an incomplete type */
204 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
205 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
206 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
208 /* Symbols that were present in the previous distribution, for use with
210 BYTE litlengthSymbolSet[36];
211 BYTE offsetSymbolSet[29];
212 BYTE matchlengthSymbolSet[53];
224 frameHeader_t header;
227 cblockStats_t oldStats; /* so they can be rolled back if uncompressible */
233 size_t dictContentSize;
238 gt_frame = 0, /* generate frames */
239 gt_block, /* generate compressed blocks without block/frame headers */
242 /*-*******************************************************
243 * Global variables (set from command line)
244 *********************************************************/
245 U32 g_maxDecompressedSizeLog = MAX_DECOMPRESSED_SIZE_LOG; /* <= 20 */
246 U32 g_maxBlockSize = ZSTD_BLOCKSIZE_MAX; /* <= 128 KB */
248 /*-*******************************************************
249 * Generator Functions
250 *********************************************************/
253 int contentSize; /* force the content size to be present */
254 } opts; /* advanced options on generation */
256 /* Generate and write a random frame header */
257 static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info)
259 BYTE* const op = frame->data;
265 int singleSegment = 0;
266 int contentSizeFlag = 0;
269 memset(&fh, 0, sizeof(fh));
271 /* generate window size */
273 /* Follow window algorithm from specification */
274 int const exponent = RAND(seed) % (MAX_WINDOW_LOG - 10);
275 int const mantissa = RAND(seed) % 8;
276 windowByte = (BYTE) ((exponent << 3) | mantissa);
277 fh.windowSize = (1U << (exponent + 10));
278 fh.windowSize += fh.windowSize / 8 * mantissa;
282 /* Generate random content size */
284 if (RAND(seed) & 7 && g_maxDecompressedSizeLog > 7) {
285 /* do content of at least 128 bytes */
286 highBit = 1ULL << RAND_range(seed, 7, g_maxDecompressedSizeLog);
287 } else if (RAND(seed) & 3) {
288 /* do small content */
289 highBit = 1ULL << RAND_range(seed, 0, MIN(7, 1U << g_maxDecompressedSizeLog));
294 fh.contentSize = highBit ? highBit + (RAND(seed) % highBit) : 0;
296 /* provide size sometimes */
297 contentSizeFlag = opts.contentSize | (RAND(seed) & 1);
299 if (contentSizeFlag && (fh.contentSize == 0 || !(RAND(seed) & 7))) {
300 /* do single segment sometimes */
301 fh.windowSize = (U32) fh.contentSize;
306 if (contentSizeFlag) {
307 /* Determine how large fcs field has to be */
308 int minFcsCode = (fh.contentSize >= 256) +
309 (fh.contentSize >= 65536 + 256) +
310 (fh.contentSize > 0xFFFFFFFFU);
311 if (!singleSegment && !minFcsCode) {
314 fcsCode = minFcsCode + (RAND(seed) % (4 - minFcsCode));
315 if (fcsCode == 1 && fh.contentSize < 256) fcsCode++;
318 /* write out the header */
319 MEM_writeLE32(op + pos, ZSTD_MAGICNUMBER);
324 * fcsCode: 2-bit flag specifying how many bytes used to represent Frame_Content_Size (bits 7-6)
325 * singleSegment: 1-bit flag describing if data must be regenerated within a single continuous memory segment. (bit 5)
326 * contentChecksumFlag: 1-bit flag that is set if frame includes checksum at the end -- set to 1 below (bit 2)
327 * dictBits: 2-bit flag describing how many bytes Dictionary_ID uses -- set to 3 (bits 1-0)
328 * For more information: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_header
330 int const dictBits = info.useDict ? 3 : 0;
331 BYTE const frameHeaderDescriptor =
332 (BYTE) ((fcsCode << 6) | (singleSegment << 5) | (1 << 2) | dictBits);
333 op[pos++] = frameHeaderDescriptor;
336 if (!singleSegment) {
337 op[pos++] = windowByte;
340 MEM_writeLE32(op + pos, (U32) info.dictID);
343 if (contentSizeFlag) {
345 default: /* Impossible */
346 case 0: op[pos++] = (BYTE) fh.contentSize; break;
347 case 1: MEM_writeLE16(op + pos, (U16) (fh.contentSize - 256)); pos += 2; break;
348 case 2: MEM_writeLE32(op + pos, (U32) fh.contentSize); pos += 4; break;
349 case 3: MEM_writeLE64(op + pos, (U64) fh.contentSize); pos += 8; break;
353 DISPLAYLEVEL(3, " frame content size:\t%u\n", (U32)fh.contentSize);
354 DISPLAYLEVEL(3, " frame window size:\t%u\n", fh.windowSize);
355 DISPLAYLEVEL(3, " content size flag:\t%d\n", contentSizeFlag);
356 DISPLAYLEVEL(3, " single segment flag:\t%d\n", singleSegment);
358 frame->data = op + pos;
362 /* Write a literal block in either raw or RLE form, return the literals size */
363 static size_t writeLiteralsBlockSimple(U32* seed, frame_t* frame, size_t contentSize)
365 BYTE* op = (BYTE*)frame->data;
366 int const type = RAND(seed) % 2;
367 int const sizeFormatDesc = RAND(seed) % 8;
369 size_t maxLitSize = MIN(contentSize, g_maxBlockSize);
371 if (sizeFormatDesc == 0) {
372 /* Size_FormatDesc = ?0 */
373 maxLitSize = MIN(maxLitSize, 31);
374 } else if (sizeFormatDesc <= 4) {
375 /* Size_FormatDesc = 01 */
376 maxLitSize = MIN(maxLitSize, 4095);
378 /* Size_Format = 11 */
379 maxLitSize = MIN(maxLitSize, 1048575);
382 litSize = RAND(seed) % (maxLitSize + 1);
383 if (frame->src == frame->srcStart && litSize == 0) {
384 litSize = 1; /* no empty literals if there's nothing preceding this block */
386 if (litSize + 3 > contentSize) {
387 litSize = contentSize; /* no matches shorter than 3 are allowed */
389 /* use smallest size format that fits */
391 op[0] = (type | (0 << 2) | (litSize << 3)) & 0xff;
393 } else if (litSize < 4096) {
394 op[0] = (type | (1 << 2) | (litSize << 4)) & 0xff;
395 op[1] = (litSize >> 4) & 0xff;
398 op[0] = (type | (3 << 2) | (litSize << 4)) & 0xff;
399 op[1] = (litSize >> 4) & 0xff;
400 op[2] = (litSize >> 12) & 0xff;
406 DISPLAYLEVEL(4, " raw literals\n");
408 RAND_buffer(seed, LITERAL_BUFFER, litSize);
409 memcpy(op, LITERAL_BUFFER, litSize);
413 BYTE const symb = (BYTE) (RAND(seed) % 256);
415 DISPLAYLEVEL(4, " rle literals: 0x%02x\n", (U32)symb);
417 memset(LITERAL_BUFFER, symb, litSize);
427 /* Generate a Huffman header for the given source */
428 static size_t writeHufHeader(U32* seed, HUF_CElt* hufTable, void* dst, size_t dstSize,
429 const void* src, size_t srcSize)
431 BYTE* const ostart = (BYTE*)dst;
434 unsigned huffLog = 11;
435 U32 maxSymbolValue = 255;
437 U32 count[HUF_SYMBOLVALUE_MAX+1];
439 /* Scan input and build symbol stats */
440 { size_t const largest = FSE_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, WKSP);
441 if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 0; } /* single symbol, rle */
442 if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */
445 /* Build Huffman Tree */
446 /* Max Huffman log is 11, min is highbit(maxSymbolValue)+1 */
447 huffLog = RAND_range(seed, ZSTD_highbit32(maxSymbolValue)+1, huffLog+1);
448 DISPLAYLEVEL(6, " huffman log: %u\n", huffLog);
449 { size_t const maxBits = HUF_buildCTable_wksp (hufTable, count, maxSymbolValue, huffLog, WKSP, sizeof(WKSP));
451 huffLog = (U32)maxBits;
454 /* Write table description header */
455 { size_t const hSize = HUF_writeCTable (op, dstSize, hufTable, maxSymbolValue, huffLog);
456 if (hSize + 12 >= srcSize) return 0; /* not useful to try compression */
463 /* Write a Huffman coded literals block and return the literals size */
464 static size_t writeLiteralsBlockCompressed(U32* seed, frame_t* frame, size_t contentSize)
466 BYTE* origop = (BYTE*)frame->data;
467 BYTE* opend = (BYTE*)frame->dataEnd;
469 BYTE* const ostart = origop;
470 int const sizeFormat = RAND(seed) % 4;
472 size_t hufHeaderSize = 0;
473 size_t compressedSize = 0;
474 size_t maxLitSize = MIN(contentSize-3, g_maxBlockSize);
476 symbolEncodingType_e hType;
478 if (contentSize < 64) {
479 /* make sure we get reasonably-sized literals for compression */
480 return ERROR(GENERIC);
483 DISPLAYLEVEL(4, " compressed literals\n");
485 switch (sizeFormat) {
486 case 0: /* fall through, size is the same as case 1 */
488 maxLitSize = MIN(maxLitSize, 1023);
492 maxLitSize = MIN(maxLitSize, 16383);
496 maxLitSize = MIN(maxLitSize, 262143);
499 default:; /* impossible */
505 litSize = RAND(seed) % (maxLitSize + 1);
506 } while (litSize < 32); /* avoid small literal sizes */
507 if (litSize + 3 > contentSize) {
508 litSize = contentSize; /* no matches shorter than 3 are allowed */
511 /* most of the time generate a new distribution */
512 if ((RAND(seed) & 3) || !frame->stats.hufInit) {
514 if (RAND(seed) & 3) {
515 /* add 10 to ensure some compressability */
516 double const weight = ((RAND(seed) % 90) + 10) / 100.0;
518 DISPLAYLEVEL(5, " distribution weight: %d%%\n",
519 (int)(weight * 100));
521 RAND_genDist(seed, frame->stats.hufDist, weight);
523 /* sometimes do restricted range literals to force
524 * non-huffman headers */
525 DISPLAYLEVEL(5, " small range literals\n");
526 RAND_bufferMaxSymb(seed, frame->stats.hufDist, DISTSIZE,
529 RAND_bufferDist(seed, frame->stats.hufDist, LITERAL_BUFFER,
532 /* generate the header from the distribution instead of the
533 * actual data to avoid bugs with symbols that were in the
534 * distribution but never showed up in the output */
535 hufHeaderSize = writeHufHeader(
536 seed, (HUF_CElt*)frame->stats.hufTable, op, opend - op,
537 frame->stats.hufDist, DISTSIZE);
538 CHECKERR(hufHeaderSize);
539 /* repeat until a valid header is written */
540 } while (hufHeaderSize == 0);
542 hType = set_compressed;
544 frame->stats.hufInit = 1;
546 /* repeat the distribution/table from last time */
547 DISPLAYLEVEL(5, " huffman repeat stats\n");
548 RAND_bufferDist(seed, frame->stats.hufDist, LITERAL_BUFFER,
557 ? HUF_compress1X_usingCTable(
558 op, opend - op, LITERAL_BUFFER, litSize,
559 (HUF_CElt*)frame->stats.hufTable)
560 : HUF_compress4X_usingCTable(
561 op, opend - op, LITERAL_BUFFER, litSize,
562 (HUF_CElt*)frame->stats.hufTable);
563 CHECKERR(compressedSize);
564 /* this only occurs when it could not compress or similar */
565 } while (compressedSize <= 0);
567 op += compressedSize;
569 compressedSize += hufHeaderSize;
570 DISPLAYLEVEL(5, " regenerated size: %u\n", (U32)litSize);
571 DISPLAYLEVEL(5, " compressed size: %u\n", (U32)compressedSize);
572 if (compressedSize >= litSize) {
573 DISPLAYLEVEL(5, " trying again\n");
574 /* if we have to try again, reset the stats so we don't accidentally
575 * try to repeat a distribution we just made */
576 frame->stats = frame->oldStats;
583 switch (sizeFormat) {
584 case 0: /* fall through, size is the same as case 1 */
586 U32 const header = hType | (sizeFormat << 2) | ((U32)litSize << 4) |
587 ((U32)compressedSize << 14);
588 MEM_writeLE24(ostart, header);
592 U32 const header = hType | (sizeFormat << 2) | ((U32)litSize << 4) |
593 ((U32)compressedSize << 18);
594 MEM_writeLE32(ostart, header);
598 U32 const header = hType | (sizeFormat << 2) | ((U32)litSize << 4) |
599 ((U32)compressedSize << 22);
600 MEM_writeLE32(ostart, header);
601 ostart[4] = (BYTE)(compressedSize >> 10);
604 default:; /* impossible */
611 static size_t writeLiteralsBlock(U32* seed, frame_t* frame, size_t contentSize)
613 /* only do compressed for larger segments to avoid compressibility issues */
614 if (RAND(seed) & 7 && contentSize >= 64) {
615 return writeLiteralsBlockCompressed(seed, frame, contentSize);
617 return writeLiteralsBlockSimple(seed, frame, contentSize);
621 static inline void initSeqStore(seqStore_t *seqStore) {
622 seqStore->sequencesStart = SEQUENCE_BUFFER;
623 seqStore->litStart = SEQUENCE_LITERAL_BUFFER;
624 seqStore->llCode = SEQUENCE_LLCODE;
625 seqStore->mlCode = SEQUENCE_MLCODE;
626 seqStore->ofCode = SEQUENCE_OFCODE;
628 ZSTD_resetSeqStore(seqStore);
631 /* Randomly generate sequence commands */
632 static U32 generateSequences(U32* seed, frame_t* frame, seqStore_t* seqStore,
633 size_t contentSize, size_t literalsSize, dictInfo info)
635 /* The total length of all the matches */
636 size_t const remainingMatch = contentSize - literalsSize;
637 size_t excessMatch = 0;
638 U32 numSequences = 0;
643 const BYTE* literals = LITERAL_BUFFER;
644 BYTE* srcPtr = frame->src;
646 if (literalsSize != contentSize) {
647 /* each match must be at least MIN_SEQ_LEN, so this is the maximum
648 * number of sequences we can have */
649 U32 const maxSequences = (U32)remainingMatch / MIN_SEQ_LEN;
650 numSequences = (RAND(seed) % maxSequences) + 1;
652 /* the extra match lengths we have to allocate to each sequence */
653 excessMatch = remainingMatch - numSequences * MIN_SEQ_LEN;
656 DISPLAYLEVEL(5, " total match lengths: %u\n", (U32)remainingMatch);
657 for (i = 0; i < numSequences; i++) {
658 /* Generate match and literal lengths by exponential distribution to
659 * ensure nice numbers */
662 ROUND(RAND_exp(seed, excessMatch / (double)(numSequences - i)));
665 ? ROUND(RAND_exp(seed,
667 (double)(numSequences - i)))
669 /* actual offset, code to send, and point to copy up to when shifting
670 * codes in the repeat offsets history */
671 U32 offset, offsetCode, repIndex;
674 matchLen = (U32) MIN(matchLen, excessMatch + MIN_SEQ_LEN);
675 literalLen = MIN(literalLen, (U32) literalsSize);
676 if (i == 0 && srcPtr == frame->srcStart && literalLen == 0) literalLen = 1;
677 if (i + 1 == numSequences) matchLen = MIN_SEQ_LEN + (U32) excessMatch;
679 memcpy(srcPtr, literals, literalLen);
680 srcPtr += literalLen;
682 if (RAND(seed) & 7) {
683 /* do a normal offset */
684 U32 const dataDecompressed = (U32)((BYTE*)srcPtr-(BYTE*)frame->srcStart);
685 offset = (RAND(seed) %
686 MIN(frame->header.windowSize,
687 (size_t)((BYTE*)srcPtr - (BYTE*)frame->srcStart))) +
689 if (info.useDict && (RAND(seed) & 1) && i + 1 != numSequences && dataDecompressed < frame->header.windowSize) {
690 /* need to occasionally generate offsets that go past the start */
691 /* including i+1 != numSequences because the last sequences has to adhere to predetermined contentSize */
692 U32 lenPastStart = (RAND(seed) % info.dictContentSize) + 1;
693 offset = (U32)((BYTE*)srcPtr - (BYTE*)frame->srcStart)+lenPastStart;
694 if (offset > frame->header.windowSize) {
695 if (lenPastStart < MIN_SEQ_LEN) {
696 /* when offset > windowSize, matchLen bound by end of dictionary (lenPastStart) */
697 /* this also means that lenPastStart must be greater than MIN_SEQ_LEN */
698 /* make sure lenPastStart does not go past dictionary start though */
699 lenPastStart = MIN(lenPastStart+MIN_SEQ_LEN, (U32)info.dictContentSize);
700 offset = (U32)((BYTE*)srcPtr - (BYTE*)frame->srcStart) + lenPastStart;
703 U32 const matchLenBound = MIN(frame->header.windowSize, lenPastStart);
704 matchLen = MIN(matchLen, matchLenBound);
708 offsetCode = offset + ZSTD_REP_MOVE;
711 /* do a repeat offset */
712 offsetCode = RAND(seed) % 3;
713 if (literalLen > 0) {
714 offset = frame->stats.rep[offsetCode];
715 repIndex = offsetCode;
718 offset = offsetCode == 2 ? frame->stats.rep[0] - 1
719 : frame->stats.rep[offsetCode + 1];
720 repIndex = MIN(2, offsetCode + 1);
723 } while (((!info.useDict) && (offset > (size_t)((BYTE*)srcPtr - (BYTE*)frame->srcStart))) || offset == 0);
727 BYTE* const dictEnd = info.dictContent + info.dictContentSize;
728 for (j = 0; j < matchLen; j++) {
729 if ((U32)((BYTE*)srcPtr - (BYTE*)frame->srcStart) < offset) {
730 /* copy from dictionary instead of literals */
731 size_t const dictOffset = offset - (srcPtr - (BYTE*)frame->srcStart);
732 *srcPtr = *(dictEnd - dictOffset);
735 *srcPtr = *(srcPtr-offset);
742 for (r = repIndex; r > 0; r--) {
743 frame->stats.rep[r] = frame->stats.rep[r - 1];
745 frame->stats.rep[0] = offset;
748 DISPLAYLEVEL(6, " LL: %5u OF: %5u ML: %5u", literalLen, offset, matchLen);
749 DISPLAYLEVEL(7, " srcPos: %8u seqNb: %3u",
750 (U32)((BYTE*)srcPtr - (BYTE*)frame->srcStart), i);
751 DISPLAYLEVEL(6, "\n");
752 if (offsetCode < 3) {
753 DISPLAYLEVEL(7, " repeat offset: %d\n", repIndex);
755 /* use libzstd sequence handling */
756 ZSTD_storeSeq(seqStore, literalLen, literals, offsetCode,
757 matchLen - MINMATCH);
759 literalsSize -= literalLen;
760 excessMatch -= (matchLen - MIN_SEQ_LEN);
761 literals += literalLen;
764 memcpy(srcPtr, literals, literalsSize);
765 srcPtr += literalsSize;
766 DISPLAYLEVEL(6, " excess literals: %5u", (U32)literalsSize);
767 DISPLAYLEVEL(7, " srcPos: %8u", (U32)((BYTE*)srcPtr - (BYTE*)frame->srcStart));
768 DISPLAYLEVEL(6, "\n");
773 static void initSymbolSet(const BYTE* symbols, size_t len, BYTE* set, BYTE maxSymbolValue)
777 memset(set, 0, (size_t)maxSymbolValue+1);
779 for (i = 0; i < len; i++) {
784 static int isSymbolSubset(const BYTE* symbols, size_t len, const BYTE* set, BYTE maxSymbolValue)
788 for (i = 0; i < len; i++) {
789 if (symbols[i] > maxSymbolValue || !set[symbols[i]]) {
796 static size_t writeSequences(U32* seed, frame_t* frame, seqStore_t* seqStorePtr,
799 /* This code is mostly copied from ZSTD_compressSequences in zstd_compress.c */
802 FSE_CTable* CTable_LitLength = frame->stats.litlengthCTable;
803 FSE_CTable* CTable_OffsetBits = frame->stats.offcodeCTable;
804 FSE_CTable* CTable_MatchLength = frame->stats.matchlengthCTable;
805 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
806 const seqDef* const sequences = seqStorePtr->sequencesStart;
807 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
808 const BYTE* const llCodeTable = seqStorePtr->llCode;
809 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
810 BYTE* const oend = (BYTE*)frame->dataEnd;
811 BYTE* op = (BYTE*)frame->data;
813 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
815 /* literals compressing block removed so that can be done separately */
817 /* Sequences Header */
818 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
819 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
820 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
821 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
823 /* seqHead : flags for FSE encoding type */
832 /* convert length/distances into codes */
833 ZSTD_seqToCodes(seqStorePtr);
835 /* CTable for Literal Lengths */
837 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, WKSP);
838 if (mostFrequent == nbSeq) {
839 /* do RLE if we have the chance */
840 *op++ = llCodeTable[0];
841 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
843 } else if (frame->stats.fseInit && !(RAND(seed) & 3) &&
844 isSymbolSubset(llCodeTable, nbSeq,
845 frame->stats.litlengthSymbolSet, 35)) {
846 /* maybe do repeat mode if we're allowed to */
848 } else if (!(RAND(seed) & 3)) {
849 /* maybe use the default distribution */
850 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
853 /* fall back on a full table */
854 size_t nbSeq_1 = nbSeq;
855 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
856 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
857 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
858 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
859 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
861 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
862 LLtype = set_compressed;
865 /* CTable for Offsets */
866 /* see Literal Lengths for descriptions of mode choices */
868 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, WKSP);
869 if (mostFrequent == nbSeq) {
870 *op++ = ofCodeTable[0];
871 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
873 } else if (frame->stats.fseInit && !(RAND(seed) & 3) &&
874 isSymbolSubset(ofCodeTable, nbSeq,
875 frame->stats.offsetSymbolSet, 28)) {
876 Offtype = set_repeat;
877 } else if (!(RAND(seed) & 3)) {
878 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, DefaultMaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
881 size_t nbSeq_1 = nbSeq;
882 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
883 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
884 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
885 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
886 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
888 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
889 Offtype = set_compressed;
892 /* CTable for MatchLengths */
893 /* see Literal Lengths for descriptions of mode choices */
895 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, WKSP);
896 if (mostFrequent == nbSeq) {
897 *op++ = *mlCodeTable;
898 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
900 } else if (frame->stats.fseInit && !(RAND(seed) & 3) &&
901 isSymbolSubset(mlCodeTable, nbSeq,
902 frame->stats.matchlengthSymbolSet, 52)) {
904 } else if (!(RAND(seed) & 3)) {
905 /* sometimes do default distribution */
906 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
909 /* fall back on table */
910 size_t nbSeq_1 = nbSeq;
911 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
912 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
913 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
914 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
915 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
917 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
918 MLtype = set_compressed;
920 frame->stats.fseInit = 1;
921 initSymbolSet(llCodeTable, nbSeq, frame->stats.litlengthSymbolSet, 35);
922 initSymbolSet(ofCodeTable, nbSeq, frame->stats.offsetSymbolSet, 28);
923 initSymbolSet(mlCodeTable, nbSeq, frame->stats.matchlengthSymbolSet, 52);
925 DISPLAYLEVEL(5, " LL type: %d OF type: %d ML type: %d\n", LLtype, Offtype, MLtype);
927 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
929 /* Encoding Sequences */
930 { BIT_CStream_t blockStream;
931 FSE_CState_t stateMatchLength;
932 FSE_CState_t stateOffsetBits;
933 FSE_CState_t stateLitLength;
935 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
938 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
939 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
940 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
941 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
942 if (MEM_32bits()) BIT_flushBits(&blockStream);
943 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
944 if (MEM_32bits()) BIT_flushBits(&blockStream);
945 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
946 BIT_flushBits(&blockStream);
949 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
950 BYTE const llCode = llCodeTable[n];
951 BYTE const ofCode = ofCodeTable[n];
952 BYTE const mlCode = mlCodeTable[n];
953 U32 const llBits = LL_bits[llCode];
954 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
955 U32 const mlBits = ML_bits[mlCode];
957 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
958 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
959 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
960 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
961 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
962 BIT_flushBits(&blockStream); /* (7)*/
963 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
964 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
965 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
966 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
967 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
968 BIT_flushBits(&blockStream); /* (7)*/
971 FSE_flushCState(&blockStream, &stateMatchLength);
972 FSE_flushCState(&blockStream, &stateOffsetBits);
973 FSE_flushCState(&blockStream, &stateLitLength);
975 { size_t const streamSize = BIT_closeCStream(&blockStream);
976 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
985 static size_t writeSequencesBlock(U32* seed, frame_t* frame, size_t contentSize,
986 size_t literalsSize, dictInfo info)
992 initSeqStore(&seqStore);
994 /* randomly generate sequences */
995 numSequences = generateSequences(seed, frame, &seqStore, contentSize, literalsSize, info);
996 /* write them out to the frame data */
997 CHECKERR(writeSequences(seed, frame, &seqStore, numSequences));
1002 static size_t writeCompressedBlock(U32* seed, frame_t* frame, size_t contentSize, dictInfo info)
1004 BYTE* const blockStart = (BYTE*)frame->data;
1005 size_t literalsSize;
1008 DISPLAYLEVEL(4, " compressed block:\n");
1010 literalsSize = writeLiteralsBlock(seed, frame, contentSize);
1012 DISPLAYLEVEL(4, " literals size: %u\n", (U32)literalsSize);
1014 nbSeq = writeSequencesBlock(seed, frame, contentSize, literalsSize, info);
1016 DISPLAYLEVEL(4, " number of sequences: %u\n", (U32)nbSeq);
1018 return (BYTE*)frame->data - blockStart;
1021 static void writeBlock(U32* seed, frame_t* frame, size_t contentSize,
1022 int lastBlock, dictInfo info)
1024 int const blockTypeDesc = RAND(seed) % 8;
1028 BYTE *const header = (BYTE*)frame->data;
1029 BYTE *op = header + 3;
1031 DISPLAYLEVEL(4, " block:\n");
1032 DISPLAYLEVEL(4, " block content size: %u\n", (U32)contentSize);
1033 DISPLAYLEVEL(4, " last block: %s\n", lastBlock ? "yes" : "no");
1035 if (blockTypeDesc == 0) {
1036 /* Raw data frame */
1038 RAND_buffer(seed, frame->src, contentSize);
1039 memcpy(op, frame->src, contentSize);
1043 blockSize = contentSize;
1044 } else if (blockTypeDesc == 1) {
1046 BYTE const symbol = RAND(seed) & 0xff;
1049 memset(frame->src, symbol, contentSize);
1053 blockSize = contentSize;
1055 /* compressed, most common */
1056 size_t compressedSize;
1059 frame->oldStats = frame->stats;
1062 compressedSize = writeCompressedBlock(seed, frame, contentSize, info);
1063 if (compressedSize >= contentSize) { /* compressed block must be strictly smaller than uncompressed one */
1065 memcpy(op, frame->src, contentSize);
1068 blockSize = contentSize; /* fall back on raw block if data doesn't
1071 frame->stats = frame->oldStats; /* don't update the stats */
1073 op += compressedSize;
1074 blockSize = compressedSize;
1077 frame->src = (BYTE*)frame->src + contentSize;
1079 DISPLAYLEVEL(4, " block type: %s\n", BLOCK_TYPES[blockType]);
1080 DISPLAYLEVEL(4, " block size field: %u\n", (U32)blockSize);
1082 header[0] = (BYTE) ((lastBlock | (blockType << 1) | (blockSize << 3)) & 0xff);
1083 MEM_writeLE16(header + 1, (U16) (blockSize >> 5));
1088 static void writeBlocks(U32* seed, frame_t* frame, dictInfo info)
1090 size_t contentLeft = frame->header.contentSize;
1091 size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize);
1093 /* 1 in 4 chance of ending frame */
1094 int const lastBlock = contentLeft > maxBlockSize ? 0 : !(RAND(seed) & 3);
1095 size_t blockContentSize;
1097 blockContentSize = contentLeft;
1099 if (contentLeft > 0 && (RAND(seed) & 7)) {
1100 /* some variable size block */
1101 blockContentSize = RAND(seed) % (MIN(maxBlockSize, contentLeft)+1);
1102 } else if (contentLeft > maxBlockSize && (RAND(seed) & 1)) {
1103 /* some full size block */
1104 blockContentSize = maxBlockSize;
1106 /* some empty block */
1107 blockContentSize = 0;
1111 writeBlock(seed, frame, blockContentSize, lastBlock, info);
1113 contentLeft -= blockContentSize;
1114 if (lastBlock) break;
1118 static void writeChecksum(frame_t* frame)
1120 /* write checksum so implementations can verify their output */
1121 U64 digest = XXH64(frame->srcStart, (BYTE*)frame->src-(BYTE*)frame->srcStart, 0);
1122 DISPLAYLEVEL(3, " checksum: %08x\n", (U32)digest);
1123 MEM_writeLE32(frame->data, (U32)digest);
1124 frame->data = (BYTE*)frame->data + 4;
1127 static void outputBuffer(const void* buf, size_t size, const char* const path)
1129 /* write data out to file */
1130 const BYTE* ip = (const BYTE*)buf;
1133 out = fopen(path, "wb");
1138 fprintf(stderr, "Failed to open file at %s: ", path);
1143 { size_t fsize = size;
1145 while (written < fsize) {
1146 written += fwrite(ip + written, 1, fsize - written, out);
1148 fprintf(stderr, "Failed to write to file at %s: ", path);
1160 static void initFrame(frame_t* fr)
1162 memset(fr, 0, sizeof(*fr));
1163 fr->data = fr->dataStart = FRAME_BUFFER;
1164 fr->dataEnd = FRAME_BUFFER + sizeof(FRAME_BUFFER);
1165 fr->src = fr->srcStart = CONTENT_BUFFER;
1166 fr->srcEnd = CONTENT_BUFFER + sizeof(CONTENT_BUFFER);
1168 /* init repeat codes */
1169 fr->stats.rep[0] = 1;
1170 fr->stats.rep[1] = 4;
1171 fr->stats.rep[2] = 8;
1175 * Generated a single zstd compressed block with no block/frame header.
1176 * Returns the final seed.
1178 static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info)
1180 size_t blockContentSize;
1181 int blockWritten = 0;
1183 DISPLAYLEVEL(4, "block seed: %u\n", seed);
1185 op = (BYTE*)frame->data;
1187 while (!blockWritten) {
1189 /* generate window size */
1190 { int const exponent = RAND(&seed) % (MAX_WINDOW_LOG - 10);
1191 int const mantissa = RAND(&seed) % 8;
1192 frame->header.windowSize = (1U << (exponent + 10));
1193 frame->header.windowSize += (frame->header.windowSize / 8) * mantissa;
1196 /* generate content size */
1197 { size_t const maxBlockSize = MIN(g_maxBlockSize, frame->header.windowSize);
1198 if (RAND(&seed) & 15) {
1199 /* some full size blocks */
1200 blockContentSize = maxBlockSize;
1201 } else if (RAND(&seed) & 7 && g_maxBlockSize >= (1U << 7)) {
1202 /* some small blocks <= 128 bytes*/
1203 blockContentSize = RAND(&seed) % (1U << 7);
1205 /* some variable size blocks */
1206 blockContentSize = RAND(&seed) % maxBlockSize;
1210 /* try generating a compressed block */
1211 frame->oldStats = frame->stats;
1213 cSize = writeCompressedBlock(&seed, frame, blockContentSize, info);
1214 if (cSize >= blockContentSize) { /* compressed size must be strictly smaller than decompressed size : https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#blocks */
1215 /* data doesn't compress -- try again */
1216 frame->stats = frame->oldStats; /* don't update the stats */
1217 DISPLAYLEVEL(5, " can't compress block : try again \n");
1220 DISPLAYLEVEL(4, " block size: %u \n", (U32)cSize);
1221 frame->src = (BYTE*)frame->src + blockContentSize;
1227 /* Return the final seed */
1228 static U32 generateFrame(U32 seed, frame_t* fr, dictInfo info)
1230 /* generate a complete frame */
1231 DISPLAYLEVEL(3, "frame seed: %u\n", seed);
1234 writeFrameHeader(&seed, fr, info);
1235 writeBlocks(&seed, fr, info);
1241 /*_*******************************************************
1242 * Dictionary Helper Functions
1243 *********************************************************/
1244 /* returns 0 if successful, otherwise returns 1 upon error */
1245 static int genRandomDict(U32 dictID, U32 seed, size_t dictSize, BYTE* fullDict)
1247 /* allocate space for samples */
1249 unsigned const numSamples = 4;
1250 size_t sampleSizes[4];
1251 BYTE* const samples = malloc(5000*sizeof(BYTE));
1252 if (samples == NULL) {
1253 DISPLAY("Error: could not allocate space for samples\n");
1257 /* generate samples */
1258 { unsigned literalValue = 1;
1259 unsigned samplesPos = 0;
1260 size_t currSize = 1;
1261 while (literalValue <= 4) {
1262 sampleSizes[literalValue - 1] = currSize;
1264 for (k = 0; k < currSize; k++) {
1265 *(samples + (samplesPos++)) = (BYTE)literalValue;
1271 { size_t dictWriteSize = 0;
1272 ZDICT_params_t zdictParams;
1273 size_t const headerSize = MAX(dictSize/4, 256);
1274 size_t const dictContentSize = dictSize - headerSize;
1275 BYTE* const dictContent = fullDict + headerSize;
1276 if (dictContentSize < ZDICT_CONTENTSIZE_MIN || dictSize < ZDICT_DICTSIZE_MIN) {
1277 DISPLAY("Error: dictionary size is too small\n");
1279 goto exitGenRandomDict;
1282 /* init dictionary params */
1283 memset(&zdictParams, 0, sizeof(zdictParams));
1284 zdictParams.dictID = dictID;
1285 zdictParams.notificationLevel = 1;
1287 /* fill in dictionary content */
1288 RAND_buffer(&seed, (void*)dictContent, dictContentSize);
1290 /* finalize dictionary with random samples */
1291 dictWriteSize = ZDICT_finalizeDictionary(fullDict, dictSize,
1292 dictContent, dictContentSize,
1293 samples, sampleSizes, numSamples,
1296 if (ZDICT_isError(dictWriteSize)) {
1297 DISPLAY("Could not finalize dictionary: %s\n", ZDICT_getErrorName(dictWriteSize));
1307 static dictInfo initDictInfo(int useDict, size_t dictContentSize, BYTE* dictContent, U32 dictID){
1308 /* allocate space statically */
1310 memset(&dictOp, 0, sizeof(dictOp));
1311 dictOp.useDict = useDict;
1312 dictOp.dictContentSize = dictContentSize;
1313 dictOp.dictContent = dictContent;
1314 dictOp.dictID = dictID;
1318 /*-*******************************************************
1320 *********************************************************/
1322 BYTE DECOMPRESSED_BUFFER[MAX_DECOMPRESSED_SIZE];
1324 static size_t testDecodeSimple(frame_t* fr)
1326 /* test decoding the generated data with the simple API */
1327 size_t const ret = ZSTD_decompress(DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
1328 fr->dataStart, (BYTE*)fr->data - (BYTE*)fr->dataStart);
1330 if (ZSTD_isError(ret)) return ret;
1332 if (memcmp(DECOMPRESSED_BUFFER, fr->srcStart,
1333 (BYTE*)fr->src - (BYTE*)fr->srcStart) != 0) {
1334 return ERROR(corruption_detected);
1340 static size_t testDecodeStreaming(frame_t* fr)
1342 /* test decoding the generated data with the streaming API */
1343 ZSTD_DStream* zd = ZSTD_createDStream();
1348 if (!zd) return ERROR(memory_allocation);
1350 in.src = fr->dataStart;
1352 in.size = (BYTE*)fr->data - (BYTE*)fr->dataStart;
1354 out.dst = DECOMPRESSED_BUFFER;
1356 out.size = ZSTD_DStreamOutSize();
1358 ZSTD_initDStream(zd);
1360 ret = ZSTD_decompressStream(zd, &out, &in);
1361 if (ZSTD_isError(ret)) goto cleanup; /* error */
1362 if (ret == 0) break; /* frame is done */
1364 /* force decoding to be done in chunks */
1365 out.size += MIN(ZSTD_DStreamOutSize(), MAX_DECOMPRESSED_SIZE - out.size);
1370 if (memcmp(out.dst, fr->srcStart, out.pos) != 0) {
1371 return ERROR(corruption_detected);
1375 ZSTD_freeDStream(zd);
1379 static size_t testDecodeWithDict(U32 seed, genType_e genType)
1381 /* create variables */
1382 size_t const dictSize = RAND(&seed) % (10 << 20) + ZDICT_DICTSIZE_MIN + ZDICT_CONTENTSIZE_MIN;
1383 U32 const dictID = RAND(&seed);
1384 size_t errorDetected = 0;
1385 BYTE* const fullDict = malloc(dictSize);
1386 if (fullDict == NULL) {
1387 return ERROR(GENERIC);
1390 /* generate random dictionary */
1391 if (genRandomDict(dictID, seed, dictSize, fullDict)) { /* return 0 on success */
1392 errorDetected = ERROR(GENERIC);
1393 goto dictTestCleanup;
1399 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
1403 { size_t const headerSize = MAX(dictSize/4, 256);
1404 size_t const dictContentSize = dictSize-headerSize;
1405 BYTE* const dictContent = fullDict+headerSize;
1406 info = initDictInfo(1, dictContentSize, dictContent, dictID);
1409 /* manually decompress and check difference */
1410 if (genType == gt_frame) {
1412 generateFrame(seed, &fr, info);
1413 ret = ZSTD_decompress_usingDict(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
1414 fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart,
1415 fullDict, dictSize);
1418 generateCompressedBlock(seed, &fr, info);
1419 ret = ZSTD_decompressBegin_usingDict(dctx, fullDict, dictSize);
1420 if (ZSTD_isError(ret)) {
1421 errorDetected = ret;
1422 ZSTD_freeDCtx(dctx);
1423 goto dictTestCleanup;
1425 ret = ZSTD_decompressBlock(dctx, DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
1426 fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart);
1428 ZSTD_freeDCtx(dctx);
1430 if (ZSTD_isError(ret)) {
1431 errorDetected = ret;
1432 goto dictTestCleanup;
1435 if (memcmp(DECOMPRESSED_BUFFER, fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart) != 0) {
1436 errorDetected = ERROR(corruption_detected);
1437 goto dictTestCleanup;
1443 return errorDetected;
1446 static size_t testDecodeRawBlock(frame_t* fr)
1448 ZSTD_DCtx* dctx = ZSTD_createDCtx();
1449 size_t ret = ZSTD_decompressBegin(dctx);
1450 if (ZSTD_isError(ret)) return ret;
1452 ret = ZSTD_decompressBlock(
1454 DECOMPRESSED_BUFFER, MAX_DECOMPRESSED_SIZE,
1455 fr->dataStart, (BYTE*)fr->data - (BYTE*)fr->dataStart);
1456 ZSTD_freeDCtx(dctx);
1457 if (ZSTD_isError(ret)) return ret;
1459 if (memcmp(DECOMPRESSED_BUFFER, fr->srcStart,
1460 (BYTE*)fr->src - (BYTE*)fr->srcStart) != 0) {
1461 return ERROR(corruption_detected);
1467 static int runBlockTest(U32* seed)
1470 U32 const seedCopy = *seed;
1471 { dictInfo const info = initDictInfo(0, 0, NULL, 0);
1472 *seed = generateCompressedBlock(*seed, &fr, info);
1475 { size_t const r = testDecodeRawBlock(&fr);
1476 if (ZSTD_isError(r)) {
1477 DISPLAY("Error in block mode on test seed %u: %s\n", seedCopy,
1478 ZSTD_getErrorName(r));
1483 { size_t const r = testDecodeWithDict(*seed, gt_block);
1484 if (ZSTD_isError(r)) {
1485 DISPLAY("Error in block mode with dictionary on test seed %u: %s\n",
1486 seedCopy, ZSTD_getErrorName(r));
1493 static int runFrameTest(U32* seed)
1496 U32 const seedCopy = *seed;
1497 { dictInfo const info = initDictInfo(0, 0, NULL, 0);
1498 *seed = generateFrame(*seed, &fr, info);
1501 { size_t const r = testDecodeSimple(&fr);
1502 if (ZSTD_isError(r)) {
1503 DISPLAY("Error in simple mode on test seed %u: %s\n",
1504 seedCopy, ZSTD_getErrorName(r));
1508 { size_t const r = testDecodeStreaming(&fr);
1509 if (ZSTD_isError(r)) {
1510 DISPLAY("Error in streaming mode on test seed %u: %s\n",
1511 seedCopy, ZSTD_getErrorName(r));
1515 { size_t const r = testDecodeWithDict(*seed, gt_frame); /* avoid big dictionaries */
1516 if (ZSTD_isError(r)) {
1517 DISPLAY("Error in dictionary mode on test seed %u: %s\n",
1518 seedCopy, ZSTD_getErrorName(r));
1525 static int runTestMode(U32 seed, unsigned numFiles, unsigned const testDurationS,
1530 UTIL_time_t const startClock = UTIL_getTime();
1531 U64 const maxClockSpan = testDurationS * SEC_TO_MICRO;
1533 if (numFiles == 0 && !testDurationS) numFiles = 1;
1535 DISPLAY("seed: %u\n", seed);
1537 for (fnum = 0; fnum < numFiles || UTIL_clockSpanMicro(startClock) < maxClockSpan; fnum++) {
1538 if (fnum < numFiles)
1539 DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
1541 DISPLAYUPDATE("\r%u ", fnum);
1543 { int const ret = (genType == gt_frame) ?
1544 runFrameTest(&seed) :
1545 runBlockTest(&seed);
1546 if (ret) return ret;
1550 DISPLAY("\r%u tests completed: ", fnum);
1556 /*-*******************************************************
1558 *********************************************************/
1560 static int generateFile(U32 seed, const char* const path,
1561 const char* const origPath, genType_e genType)
1565 DISPLAY("seed: %u\n", seed);
1567 { dictInfo const info = initDictInfo(0, 0, NULL, 0);
1568 if (genType == gt_frame) {
1569 generateFrame(seed, &fr, info);
1571 generateCompressedBlock(seed, &fr, info);
1574 outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, path);
1576 outputBuffer(fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart, origPath);
1581 static int generateCorpus(U32 seed, unsigned numFiles, const char* const path,
1582 const char* const origPath, genType_e genType)
1584 char outPath[MAX_PATH];
1587 DISPLAY("seed: %u\n", seed);
1589 for (fnum = 0; fnum < numFiles; fnum++) {
1592 DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
1594 { dictInfo const info = initDictInfo(0, 0, NULL, 0);
1595 if (genType == gt_frame) {
1596 seed = generateFrame(seed, &fr, info);
1598 seed = generateCompressedBlock(seed, &fr, info);
1602 if (snprintf(outPath, MAX_PATH, "%s/z%06u.zst", path, fnum) + 1 > MAX_PATH) {
1603 DISPLAY("Error: path too long\n");
1606 outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, outPath);
1609 if (snprintf(outPath, MAX_PATH, "%s/z%06u", origPath, fnum) + 1 > MAX_PATH) {
1610 DISPLAY("Error: path too long\n");
1613 outputBuffer(fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart, outPath);
1617 DISPLAY("\r%u/%u \n", fnum, numFiles);
1622 static int generateCorpusWithDict(U32 seed, unsigned numFiles, const char* const path,
1623 const char* const origPath, const size_t dictSize,
1626 char outPath[MAX_PATH];
1628 U32 const dictID = RAND(&seed);
1629 int errorDetected = 0;
1631 if (snprintf(outPath, MAX_PATH, "%s/dictionary", path) + 1 > MAX_PATH) {
1632 DISPLAY("Error: path too long\n");
1636 /* allocate space for the dictionary */
1637 fullDict = malloc(dictSize);
1638 if (fullDict == NULL) {
1639 DISPLAY("Error: could not allocate space for full dictionary.\n");
1643 /* randomly generate the dictionary */
1644 { int const ret = genRandomDict(dictID, seed, dictSize, fullDict);
1646 errorDetected = ret;
1651 /* write out dictionary */
1652 if (numFiles != 0) {
1653 if (snprintf(outPath, MAX_PATH, "%s/dictionary", path) + 1 > MAX_PATH) {
1654 DISPLAY("Error: dictionary path too long\n");
1658 outputBuffer(fullDict, dictSize, outPath);
1661 outputBuffer(fullDict, dictSize, "dictionary");
1664 /* generate random compressed/decompressed files */
1666 for (fnum = 0; fnum < MAX(numFiles, 1); fnum++) {
1668 DISPLAYUPDATE("\r%u/%u ", fnum, numFiles);
1670 size_t const headerSize = MAX(dictSize/4, 256);
1671 size_t const dictContentSize = dictSize-headerSize;
1672 BYTE* const dictContent = fullDict+headerSize;
1673 dictInfo const info = initDictInfo(1, dictContentSize, dictContent, dictID);
1674 if (genType == gt_frame) {
1675 seed = generateFrame(seed, &fr, info);
1677 seed = generateCompressedBlock(seed, &fr, info);
1681 if (numFiles != 0) {
1682 if (snprintf(outPath, MAX_PATH, "%s/z%06u.zst", path, fnum) + 1 > MAX_PATH) {
1683 DISPLAY("Error: path too long\n");
1687 outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, outPath);
1690 if (snprintf(outPath, MAX_PATH, "%s/z%06u", origPath, fnum) + 1 > MAX_PATH) {
1691 DISPLAY("Error: path too long\n");
1695 outputBuffer(fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart, outPath);
1699 outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, path);
1701 outputBuffer(fr.srcStart, (BYTE*)fr.src - (BYTE*)fr.srcStart, origPath);
1709 return errorDetected;
1713 /*_*******************************************************
1715 *********************************************************/
1716 static U32 makeSeed(void)
1718 U32 t = (U32) time(NULL);
1719 return XXH32(&t, sizeof(t), 0) % 65536;
1722 static unsigned readInt(const char** argument)
1725 while ((**argument>='0') && (**argument<='9')) {
1727 val += **argument - '0';
1733 static void usage(const char* programName)
1735 DISPLAY( "Usage :\n");
1736 DISPLAY( " %s [args]\n", programName);
1738 DISPLAY( "Arguments :\n");
1739 DISPLAY( " -p<path> : select output path (default:stdout)\n");
1740 DISPLAY( " in multiple files mode this should be a directory\n");
1741 DISPLAY( " -o<path> : select path to output original file (default:no output)\n");
1742 DISPLAY( " in multiple files mode this should be a directory\n");
1743 DISPLAY( " -s# : select seed (default:random based on time)\n");
1744 DISPLAY( " -n# : number of files to generate (default:1)\n");
1745 DISPLAY( " -t : activate test mode (test files against libzstd instead of outputting them)\n");
1746 DISPLAY( " -T# : length of time to run tests for\n");
1747 DISPLAY( " -v : increase verbosity level (default:0, max:7)\n");
1748 DISPLAY( " -h/H : display help/long help and exit\n");
1751 static void advancedUsage(const char* programName)
1755 DISPLAY( "Advanced arguments :\n");
1756 DISPLAY( " --content-size : always include the content size in the frame header\n");
1757 DISPLAY( " --use-dict=# : include a dictionary used to decompress the corpus\n");
1758 DISPLAY( " --gen-blocks : generate raw compressed blocks without block/frame headers\n");
1759 DISPLAY( " --max-block-size-log=# : max block size log, must be in range [2, 17]\n");
1760 DISPLAY( " --max-content-size-log=# : max content size log, must be <= 20\n");
1761 DISPLAY( " (this is ignored with gen-blocks)\n");
1764 /*! readU32FromChar() :
1765 @return : unsigned integer value read from input in `char` format
1766 allows and interprets K, KB, KiB, M, MB and MiB suffix.
1767 Will also modify `*stringPtr`, advancing it to position where it stopped reading.
1768 Note : function result can overflow if digit string > MAX_UINT */
1769 static unsigned readU32FromChar(const char** stringPtr)
1771 unsigned result = 0;
1772 while ((**stringPtr >='0') && (**stringPtr <='9'))
1773 result *= 10, result += **stringPtr - '0', (*stringPtr)++ ;
1774 if ((**stringPtr=='K') || (**stringPtr=='M')) {
1776 if (**stringPtr=='M') result <<= 10;
1778 if (**stringPtr=='i') (*stringPtr)++;
1779 if (**stringPtr=='B') (*stringPtr)++;
1784 /** longCommandWArg() :
1785 * check if *stringPtr is the same as longCommand.
1786 * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
1787 * @return 0 and doesn't modify *stringPtr otherwise.
1789 static unsigned longCommandWArg(const char** stringPtr, const char* longCommand)
1791 size_t const comSize = strlen(longCommand);
1792 int const result = !strncmp(*stringPtr, longCommand, comSize);
1793 if (result) *stringPtr += comSize;
1797 int main(int argc, char** argv)
1801 unsigned numFiles = 0;
1802 unsigned testDuration = 0;
1804 const char* path = NULL;
1805 const char* origPath = NULL;
1807 unsigned dictSize = (10 << 10); /* 10 kB default */
1808 genType_e genType = gt_frame;
1812 /* Check command line */
1813 for (argNb=1; argNb<argc; argNb++) {
1814 const char* argument = argv[argNb];
1815 if(!argument) continue; /* Protection if argument empty */
1817 /* Handle commands. Aggregated commands are allowed */
1818 if (argument[0]=='-') {
1820 while (*argument!=0) {
1827 advancedUsage(argv[0]);
1836 seed = readInt(&argument);
1840 numFiles = readInt(&argument);
1844 testDuration = readInt(&argument);
1845 if (*argument == 'm') {
1848 if (*argument == 'n') argument++;
1853 origPath = argument;
1854 argument += strlen(argument);
1859 argument += strlen(argument);
1867 if (strcmp(argument, "content-size") == 0) {
1868 opts.contentSize = 1;
1869 } else if (longCommandWArg(&argument, "use-dict=")) {
1870 dictSize = readU32FromChar(&argument);
1872 } else if (strcmp(argument, "gen-blocks") == 0) {
1874 } else if (longCommandWArg(&argument, "max-block-size-log=")) {
1875 U32 value = readU32FromChar(&argument);
1876 if (value >= 2 && value <= ZSTD_BLOCKSIZE_MAX) {
1877 g_maxBlockSize = 1U << value;
1879 } else if (longCommandWArg(&argument, "max-content-size-log=")) {
1880 U32 value = readU32FromChar(&argument);
1881 g_maxDecompressedSizeLog =
1882 MIN(MAX_DECOMPRESSED_SIZE_LOG, value);
1884 advancedUsage(argv[0]);
1887 argument += strlen(argument);
1892 } } } } /* for (argNb=1; argNb<argc; argNb++) */
1899 return runTestMode(seed, numFiles, testDuration, genType);
1902 DISPLAY("Error: -T requires test mode (-t)\n\n");
1909 DISPLAY("Error: path is required in file generation mode\n");
1914 if (numFiles == 0 && useDict == 0) {
1915 return generateFile(seed, path, origPath, genType);
1916 } else if (useDict == 0){
1917 return generateCorpus(seed, numFiles, path, origPath, genType);
1919 /* should generate files with a dictionary */
1920 return generateCorpusWithDict(seed, numFiles, path, origPath, dictSize, genType);