648db22b |
1 | /* |
2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
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 | } |