Path: blob/main/sys/contrib/zstd/examples/streaming_compression.c
48249 views
/*1* Copyright (c) Yann Collet, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under both the BSD-style license (found in the5* LICENSE file in the root directory of this source tree) and the GPLv2 (found6* in the COPYING file in the root directory of this source tree).7* You may select, at your option, one of the above-listed licenses.8*/91011#include <stdio.h> // printf12#include <stdlib.h> // free13#include <string.h> // memset, strcat, strlen14#include <zstd.h> // presumes zstd library is installed15#include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD()1617static void compressFile_orDie(const char* fname, const char* outName, int cLevel,18int nbThreads)19{20fprintf (stderr, "Starting compression of %s with level %d, using %d threads\n",21fname, cLevel, nbThreads);2223/* Open the input and output files. */24FILE* const fin = fopen_orDie(fname, "rb");25FILE* const fout = fopen_orDie(outName, "wb");26/* Create the input and output buffers.27* They may be any size, but we recommend using these functions to size them.28* Performance will only suffer significantly for very tiny buffers.29*/30size_t const buffInSize = ZSTD_CStreamInSize();31void* const buffIn = malloc_orDie(buffInSize);32size_t const buffOutSize = ZSTD_CStreamOutSize();33void* const buffOut = malloc_orDie(buffOutSize);3435/* Create the context. */36ZSTD_CCtx* const cctx = ZSTD_createCCtx();37CHECK(cctx != NULL, "ZSTD_createCCtx() failed!");3839/* Set any parameters you want.40* Here we set the compression level, and enable the checksum.41*/42CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel) );43CHECK_ZSTD( ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1) );44ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, nbThreads);4546/* This loop read from the input file, compresses that entire chunk,47* and writes all output produced to the output file.48*/49size_t const toRead = buffInSize;50for (;;) {51size_t read = fread_orDie(buffIn, toRead, fin);52/* Select the flush mode.53* If the read may not be finished (read == toRead) we use54* ZSTD_e_continue. If this is the last chunk, we use ZSTD_e_end.55* Zstd optimizes the case where the first flush mode is ZSTD_e_end,56* since it knows it is compressing the entire source in one pass.57*/58int const lastChunk = (read < toRead);59ZSTD_EndDirective const mode = lastChunk ? ZSTD_e_end : ZSTD_e_continue;60/* Set the input buffer to what we just read.61* We compress until the input buffer is empty, each time flushing the62* output.63*/64ZSTD_inBuffer input = { buffIn, read, 0 };65int finished;66do {67/* Compress into the output buffer and write all of the output to68* the file so we can reuse the buffer next iteration.69*/70ZSTD_outBuffer output = { buffOut, buffOutSize, 0 };71size_t const remaining = ZSTD_compressStream2(cctx, &output , &input, mode);72CHECK_ZSTD(remaining);73fwrite_orDie(buffOut, output.pos, fout);74/* If we're on the last chunk we're finished when zstd returns 0,75* which means its consumed all the input AND finished the frame.76* Otherwise, we're finished when we've consumed all the input.77*/78finished = lastChunk ? (remaining == 0) : (input.pos == input.size);79} while (!finished);80CHECK(input.pos == input.size,81"Impossible: zstd only returns 0 when the input is completely consumed!");8283if (lastChunk) {84break;85}86}8788ZSTD_freeCCtx(cctx);89fclose_orDie(fout);90fclose_orDie(fin);91free(buffIn);92free(buffOut);93}949596static char* createOutFilename_orDie(const char* filename)97{98size_t const inL = strlen(filename);99size_t const outL = inL + 5;100void* const outSpace = malloc_orDie(outL);101memset(outSpace, 0, outL);102strcat(outSpace, filename);103strcat(outSpace, ".zst");104return (char*)outSpace;105}106107int main(int argc, const char** argv)108{109const char* const exeName = argv[0];110111if (argc < 2) {112printf("wrong arguments\n");113printf("usage:\n");114printf("%s FILE [LEVEL] [THREADS]\n", exeName);115return 1;116}117118int cLevel = 1;119int nbThreads = 4;120121if (argc >= 3) {122cLevel = atoi (argv[2]);123CHECK(cLevel != 0, "can't parse LEVEL!");124}125126if (argc >= 4) {127nbThreads = atoi (argv[3]);128CHECK(nbThreads != 0, "can't parse THREADS!");129}130131const char* const inFilename = argv[1];132133char* const outFilename = createOutFilename_orDie(inFilename);134compressFile_orDie(inFilename, outFilename, cLevel, nbThreads);135136free(outFilename); /* not strictly required, since program execution stops there,137* but some static analyzer may complain otherwise */138return 0;139}140141142