Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/zstd/examples/streaming_decompression.c
48249 views
1
/*
2
* Copyright (c) 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
#include <stdio.h> // fprintf
13
#include <stdlib.h> // free
14
#include <zstd.h> // presumes zstd library is installed
15
#include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD()
16
17
static void decompressFile_orDie(const char* fname)
18
{
19
FILE* const fin = fopen_orDie(fname, "rb");
20
size_t const buffInSize = ZSTD_DStreamInSize();
21
void* const buffIn = malloc_orDie(buffInSize);
22
FILE* const fout = stdout;
23
size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */
24
void* const buffOut = malloc_orDie(buffOutSize);
25
26
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
27
CHECK(dctx != NULL, "ZSTD_createDCtx() failed!");
28
29
/* This loop assumes that the input file is one or more concatenated zstd
30
* streams. This example won't work if there is trailing non-zstd data at
31
* the end, but streaming decompression in general handles this case.
32
* ZSTD_decompressStream() returns 0 exactly when the frame is completed,
33
* and doesn't consume input after the frame.
34
*/
35
size_t const toRead = buffInSize;
36
size_t read;
37
size_t lastRet = 0;
38
int isEmpty = 1;
39
while ( (read = fread_orDie(buffIn, toRead, fin)) ) {
40
isEmpty = 0;
41
ZSTD_inBuffer input = { buffIn, read, 0 };
42
/* Given a valid frame, zstd won't consume the last byte of the frame
43
* until it has flushed all of the decompressed data of the frame.
44
* Therefore, instead of checking if the return code is 0, we can
45
* decompress just check if input.pos < input.size.
46
*/
47
while (input.pos < input.size) {
48
ZSTD_outBuffer output = { buffOut, buffOutSize, 0 };
49
/* The return code is zero if the frame is complete, but there may
50
* be multiple frames concatenated together. Zstd will automatically
51
* reset the context when a frame is complete. Still, calling
52
* ZSTD_DCtx_reset() can be useful to reset the context to a clean
53
* state, for instance if the last decompression call returned an
54
* error.
55
*/
56
size_t const ret = ZSTD_decompressStream(dctx, &output , &input);
57
CHECK_ZSTD(ret);
58
fwrite_orDie(buffOut, output.pos, fout);
59
lastRet = ret;
60
}
61
}
62
63
if (isEmpty) {
64
fprintf(stderr, "input is empty\n");
65
exit(1);
66
}
67
68
if (lastRet != 0) {
69
/* The last return value from ZSTD_decompressStream did not end on a
70
* frame, but we reached the end of the file! We assume this is an
71
* error, and the input was truncated.
72
*/
73
fprintf(stderr, "EOF before end of stream: %zu\n", lastRet);
74
exit(1);
75
}
76
77
ZSTD_freeDCtx(dctx);
78
fclose_orDie(fin);
79
fclose_orDie(fout);
80
free(buffIn);
81
free(buffOut);
82
}
83
84
85
int main(int argc, const char** argv)
86
{
87
const char* const exeName = argv[0];
88
89
if (argc!=2) {
90
fprintf(stderr, "wrong arguments\n");
91
fprintf(stderr, "usage:\n");
92
fprintf(stderr, "%s FILE\n", exeName);
93
return 1;
94
}
95
96
const char* const inFilename = argv[1];
97
98
decompressFile_orDie(inFilename);
99
return 0;
100
}
101
102