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