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