1 /* 2 * Copyright (c) 2016-2020, 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