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