]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
[examples] Update multiple_streaming_compression.c
authorNick Terrell <terrelln@fb.com>
Mon, 1 Apr 2019 23:41:06 +0000 (16:41 -0700)
committerNick Terrell <terrelln@fb.com>
Mon, 1 Apr 2019 23:41:06 +0000 (16:41 -0700)
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.

examples/multiple_streaming_compression.c

index 442ff40ae29d469261ddecc5d5e2dc079cb5d686..0054c7b0093277057eb9c00a540740f04847ac14 100644 (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);