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