xref: /netbsd-src/external/bsd/zstd/dist/examples/multiple_streaming_compression.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos 
11*3117ece4Schristos 
12*3117ece4Schristos /* The objective of this example is to show of to compress multiple successive files
13*3117ece4Schristos *  while preserving memory management.
14*3117ece4Schristos *  All structures and buffers will be created only once,
15*3117ece4Schristos *  and shared across all compression operations */
16*3117ece4Schristos 
17*3117ece4Schristos #include <stdio.h>     // printf
18*3117ece4Schristos #include <stdlib.h>    // free
19*3117ece4Schristos #include <string.h>    // memset, strcat
20*3117ece4Schristos #include <zstd.h>      // presumes zstd library is installed
21*3117ece4Schristos #include "common.h"    // Helper functions, CHECK(), and CHECK_ZSTD()
22*3117ece4Schristos 
23*3117ece4Schristos typedef struct {
24*3117ece4Schristos     void* buffIn;
25*3117ece4Schristos     void* buffOut;
26*3117ece4Schristos     size_t buffInSize;
27*3117ece4Schristos     size_t buffOutSize;
28*3117ece4Schristos     ZSTD_CCtx* cctx;
29*3117ece4Schristos } resources;
30*3117ece4Schristos 
31*3117ece4Schristos static resources createResources_orDie(int cLevel)
32*3117ece4Schristos {
33*3117ece4Schristos     resources ress;
34*3117ece4Schristos     ress.buffInSize = ZSTD_CStreamInSize();   /* can always read one full block */
35*3117ece4Schristos     ress.buffOutSize= ZSTD_CStreamOutSize();  /* can always flush a full block */
36*3117ece4Schristos     ress.buffIn = malloc_orDie(ress.buffInSize);
37*3117ece4Schristos     ress.buffOut= malloc_orDie(ress.buffOutSize);
38*3117ece4Schristos     ress.cctx = ZSTD_createCCtx();
39*3117ece4Schristos     CHECK(ress.cctx != NULL, "ZSTD_createCCtx() failed!");
40*3117ece4Schristos 
41*3117ece4Schristos     /* Set any compression parameters you want here.
42*3117ece4Schristos      * They will persist for every compression operation.
43*3117ece4Schristos      * Here we set the compression level, and enable the checksum.
44*3117ece4Schristos      */
45*3117ece4Schristos     CHECK_ZSTD( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_compressionLevel, cLevel) );
46*3117ece4Schristos     CHECK_ZSTD( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_checksumFlag, 1) );
47*3117ece4Schristos     return ress;
48*3117ece4Schristos }
49*3117ece4Schristos 
50*3117ece4Schristos static void freeResources(resources ress)
51*3117ece4Schristos {
52*3117ece4Schristos     ZSTD_freeCCtx(ress.cctx);
53*3117ece4Schristos     free(ress.buffIn);
54*3117ece4Schristos     free(ress.buffOut);
55*3117ece4Schristos }
56*3117ece4Schristos 
57*3117ece4Schristos static void compressFile_orDie(resources ress, const char* fname, const char* outName)
58*3117ece4Schristos {
59*3117ece4Schristos     // Open the input and output files.
60*3117ece4Schristos     FILE* const fin  = fopen_orDie(fname, "rb");
61*3117ece4Schristos     FILE* const fout = fopen_orDie(outName, "wb");
62*3117ece4Schristos 
63*3117ece4Schristos     /* Reset the context to a clean state to start a new compression operation.
64*3117ece4Schristos      * The parameters are sticky, so we keep the compression level and extra
65*3117ece4Schristos      * parameters that we set in createResources_orDie().
66*3117ece4Schristos      */
67*3117ece4Schristos     CHECK_ZSTD( ZSTD_CCtx_reset(ress.cctx, ZSTD_reset_session_only) );
68*3117ece4Schristos 
69*3117ece4Schristos     size_t const toRead = ress.buffInSize;
70*3117ece4Schristos     size_t read;
71*3117ece4Schristos     while ( (read = fread_orDie(ress.buffIn, toRead, fin)) ) {
72*3117ece4Schristos         /* This loop is the same as streaming_compression.c.
73*3117ece4Schristos          * See that file for detailed comments.
74*3117ece4Schristos          */
75*3117ece4Schristos         int const lastChunk = (read < toRead);
76*3117ece4Schristos         ZSTD_EndDirective const mode = lastChunk ? ZSTD_e_end : ZSTD_e_continue;
77*3117ece4Schristos 
78*3117ece4Schristos         ZSTD_inBuffer input = { ress.buffIn, read, 0 };
79*3117ece4Schristos         int finished;
80*3117ece4Schristos         do {
81*3117ece4Schristos             ZSTD_outBuffer output = { ress.buffOut, ress.buffOutSize, 0 };
82*3117ece4Schristos             size_t const remaining = ZSTD_compressStream2(ress.cctx, &output, &input, mode);
83*3117ece4Schristos             CHECK_ZSTD(remaining);
84*3117ece4Schristos             fwrite_orDie(ress.buffOut, output.pos, fout);
85*3117ece4Schristos             finished = lastChunk ? (remaining == 0) : (input.pos == input.size);
86*3117ece4Schristos         } while (!finished);
87*3117ece4Schristos         CHECK(input.pos == input.size,
88*3117ece4Schristos               "Impossible: zstd only returns 0 when the input is completely consumed!");
89*3117ece4Schristos     }
90*3117ece4Schristos 
91*3117ece4Schristos     fclose_orDie(fout);
92*3117ece4Schristos     fclose_orDie(fin);
93*3117ece4Schristos }
94*3117ece4Schristos 
95*3117ece4Schristos int main(int argc, const char** argv)
96*3117ece4Schristos {
97*3117ece4Schristos     const char* const exeName = argv[0];
98*3117ece4Schristos 
99*3117ece4Schristos     if (argc<2) {
100*3117ece4Schristos         printf("wrong arguments\n");
101*3117ece4Schristos         printf("usage:\n");
102*3117ece4Schristos         printf("%s FILE(s)\n", exeName);
103*3117ece4Schristos         return 1;
104*3117ece4Schristos     }
105*3117ece4Schristos 
106*3117ece4Schristos     int const cLevel = 7;
107*3117ece4Schristos     resources const ress = createResources_orDie(cLevel);
108*3117ece4Schristos     void* ofnBuffer = NULL;
109*3117ece4Schristos     size_t ofnbSize = 0;
110*3117ece4Schristos 
111*3117ece4Schristos     int argNb;
112*3117ece4Schristos     for (argNb = 1; argNb < argc; argNb++) {
113*3117ece4Schristos         const char* const ifn = argv[argNb];
114*3117ece4Schristos         size_t const ifnSize = strlen(ifn);
115*3117ece4Schristos         size_t const ofnSize = ifnSize + 5;
116*3117ece4Schristos         if (ofnbSize <= ofnSize) {
117*3117ece4Schristos             ofnbSize = ofnSize + 16;
118*3117ece4Schristos             free(ofnBuffer);
119*3117ece4Schristos             ofnBuffer = malloc_orDie(ofnbSize);
120*3117ece4Schristos         }
121*3117ece4Schristos         memset(ofnBuffer, 0, ofnSize);
122*3117ece4Schristos         strcat(ofnBuffer, ifn);
123*3117ece4Schristos         strcat(ofnBuffer, ".zst");
124*3117ece4Schristos         compressFile_orDie(ress, ifn, ofnBuffer);
125*3117ece4Schristos     }
126*3117ece4Schristos 
127*3117ece4Schristos     freeResources(ress);
128*3117ece4Schristos     free(ofnBuffer);
129*3117ece4Schristos 
130*3117ece4Schristos     printf("compressed %i files \n", argc-1);
131*3117ece4Schristos 
132*3117ece4Schristos     return 0;
133*3117ece4Schristos }
134