#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"
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);
}
return 1;
}
- resources const ress = createResources_orDie();
+ int const cLevel = 7;
+ resources const ress = createResources_orDie(cLevel);
void* ofnBuffer = NULL;
size_t ofnbSize = 0;
memset(ofnBuffer, 0, ofnSize);
strcat(ofnBuffer, ifn);
strcat(ofnBuffer, ".zst");
- compressFile_orDie(ress, ifn, ofnBuffer, 7);
+ compressFile_orDie(ress, ifn, ofnBuffer);
}
freeResources(ress);