1 /***********************************************************************************************************************************
2 Compression Helper
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <string.h>
7
8 #include "common/compress/helper.h"
9 #include "common/compress/bz2/common.h"
10 #include "common/compress/bz2/compress.h"
11 #include "common/compress/bz2/decompress.h"
12 #include "common/compress/gz/common.h"
13 #include "common/compress/gz/compress.h"
14 #include "common/compress/gz/decompress.h"
15 #include "common/compress/lz4/common.h"
16 #include "common/compress/lz4/compress.h"
17 #include "common/compress/lz4/decompress.h"
18 #include "common/compress/zst/common.h"
19 #include "common/compress/zst/compress.h"
20 #include "common/compress/zst/decompress.h"
21 #include "common/debug.h"
22 #include "common/log.h"
23 #include "version.h"
24
25 /***********************************************************************************************************************************
26 Compression type constants
27 ***********************************************************************************************************************************/
28 #define COMPRESS_TYPE_NONE "none"
29
30 // Constants for currently unsupported compression types
31 #define XZ_EXT "xz"
32
33 /***********************************************************************************************************************************
34 Configuration for supported and future compression types
35 ***********************************************************************************************************************************/
36 static const struct CompressHelperLocal
37 {
38 const String *const type; // Compress type -- must be extension without period prefixed
39 const String *const ext; // File extension with period prefixed
40 const char *compressType; // Type of the compression filter
41 IoFilter *(*compressNew)(int); // Function to create new compression filter
42 const char *decompressType; // Type of the decompression filter
43 IoFilter *(*decompressNew)(void); // Function to create new decompression filter
44 int levelDefault; // Default compression level
45 } compressHelperLocal[] =
46 {
47 {
48 .type = STRDEF(COMPRESS_TYPE_NONE),
49 .ext = STRDEF(""),
50 },
51 {
52 .type = STRDEF(BZ2_EXT),
53 .ext = STRDEF("." BZ2_EXT),
54 .compressType = BZ2_COMPRESS_FILTER_TYPE,
55 .compressNew = bz2CompressNew,
56 .decompressType = BZ2_DECOMPRESS_FILTER_TYPE,
57 .decompressNew = bz2DecompressNew,
58 .levelDefault = 9,
59 },
60 {
61 .type = STRDEF(GZ_EXT),
62 .ext = STRDEF("." GZ_EXT),
63 .compressType = GZ_COMPRESS_FILTER_TYPE,
64 .compressNew = gzCompressNew,
65 .decompressType = GZ_DECOMPRESS_FILTER_TYPE,
66 .decompressNew = gzDecompressNew,
67 .levelDefault = 6,
68 },
69 {
70 .type = STRDEF(LZ4_EXT),
71 .ext = STRDEF("." LZ4_EXT),
72 #ifdef HAVE_LIBLZ4
73 .compressType = LZ4_COMPRESS_FILTER_TYPE,
74 .compressNew = lz4CompressNew,
75 .decompressType = LZ4_DECOMPRESS_FILTER_TYPE,
76 .decompressNew = lz4DecompressNew,
77 .levelDefault = 1,
78 #endif
79 },
80 {
81 .type = STRDEF(ZST_EXT),
82 .ext = STRDEF("." ZST_EXT),
83 #ifdef HAVE_LIBZST
84 .compressType = ZST_COMPRESS_FILTER_TYPE,
85 .compressNew = zstCompressNew,
86 .decompressType = ZST_DECOMPRESS_FILTER_TYPE,
87 .decompressNew = zstDecompressNew,
88 .levelDefault = 3,
89 #endif
90 },
91 {
92 .type = STRDEF(XZ_EXT),
93 .ext = STRDEF("." XZ_EXT),
94 },
95 {
96 .type = STRDEF(BZ2_EXT),
97 .ext = STRDEF("." BZ2_EXT),
98 },
99 };
100
101 #define COMPRESS_LIST_SIZE \
102 (sizeof(compressHelperLocal) / sizeof(struct CompressHelperLocal))
103
104 /**********************************************************************************************************************************/
105 CompressType
compressTypeEnum(const String * type)106 compressTypeEnum(const String *type)
107 {
108 FUNCTION_TEST_BEGIN();
109 FUNCTION_TEST_PARAM(STRING, type);
110 FUNCTION_TEST_END();
111
112 ASSERT(type != NULL);
113
114 CompressType result = compressTypeNone;
115
116 for (; result < COMPRESS_LIST_SIZE; result++)
117 {
118 if (strEq(type, compressHelperLocal[result].type))
119 break;
120 }
121
122 if (result == COMPRESS_LIST_SIZE)
123 THROW_FMT(AssertError, "invalid compression type '%s'", strZ(type));
124
125 FUNCTION_TEST_RETURN(result);
126 }
127
128 /**********************************************************************************************************************************/
129 void
compressTypePresent(CompressType type)130 compressTypePresent(CompressType type)
131 {
132 FUNCTION_TEST_BEGIN();
133 FUNCTION_TEST_PARAM(ENUM, type);
134 FUNCTION_TEST_END();
135
136 ASSERT(type < COMPRESS_LIST_SIZE);
137
138 if (type != compressTypeNone && compressHelperLocal[type].compressNew == NULL)
139 THROW_FMT(OptionInvalidValueError, PROJECT_NAME " not compiled with %s support", strZ(compressHelperLocal[type].type));
140
141 FUNCTION_TEST_RETURN_VOID();
142 }
143
144 /**********************************************************************************************************************************/
145 const String *
compressTypeStr(CompressType type)146 compressTypeStr(CompressType type)
147 {
148 FUNCTION_TEST_BEGIN();
149 FUNCTION_TEST_PARAM(ENUM, type);
150 FUNCTION_TEST_END();
151
152 ASSERT(type < COMPRESS_LIST_SIZE);
153
154 FUNCTION_TEST_RETURN(compressHelperLocal[type].type);
155 }
156
157 /**********************************************************************************************************************************/
158 CompressType
compressTypeFromName(const String * name)159 compressTypeFromName(const String *name)
160 {
161 FUNCTION_TEST_BEGIN();
162 FUNCTION_TEST_PARAM(STRING, name);
163 FUNCTION_TEST_END();
164
165 CompressType result = compressTypeNone + 1;
166
167 for (; result < COMPRESS_LIST_SIZE; result++)
168 {
169 if (strEndsWith(name, compressHelperLocal[result].ext))
170 break;
171 }
172
173 if (result == COMPRESS_LIST_SIZE)
174 result = compressTypeNone;
175
176 FUNCTION_TEST_RETURN(result);
177 }
178
179 /**********************************************************************************************************************************/
180 int
compressLevelDefault(CompressType type)181 compressLevelDefault(CompressType type)
182 {
183 FUNCTION_TEST_BEGIN();
184 FUNCTION_TEST_PARAM(ENUM, type);
185 FUNCTION_TEST_END();
186
187 ASSERT(type < COMPRESS_LIST_SIZE);
188 compressTypePresent(type);
189
190 FUNCTION_TEST_RETURN(compressHelperLocal[type].levelDefault);
191 }
192
193 /**********************************************************************************************************************************/
194 IoFilter *
compressFilter(CompressType type,int level)195 compressFilter(CompressType type, int level)
196 {
197 FUNCTION_TEST_BEGIN();
198 FUNCTION_TEST_PARAM(ENUM, type);
199 FUNCTION_TEST_PARAM(INT, level);
200 FUNCTION_TEST_END();
201
202 ASSERT(type < COMPRESS_LIST_SIZE);
203 ASSERT(type != compressTypeNone);
204 compressTypePresent(type);
205
206 FUNCTION_TEST_RETURN(compressHelperLocal[type].compressNew(level));
207 }
208
209 /**********************************************************************************************************************************/
210 IoFilter *
compressFilterVar(const String * filterType,const VariantList * filterParamList)211 compressFilterVar(const String *filterType, const VariantList *filterParamList)
212 {
213 FUNCTION_LOG_BEGIN(logLevelTrace);
214 FUNCTION_LOG_PARAM(STRING, filterType);
215 FUNCTION_LOG_PARAM(VARIANT_LIST, filterParamList);
216 FUNCTION_LOG_END();
217
218 ASSERT(filterType != NULL);
219
220 IoFilter *result = NULL;
221
222 for (CompressType compressIdx = compressTypeNone + 1; compressIdx < COMPRESS_LIST_SIZE; compressIdx++)
223 {
224 const struct CompressHelperLocal *compress = &compressHelperLocal[compressIdx];
225
226 if (compress->compressType != NULL && strEqZ(filterType, compress->compressType))
227 {
228 result = compress->compressNew(varIntForce(varLstGet(filterParamList, 0)));
229 break;
230 }
231 else if (compress->decompressType != NULL && strEqZ(filterType, compress->decompressType))
232 {
233 result = compress->decompressNew();
234 break;
235 }
236 }
237
238 FUNCTION_LOG_RETURN(IO_FILTER, result);
239 }
240
241 /**********************************************************************************************************************************/
242 IoFilter *
decompressFilter(CompressType type)243 decompressFilter(CompressType type)
244 {
245 FUNCTION_TEST_BEGIN();
246 FUNCTION_TEST_PARAM(ENUM, type);
247 FUNCTION_TEST_END();
248
249 ASSERT(type < COMPRESS_LIST_SIZE);
250 ASSERT(type != compressTypeNone);
251 compressTypePresent(type);
252
253 FUNCTION_TEST_RETURN(compressHelperLocal[type].decompressNew());
254 }
255
256 /**********************************************************************************************************************************/
257 const String *
compressExtStr(CompressType type)258 compressExtStr(CompressType type)
259 {
260 FUNCTION_TEST_BEGIN();
261 FUNCTION_TEST_PARAM(ENUM, type);
262 FUNCTION_TEST_END();
263
264 ASSERT(type < COMPRESS_LIST_SIZE);
265
266 FUNCTION_TEST_RETURN(compressHelperLocal[type].ext);
267 }
268
269 /**********************************************************************************************************************************/
270 void
compressExtCat(String * file,CompressType type)271 compressExtCat(String *file, CompressType type)
272 {
273 FUNCTION_TEST_BEGIN();
274 FUNCTION_TEST_PARAM(STRING, file);
275 FUNCTION_TEST_PARAM(ENUM, type);
276 FUNCTION_TEST_END();
277
278 ASSERT(file != NULL);
279
280 strCat(file, compressExtStr(type));
281
282 FUNCTION_TEST_RETURN_VOID();
283 }
284
285 /**********************************************************************************************************************************/
286 String *
compressExtStrip(const String * file,CompressType type)287 compressExtStrip(const String *file, CompressType type)
288 {
289 FUNCTION_TEST_BEGIN();
290 FUNCTION_TEST_PARAM(STRING, file);
291 FUNCTION_TEST_PARAM(ENUM, type);
292 FUNCTION_TEST_END();
293
294 ASSERT(file != NULL);
295
296 if (!strEndsWith(file, compressExtStr(type)))
297 THROW_FMT(FormatError, "'%s' must have '%s' extension", strZ(file), strZ(compressExtStr(type)));
298
299 FUNCTION_TEST_RETURN(strSubN(file, 0, strSize(file) - strSize(compressExtStr(type))));
300 }
301