Update CLI and link from educational decoder

This commit is contained in:
Sean Purcell
2017-02-23 13:06:50 -08:00
parent 485ca8c352
commit 3cd8d50c34
2 changed files with 63 additions and 27 deletions
+10
View File
@@ -17,3 +17,13 @@ It also contains implementations of Huffman and FSE table decoding.
harness <input-file> <output-file> [dictionary] harness <input-file> <output-file> [dictionary]
As an additional resource to be used with this decoder,
see the `decodecorpus` tool in the [tests] directory.
It generates valid Zstandard frames that can be used to verify
a Zstandard decoder implementation.
Note that to use the tool to verify this decoder implementation,
the --content-size flag should be set,
as this decoder does not handle streaming decoding,
and so it must know the decompressed size in advance.
[tests]: https://github.com/facebook/zstd/blob/dev/tests/
+53 -27
View File
@@ -235,12 +235,16 @@ typedef struct {
* Generator Functions * Generator Functions
*********************************************************/ *********************************************************/
struct {
int contentSize; /* force the content size to be present */
} opts; /* advanced options on generation */
/* Generate and write a random frame header */ /* Generate and write a random frame header */
static void writeFrameHeader(U32* seed, frame_t* frame) static void writeFrameHeader(U32* seed, frame_t* frame)
{ {
BYTE* const op = frame->data; BYTE* const op = frame->data;
size_t pos = 0; size_t pos = 0;
frameHeader_t fl; frameHeader_t fh;
BYTE windowByte = 0; BYTE windowByte = 0;
@@ -248,7 +252,7 @@ static void writeFrameHeader(U32* seed, frame_t* frame)
int contentSizeFlag = 0; int contentSizeFlag = 0;
int fcsCode = 0; int fcsCode = 0;
memset(&fl, 0, sizeof(fl)); memset(&fh, 0, sizeof(fh));
/* generate window size */ /* generate window size */
{ {
@@ -256,8 +260,8 @@ static void writeFrameHeader(U32* seed, frame_t* frame)
int const exponent = RAND(seed) % (MAX_WINDOW_LOG - 10); int const exponent = RAND(seed) % (MAX_WINDOW_LOG - 10);
int const mantissa = RAND(seed) % 8; int const mantissa = RAND(seed) % 8;
windowByte = (exponent << 3) | mantissa; windowByte = (exponent << 3) | mantissa;
fl.windowSize = (1U << (exponent + 10)); fh.windowSize = (1U << (exponent + 10));
fl.windowSize += fl.windowSize / 8 * mantissa; fh.windowSize += fh.windowSize / 8 * mantissa;
} }
{ {
@@ -273,28 +277,28 @@ static void writeFrameHeader(U32* seed, frame_t* frame)
/* 0 size frame */ /* 0 size frame */
highBit = 0; highBit = 0;
} }
fl.contentSize = highBit ? highBit + (RAND(seed) % highBit) : 0; fh.contentSize = highBit ? highBit + (RAND(seed) % highBit) : 0;
/* provide size sometimes */ /* provide size sometimes */
contentSizeFlag = RAND(seed) & 1; contentSizeFlag = opts.contentSize | (RAND(seed) & 1);
if (contentSizeFlag && !(RAND(seed) & 7)) { if (contentSizeFlag && (fh.contentSize == 0 || !(RAND(seed) & 7))) {
/* do single segment sometimes */ /* do single segment sometimes */
fl.windowSize = fl.contentSize; fh.windowSize = fh.contentSize;
singleSegment = 1; singleSegment = 1;
} }
} }
if (contentSizeFlag) { if (contentSizeFlag) {
/* Determine how large fcs field has to be */ /* Determine how large fcs field has to be */
int minFcsCode = (fl.contentSize >= 256) + int minFcsCode = (fh.contentSize >= 256) +
(fl.contentSize >= 65536 + 256) + (fh.contentSize >= 65536 + 256) +
(fl.contentSize > 0xFFFFFFFFU); (fh.contentSize > 0xFFFFFFFFU);
if (!singleSegment && !minFcsCode) { if (!singleSegment && !minFcsCode) {
minFcsCode = 1; minFcsCode = 1;
} }
fcsCode = minFcsCode + (RAND(seed) % (4 - minFcsCode)); fcsCode = minFcsCode + (RAND(seed) % (4 - minFcsCode));
if (fcsCode == 1 && fl.contentSize < 256) fcsCode++; if (fcsCode == 1 && fh.contentSize < 256) fcsCode++;
} }
/* write out the header */ /* write out the header */
@@ -314,20 +318,20 @@ static void writeFrameHeader(U32* seed, frame_t* frame)
if (contentSizeFlag) { if (contentSizeFlag) {
switch (fcsCode) { switch (fcsCode) {
default: /* Impossible */ default: /* Impossible */
case 0: op[pos++] = fl.contentSize; break; case 0: op[pos++] = fh.contentSize; break;
case 1: MEM_writeLE16(op + pos, fl.contentSize - 256); pos += 2; break; case 1: MEM_writeLE16(op + pos, fh.contentSize - 256); pos += 2; break;
case 2: MEM_writeLE32(op + pos, fl.contentSize); pos += 4; break; case 2: MEM_writeLE32(op + pos, fh.contentSize); pos += 4; break;
case 3: MEM_writeLE64(op + pos, fl.contentSize); pos += 8; break; case 3: MEM_writeLE64(op + pos, fh.contentSize); pos += 8; break;
} }
} }
DISPLAYLEVEL(2, " frame content size:\t%zu\n", fl.contentSize); DISPLAYLEVEL(2, " frame content size:\t%zu\n", fh.contentSize);
DISPLAYLEVEL(2, " frame window size:\t%u\n", fl.windowSize); DISPLAYLEVEL(2, " frame window size:\t%u\n", fh.windowSize);
DISPLAYLEVEL(2, " content size flag:\t%d\n", contentSizeFlag); DISPLAYLEVEL(2, " content size flag:\t%d\n", contentSizeFlag);
DISPLAYLEVEL(2, " single segment flag:\t%d\n", singleSegment); DISPLAYLEVEL(2, " single segment flag:\t%d\n", singleSegment);
frame->data = op + pos; frame->data = op + pos;
frame->header = fl; frame->header = fh;
} }
/* Write a literal block in either raw or RLE form, return the literals size */ /* Write a literal block in either raw or RLE form, return the literals size */
@@ -1245,6 +1249,8 @@ static int generateFile(U32 seed, const char* const path,
{ {
frame_t fr; frame_t fr;
DISPLAY("seed: %u\n", seed);
generateFrame(seed, &fr); generateFrame(seed, &fr);
outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, path); outputBuffer(fr.dataStart, (BYTE*)fr.data - (BYTE*)fr.dataStart, path);
@@ -1260,11 +1266,6 @@ static int generateCorpus(U32 seed, unsigned numFiles, const char* const path,
char outPath[MAX_PATH]; char outPath[MAX_PATH];
unsigned fnum; unsigned fnum;
if (!path) {
DISPLAY("Error: valid path is required in multiple files mode\n");
return 1;
}
DISPLAY("seed: %u\n", seed); DISPLAY("seed: %u\n", seed);
for (fnum = 0; fnum < numFiles; fnum++) { for (fnum = 0; fnum < numFiles; fnum++) {
@@ -1330,7 +1331,15 @@ static void usage(const char* programName)
DISPLAY( " -t : activate test mode (test files against libzstd instead of outputting them)\n"); DISPLAY( " -t : activate test mode (test files against libzstd instead of outputting them)\n");
DISPLAY( " -T# : length of time to run tests for\n"); DISPLAY( " -T# : length of time to run tests for\n");
DISPLAY( " -v : increase verbosity level (default:0, max:7)\n"); DISPLAY( " -v : increase verbosity level (default:0, max:7)\n");
DISPLAY( " -h : display help and exit\n"); DISPLAY( " -h/H : display help/long help and exit\n");
}
static void advancedUsage(const char* programName)
{
usage(programName);
DISPLAY( "\n");
DISPLAY( "Advanced arguments :\n");
DISPLAY( " --content-size : always include the content size in the frame header\n");
} }
int main(int argc, char** argv) int main(int argc, char** argv)
@@ -1359,6 +1368,9 @@ int main(int argc, char** argv)
case 'h': case 'h':
usage(argv[0]); usage(argv[0]);
return 0; return 0;
case 'H':
advancedUsage(argv[0]);
return 0;
case 'v': case 'v':
argument++; argument++;
g_displayLevel++; g_displayLevel++;
@@ -1395,6 +1407,16 @@ int main(int argc, char** argv)
argument++; argument++;
testMode = 1; testMode = 1;
break; break;
case '-':
argument++;
if (strcmp(argument, "content-size") == 0) {
opts.contentSize = 1;
} else {
advancedUsage(argv[0]);
return 1;
}
argument += strlen(argument);
break;
default: default:
usage(argv[0]); usage(argv[0]);
return 1; return 1;
@@ -1414,11 +1436,15 @@ int main(int argc, char** argv)
} }
} }
if (!path) {
DISPLAY("Error: path is required in file generation mode\n");
usage(argv[0]);
return 1;
}
if (numFiles == 0) { if (numFiles == 0) {
return generateFile(seed, path, origPath); return generateFile(seed, path, origPath);
} else { } else {
return generateCorpus(seed, numFiles, path, origPath); return generateCorpus(seed, numFiles, path, origPath);
} }
return 0;
} }