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