[examples] Update multiple_streaming_compression.c

Update to use the new streaming API. Making progress on Issue #1548.

Tested that multiple files could be compressed, and that the output
is the same as calling `streaming_compression` multiple times with
the same compression level, and that it can be decompressed.
dev
Nick Terrell 2019-04-01 16:41:06 -07:00
parent 425ce5547c
commit fb13d757af
1 changed files with 42 additions and 26 deletions

View File

@ -18,7 +18,7 @@
#include <stdio.h> // fprintf, perror, feof
#include <string.h> // strerror
#include <errno.h> // errno
#define ZSTD_STATIC_LINKING_ONLY // streaming API defined as "experimental" for the time being
#define ZSTD_STATIC_LINKING_ONLY // TODO: Remove once the API is stable
#include <zstd.h> // presumes zstd library is installed
#include "utils.h"
@ -27,53 +27,68 @@ typedef struct {
void* buffOut;
size_t buffInSize;
size_t buffOutSize;
ZSTD_CStream* cstream;
} resources ;
ZSTD_CCtx* cctx;
} resources;
static resources createResources_orDie()
static resources createResources_orDie(int cLevel)
{
resources ress;
ress.buffInSize = ZSTD_CStreamInSize(); /* can always read one full block */
ress.buffOutSize= ZSTD_CStreamOutSize(); /* can always flush a full block */
ress.buffIn = malloc_orDie(ress.buffInSize);
ress.buffOut= malloc_orDie(ress.buffOutSize);
ress.cstream = ZSTD_createCStream();
if (ress.cstream==NULL) { fprintf(stderr, "ZSTD_createCStream() error \n"); exit(10); }
ress.cctx = ZSTD_createCCtx();
CHECK(ress.cctx != NULL, "ZSTD_createCCtx() failed!");
/* Set any compression parameters you want here.
* They will persist for every compression operation.
* Here we set the compression level, and enable the checksum.
*/
CHECK_ZSTD( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_compressionLevel, cLevel) );
CHECK_ZSTD( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_checksumFlag, 1) );
return ress;
}
static void freeResources(resources ress)
{
ZSTD_freeCStream(ress.cstream);
ZSTD_freeCCtx(ress.cctx);
free(ress.buffIn);
free(ress.buffOut);
}
static void compressFile_orDie(resources ress, const char* fname, const char* outName, int cLevel)
static void compressFile_orDie(resources ress, const char* fname, const char* outName)
{
// Open the input and output files.
FILE* const fin = fopen_orDie(fname, "rb");
FILE* const fout = fopen_orDie(outName, "wb");
size_t const initResult = ZSTD_initCStream(ress.cstream, cLevel);
if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_initCStream() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); }
/* Reset the context to a clean state to start a new compression operation.
* The parameters are sticky, so we keep the compression level and extra
* parameters that we set in createResources_orDie().
*/
CHECK_ZSTD( ZSTD_CCtx_reset(ress.cctx, ZSTD_reset_session_only) );
size_t const toRead = ress.buffInSize;
size_t read;
while ( (read = fread_orDie(ress.buffIn, toRead, fin)) ) {
/* This loop is the same as streaming_compression.c.
* See that file for detailed comments.
*/
int const lastChunk = (read < toRead);
ZSTD_EndDirective const mode = lastChunk ? ZSTD_e_end : ZSTD_e_continue;
size_t read, toRead = ress.buffInSize;
while( (read = fread_orDie(ress.buffIn, toRead, fin)) ) {
ZSTD_inBuffer input = { ress.buffIn, read, 0 };
while (input.pos < input.size) {
ZSTD_outBuffer output = { ress.buffOut, ress.buffOutSize, 0 };
toRead = ZSTD_compressStream(ress.cstream, &output , &input); /* toRead is guaranteed to be <= ZSTD_CStreamInSize() */
if (ZSTD_isError(toRead)) { fprintf(stderr, "ZSTD_compressStream() error : %s \n", ZSTD_getErrorName(toRead)); exit(12); }
if (toRead > ress.buffInSize) toRead = ress.buffInSize; /* Safely handle when `buffInSize` is manually changed to a smaller value */
fwrite_orDie(ress.buffOut, output.pos, fout);
}
int finished;
do {
ZSTD_outBuffer output = { ress.buffOut, ress.buffOutSize, 0 };
size_t const remaining = ZSTD_compressStream2(ress.cctx, &output, &input, mode);
CHECK_ZSTD(remaining);
fwrite_orDie(ress.buffOut, output.pos, fout);
finished = lastChunk ? (remaining == 0) : (input.pos == input.size);
} while (!finished);
assert(input.pos == input.size);
}
ZSTD_outBuffer output = { ress.buffOut, ress.buffOutSize, 0 };
size_t const remainingToFlush = ZSTD_endStream(ress.cstream, &output); /* close frame */
if (remainingToFlush) { fprintf(stderr, "not fully flushed"); exit(13); }
fwrite_orDie(ress.buffOut, output.pos, fout);
fclose_orDie(fout);
fclose_orDie(fin);
}
@ -89,7 +104,8 @@ int main(int argc, const char** argv)
return 1;
}
resources const ress = createResources_orDie();
int const cLevel = 7;
resources const ress = createResources_orDie(cLevel);
void* ofnBuffer = NULL;
size_t ofnbSize = 0;
@ -106,7 +122,7 @@ int main(int argc, const char** argv)
memset(ofnBuffer, 0, ofnSize);
strcat(ofnBuffer, ifn);
strcat(ofnBuffer, ".zst");
compressFile_orDie(ress, ifn, ofnBuffer, 7);
compressFile_orDie(ress, ifn, ofnBuffer);
}
freeResources(ress);