libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
compress.c
1#include <clod/compression.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include <libdeflate.h>
6#include <lz4hc.h>
7#include <lz4frame.h>
8#include <lzma.h>
9#include <zstd.h>
10
12 void *(*malloc_func)(size_t);
13 void (*free_func)(void *);
14
15 struct libdeflate_compressor *libdeflate_compressor[CLOD_COMPRESSION_LEVELS];
16 ZSTD_CCtx *zstd_cctx;
17};
18
19void *compressor_lzma_malloc(void *user, size_t n, size_t size) {
20 auto const ctx = (struct clod_compressor *)user;
21 return ctx->malloc_func(n * size);
22}
23void compressor_lzma_free(void *user, void *address) {
24 auto const ctx = (struct clod_compressor *)user;
25 ctx->free_func(address);
26}
27
29 struct clod_compressor *ctx = malloc(sizeof(struct clod_compressor));
30 memset(ctx, 0, sizeof(*ctx));
31 // LZ4 and ZSTD are missing custom memory allocation methods.
32 ctx->malloc_func = malloc;
33 ctx->free_func = free;
34 return ctx;
35}
36
38 for (int i = 0; i < CLOD_COMPRESSION_LEVELS; i++)
39 if (ctx->libdeflate_compressor[i])
40 libdeflate_free_compressor(ctx->libdeflate_compressor[i]);
41
42 if (ctx->zstd_cctx)
43 ZSTD_freeCCtx(ctx->zstd_cctx);
44
45 ctx->free_func(ctx);
46}
47
50 void *dst, const size_t dst_max_size,
51 const void *src, const size_t src_size,
52 size_t *actual_size,
53 const enum clod_compression_method method,
54 const enum clod_compression_level level
55) {
56 switch (method) {
57 case CLOD_UNCOMPRESSED: {
58 if (dst_max_size < src_size) {
60 }
61 memcpy(dst, src, src_size);
62 *actual_size = src_size;
64 }
65 case CLOD_GZIP: {
66 struct libdeflate_compressor *compressor = ctx->libdeflate_compressor[level];
67 if (!compressor) {
68 const int libdeflate_level =
69 level == CLOD_COMPRESSION_HIGHEST ? 12 :
70 level == CLOD_COMPRESSION_HIGH ? 9 :
71 level == CLOD_COMPRESSION_NORMAL ? 6 :
72 level == CLOD_COMPRESSION_LOW ? 3 :
73 level == CLOD_COMPRESSION_LOWEST ? 1 :
74 6;
75
76 struct libdeflate_options opts = {0};
77 opts.sizeof_options = sizeof(opts);
78 opts.free_func = ctx->free_func;
79 opts.malloc_func = ctx->malloc_func;
80
81 compressor = libdeflate_alloc_compressor_ex(libdeflate_level, &opts);
82 if (!compressor) {
84 }
85 ctx->libdeflate_compressor[level] = compressor;
86 }
87
88 const size_t size = libdeflate_gzip_compress(compressor,
89 src, src_size,
90 dst, dst_max_size);
91
92 if (size == 0) return CLOD_COMPRESSION_SHORT_BUFFER;
93
94 *actual_size = size;
96 }
97 case CLOD_ZLIB: {
98 struct libdeflate_compressor *compressor = ctx->libdeflate_compressor[level];
99 if (!compressor) {
100 const int libdeflate_level =
101 level == CLOD_COMPRESSION_HIGHEST ? 12 :
102 level == CLOD_COMPRESSION_HIGH ? 9 :
103 level == CLOD_COMPRESSION_NORMAL ? 6 :
104 level == CLOD_COMPRESSION_LOW ? 3 :
105 level == CLOD_COMPRESSION_LOWEST ? 1 :
106 6;
107
108 struct libdeflate_options opts = {0};
109 opts.sizeof_options = sizeof(opts);
110 opts.free_func = ctx->free_func;
111 opts.malloc_func = ctx->malloc_func;
112
113 compressor = libdeflate_alloc_compressor_ex(libdeflate_level, &opts);
114 if (!compressor) {
116 }
117 ctx->libdeflate_compressor[level] = compressor;
118 }
119
120 const size_t size = libdeflate_zlib_compress(compressor,
121 src, src_size,
122 dst, dst_max_size);
123
124 if (size == 0) return CLOD_COMPRESSION_SHORT_BUFFER;
125
126 *actual_size = size;
128 }
129 case CLOD_DEFLATE: {
130 struct libdeflate_compressor *compressor = ctx->libdeflate_compressor[level];
131 if (!compressor) {
132 const int libdeflate_level =
133 level == CLOD_COMPRESSION_HIGHEST ? 12 :
134 level == CLOD_COMPRESSION_HIGH ? 9 :
135 level == CLOD_COMPRESSION_NORMAL ? 6 :
136 level == CLOD_COMPRESSION_LOW ? 3 :
137 level == CLOD_COMPRESSION_LOWEST ? 1 :
138 6;
139
140 struct libdeflate_options opts = {0};
141 opts.sizeof_options = sizeof(opts);
142 opts.free_func = ctx->free_func;
143 opts.malloc_func = ctx->malloc_func;
144
145 compressor = libdeflate_alloc_compressor_ex(libdeflate_level, &opts);
146 if (!compressor) {
148 }
149 ctx->libdeflate_compressor[level] = compressor;
150 }
151
152 const size_t size = libdeflate_deflate_compress(compressor,
153 src, src_size,
154 dst, dst_max_size);
155
156 if (size == 0) return CLOD_COMPRESSION_SHORT_BUFFER;
157
158 *actual_size = size;
160 }
161 case CLOD_LZ4F: {
162 LZ4F_preferences_t prefs = LZ4F_INIT_PREFERENCES;
163 prefs.frameInfo.contentSize = src_size;
164 prefs.compressionLevel =
165 level == CLOD_COMPRESSION_HIGHEST ? LZ4HC_CLEVEL_MAX :
166 level == CLOD_COMPRESSION_HIGH ? LZ4HC_CLEVEL_OPT_MIN :
167 level == CLOD_COMPRESSION_NORMAL ? LZ4HC_CLEVEL_DEFAULT :
168 level == CLOD_COMPRESSION_LOW ? LZ4HC_CLEVEL_MIN :
169 level == CLOD_COMPRESSION_LOWEST ? 0 :
170 LZ4HC_CLEVEL_DEFAULT;
171
172 const size_t size = LZ4F_compressFrame(
173 dst, dst_max_size,
174 src, src_size,
175 &prefs);
176
177 if (LZ4F_isError(size)) {
179 }
180
181 *actual_size = size;
183 }
184 case CLOD_XZ: {
185 const lzma_allocator allocator = {
186 .alloc = compressor_lzma_malloc,
187 .free = compressor_lzma_free,
188 .opaque = ctx,
189 };
190
191 lzma_stream stream = LZMA_STREAM_INIT;
192 stream.allocator = &allocator;
193
194 const uint32_t preset =
195 level == CLOD_COMPRESSION_HIGHEST ? LZMA_PRESET_EXTREME | 9 :
196 level == CLOD_COMPRESSION_HIGH ? 8 :
197 level == CLOD_COMPRESSION_NORMAL ? 6 :
198 level == CLOD_COMPRESSION_LOW ? 3 :
199 level == CLOD_COMPRESSION_LOWEST ? 1 :
200 6;
201
202 lzma_ret ret = lzma_easy_encoder(&stream, preset, LZMA_CHECK_CRC64);
203 if (ret != LZMA_OK) {
204 return ret == LZMA_MEM_ERROR ? CLOD_COMPRESSION_ALLOC_FAILED : CLOD_COMPRESSION_INVALID;
205 }
206
207 stream.next_in = (uint8_t *)src;
208 stream.avail_in = src_size;
209 stream.next_out = (uint8_t *)dst;
210 stream.avail_out = dst_max_size;
211
212 do {
213 ret = lzma_code(&stream, LZMA_FINISH);
214 } while (ret == LZMA_OK);
215
216 lzma_end(&stream);
217
218 switch (ret) {
219 case LZMA_STREAM_END:
220 *actual_size = stream.total_out;
222 case LZMA_BUF_ERROR:
223 if (stream.avail_out == 0) {
224 *actual_size = 0;
226 }
228 case LZMA_MEM_ERROR: return CLOD_COMPRESSION_ALLOC_FAILED;
229 default: return CLOD_COMPRESSION_INVALID;
230 }
231 }
232 case CLOD_ZSTD: {
233 if (!ctx->zstd_cctx) {
234 ctx->zstd_cctx = ZSTD_createCCtx();
235 if (!ctx->zstd_cctx) return CLOD_COMPRESSION_ALLOC_FAILED;
236 }
237
238 const int compression_level =
239 level == CLOD_COMPRESSION_HIGHEST ? ZSTD_maxCLevel() :
240 level == CLOD_COMPRESSION_HIGH ? 14 :
241 level == CLOD_COMPRESSION_NORMAL ? 5 :
242 level == CLOD_COMPRESSION_LOW ? 3 :
243 level == CLOD_COMPRESSION_LOWEST ? 1 :
244 3;
245
246 const size_t size = ZSTD_compressCCtx(ctx->zstd_cctx,
247 dst, dst_max_size,
248 src, src_size,
249 compression_level
250 );
251 switch (ZSTD_getErrorCode(size)) {
252 case ZSTD_error_no_error:
253 *actual_size = size;
255 case ZSTD_error_dstSize_tooSmall:
257 case ZSTD_error_memory_allocation:
259 default:
261 }
262 }
263 default: {
265 }
266 }
267}
void clod_compressor_free(struct clod_compressor *ctx)
Definition compress.c:37
struct clod_compressor * clod_compressor_init()
Definition compress.c:28
clod_compression_level
Definition compression.h:74
clod_compression_result
Definition compression.h:92
clod_compression_method
Definition compression.h:36
enum clod_compression_result clod_compress(struct clod_compressor *ctx, void *dst, const size_t dst_max_size, const void *src, const size_t src_size, size_t *actual_size, const enum clod_compression_method method, const enum clod_compression_level level)
Definition compress.c:49
@ CLOD_COMPRESSION_HIGH
Definition compression.h:82
@ CLOD_COMPRESSION_NORMAL
Definition compression.h:80
@ CLOD_COMPRESSION_LOW
Definition compression.h:78
@ CLOD_COMPRESSION_LOWEST
Definition compression.h:76
@ CLOD_COMPRESSION_HIGHEST
Definition compression.h:84
@ CLOD_COMPRESSION_LEVELS
Definition compression.h:86
@ CLOD_COMPRESSION_ALLOC_FAILED
@ CLOD_COMPRESSION_SUCCESS
Definition compression.h:94
@ CLOD_COMPRESSION_INVALID
Definition compression.h:96
@ CLOD_COMPRESSION_SHORT_BUFFER
@ CLOD_GZIP
Definition compression.h:63
@ CLOD_UNCOMPRESSED
Definition compression.h:38
@ CLOD_ZSTD
Definition compression.h:43
@ CLOD_LZ4F
Definition compression.h:47
@ CLOD_XZ
Definition compression.h:51
@ CLOD_DEFLATE
Definition compression.h:55
@ CLOD_ZLIB
Definition compression.h:59
Sized string helpers.