12b9c00cbSConrad Meyer /* 22b9c00cbSConrad Meyer * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 32b9c00cbSConrad Meyer * All rights reserved. 42b9c00cbSConrad Meyer * 52b9c00cbSConrad Meyer * This source code is licensed under both the BSD-style license (found in the 62b9c00cbSConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found 72b9c00cbSConrad Meyer * in the COPYING file in the root directory of this source tree). 82b9c00cbSConrad Meyer * You may select, at your option, one of the above-listed licenses. 92b9c00cbSConrad Meyer */ 102b9c00cbSConrad Meyer 112b9c00cbSConrad Meyer 122b9c00cbSConrad Meyer #include <stdio.h> // printf 132b9c00cbSConrad Meyer #include <stdlib.h> // free 142b9c00cbSConrad Meyer #include <string.h> // memset, strcat, strlen 152b9c00cbSConrad Meyer #include <zstd.h> // presumes zstd library is installed 162b9c00cbSConrad Meyer #include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD() 172b9c00cbSConrad Meyer 182b9c00cbSConrad Meyer 192b9c00cbSConrad Meyer static void compressFile_orDie(const char* fname, const char* outName, int cLevel) 202b9c00cbSConrad Meyer { 212b9c00cbSConrad Meyer /* Open the input and output files. */ 222b9c00cbSConrad Meyer FILE* const fin = fopen_orDie(fname, "rb"); 232b9c00cbSConrad Meyer FILE* const fout = fopen_orDie(outName, "wb"); 242b9c00cbSConrad Meyer /* Create the input and output buffers. 252b9c00cbSConrad Meyer * They may be any size, but we recommend using these functions to size them. 262b9c00cbSConrad Meyer * Performance will only suffer significantly for very tiny buffers. 272b9c00cbSConrad Meyer */ 282b9c00cbSConrad Meyer size_t const buffInSize = ZSTD_CStreamInSize(); 292b9c00cbSConrad Meyer void* const buffIn = malloc_orDie(buffInSize); 302b9c00cbSConrad Meyer size_t const buffOutSize = ZSTD_CStreamOutSize(); 312b9c00cbSConrad Meyer void* const buffOut = malloc_orDie(buffOutSize); 322b9c00cbSConrad Meyer 332b9c00cbSConrad Meyer /* Create the context. */ 342b9c00cbSConrad Meyer ZSTD_CCtx* const cctx = ZSTD_createCCtx(); 352b9c00cbSConrad Meyer CHECK(cctx != NULL, "ZSTD_createCCtx() failed!"); 362b9c00cbSConrad Meyer 372b9c00cbSConrad Meyer /* Set any parameters you want. 382b9c00cbSConrad Meyer * Here we set the compression level, and enable the checksum. 392b9c00cbSConrad Meyer */ 402b9c00cbSConrad Meyer CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel) ); 412b9c00cbSConrad Meyer CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1) ); 422b9c00cbSConrad Meyer 432b9c00cbSConrad Meyer /* This loop read from the input file, compresses that entire chunk, 442b9c00cbSConrad Meyer * and writes all output produced to the output file. 452b9c00cbSConrad Meyer */ 462b9c00cbSConrad Meyer size_t const toRead = buffInSize; 47*9cbefe25SConrad Meyer for (;;) { 48*9cbefe25SConrad Meyer size_t read = fread_orDie(buffIn, toRead, fin); 492b9c00cbSConrad Meyer /* Select the flush mode. 502b9c00cbSConrad Meyer * If the read may not be finished (read == toRead) we use 512b9c00cbSConrad Meyer * ZSTD_e_continue. If this is the last chunk, we use ZSTD_e_end. 522b9c00cbSConrad Meyer * Zstd optimizes the case where the first flush mode is ZSTD_e_end, 532b9c00cbSConrad Meyer * since it knows it is compressing the entire source in one pass. 542b9c00cbSConrad Meyer */ 552b9c00cbSConrad Meyer int const lastChunk = (read < toRead); 562b9c00cbSConrad Meyer ZSTD_EndDirective const mode = lastChunk ? ZSTD_e_end : ZSTD_e_continue; 572b9c00cbSConrad Meyer /* Set the input buffer to what we just read. 582b9c00cbSConrad Meyer * We compress until the input buffer is empty, each time flushing the 592b9c00cbSConrad Meyer * output. 602b9c00cbSConrad Meyer */ 612b9c00cbSConrad Meyer ZSTD_inBuffer input = { buffIn, read, 0 }; 622b9c00cbSConrad Meyer int finished; 632b9c00cbSConrad Meyer do { 642b9c00cbSConrad Meyer /* Compress into the output buffer and write all of the output to 652b9c00cbSConrad Meyer * the file so we can reuse the buffer next iteration. 662b9c00cbSConrad Meyer */ 672b9c00cbSConrad Meyer ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; 682b9c00cbSConrad Meyer size_t const remaining = ZSTD_compressStream2(cctx, &output , &input, mode); 692b9c00cbSConrad Meyer CHECK_ZSTD(remaining); 702b9c00cbSConrad Meyer fwrite_orDie(buffOut, output.pos, fout); 712b9c00cbSConrad Meyer /* If we're on the last chunk we're finished when zstd returns 0, 722b9c00cbSConrad Meyer * which means its consumed all the input AND finished the frame. 732b9c00cbSConrad Meyer * Otherwise, we're finished when we've consumed all the input. 742b9c00cbSConrad Meyer */ 752b9c00cbSConrad Meyer finished = lastChunk ? (remaining == 0) : (input.pos == input.size); 762b9c00cbSConrad Meyer } while (!finished); 772b9c00cbSConrad Meyer CHECK(input.pos == input.size, 782b9c00cbSConrad Meyer "Impossible: zstd only returns 0 when the input is completely consumed!"); 79*9cbefe25SConrad Meyer 80*9cbefe25SConrad Meyer if (lastChunk) { 81*9cbefe25SConrad Meyer break; 82*9cbefe25SConrad Meyer } 832b9c00cbSConrad Meyer } 842b9c00cbSConrad Meyer 852b9c00cbSConrad Meyer ZSTD_freeCCtx(cctx); 862b9c00cbSConrad Meyer fclose_orDie(fout); 872b9c00cbSConrad Meyer fclose_orDie(fin); 882b9c00cbSConrad Meyer free(buffIn); 892b9c00cbSConrad Meyer free(buffOut); 902b9c00cbSConrad Meyer } 912b9c00cbSConrad Meyer 922b9c00cbSConrad Meyer 932b9c00cbSConrad Meyer static char* createOutFilename_orDie(const char* filename) 942b9c00cbSConrad Meyer { 952b9c00cbSConrad Meyer size_t const inL = strlen(filename); 962b9c00cbSConrad Meyer size_t const outL = inL + 5; 972b9c00cbSConrad Meyer void* const outSpace = malloc_orDie(outL); 982b9c00cbSConrad Meyer memset(outSpace, 0, outL); 992b9c00cbSConrad Meyer strcat(outSpace, filename); 1002b9c00cbSConrad Meyer strcat(outSpace, ".zst"); 1012b9c00cbSConrad Meyer return (char*)outSpace; 1022b9c00cbSConrad Meyer } 1032b9c00cbSConrad Meyer 1042b9c00cbSConrad Meyer int main(int argc, const char** argv) 1052b9c00cbSConrad Meyer { 1062b9c00cbSConrad Meyer const char* const exeName = argv[0]; 1072b9c00cbSConrad Meyer 1082b9c00cbSConrad Meyer if (argc!=2) { 1092b9c00cbSConrad Meyer printf("wrong arguments\n"); 1102b9c00cbSConrad Meyer printf("usage:\n"); 1112b9c00cbSConrad Meyer printf("%s FILE\n", exeName); 1122b9c00cbSConrad Meyer return 1; 1132b9c00cbSConrad Meyer } 1142b9c00cbSConrad Meyer 1152b9c00cbSConrad Meyer const char* const inFilename = argv[1]; 1162b9c00cbSConrad Meyer 1172b9c00cbSConrad Meyer char* const outFilename = createOutFilename_orDie(inFilename); 1182b9c00cbSConrad Meyer compressFile_orDie(inFilename, outFilename, 1); 1192b9c00cbSConrad Meyer 1202b9c00cbSConrad Meyer free(outFilename); /* not strictly required, since program execution stops there, 1212b9c00cbSConrad Meyer * but some static analyzer main complain otherwise */ 1222b9c00cbSConrad Meyer return 0; 1232b9c00cbSConrad Meyer } 124