Path: blob/main/sys/contrib/zstd/examples/streaming_decompression.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> // fprintf12#include <stdlib.h> // free13#include <zstd.h> // presumes zstd library is installed14#include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD()1516static void decompressFile_orDie(const char* fname)17{18FILE* const fin = fopen_orDie(fname, "rb");19size_t const buffInSize = ZSTD_DStreamInSize();20void* const buffIn = malloc_orDie(buffInSize);21FILE* const fout = stdout;22size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */23void* const buffOut = malloc_orDie(buffOutSize);2425ZSTD_DCtx* const dctx = ZSTD_createDCtx();26CHECK(dctx != NULL, "ZSTD_createDCtx() failed!");2728/* This loop assumes that the input file is one or more concatenated zstd29* streams. This example won't work if there is trailing non-zstd data at30* the end, but streaming decompression in general handles this case.31* ZSTD_decompressStream() returns 0 exactly when the frame is completed,32* and doesn't consume input after the frame.33*/34size_t const toRead = buffInSize;35size_t read;36size_t lastRet = 0;37int isEmpty = 1;38while ( (read = fread_orDie(buffIn, toRead, fin)) ) {39isEmpty = 0;40ZSTD_inBuffer input = { buffIn, read, 0 };41/* Given a valid frame, zstd won't consume the last byte of the frame42* until it has flushed all of the decompressed data of the frame.43* Therefore, instead of checking if the return code is 0, we can44* decompress just check if input.pos < input.size.45*/46while (input.pos < input.size) {47ZSTD_outBuffer output = { buffOut, buffOutSize, 0 };48/* The return code is zero if the frame is complete, but there may49* be multiple frames concatenated together. Zstd will automatically50* reset the context when a frame is complete. Still, calling51* ZSTD_DCtx_reset() can be useful to reset the context to a clean52* state, for instance if the last decompression call returned an53* error.54*/55size_t const ret = ZSTD_decompressStream(dctx, &output , &input);56CHECK_ZSTD(ret);57fwrite_orDie(buffOut, output.pos, fout);58lastRet = ret;59}60}6162if (isEmpty) {63fprintf(stderr, "input is empty\n");64exit(1);65}6667if (lastRet != 0) {68/* The last return value from ZSTD_decompressStream did not end on a69* frame, but we reached the end of the file! We assume this is an70* error, and the input was truncated.71*/72fprintf(stderr, "EOF before end of stream: %zu\n", lastRet);73exit(1);74}7576ZSTD_freeDCtx(dctx);77fclose_orDie(fin);78fclose_orDie(fout);79free(buffIn);80free(buffOut);81}828384int main(int argc, const char** argv)85{86const char* const exeName = argv[0];8788if (argc!=2) {89fprintf(stderr, "wrong arguments\n");90fprintf(stderr, "usage:\n");91fprintf(stderr, "%s FILE\n", exeName);92return 1;93}9495const char* const inFilename = argv[1];9697decompressFile_orDie(inFilename);98return 0;99}100101102