Rizin
unix-like reverse engineering framework and cli tools
compression.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014-2015 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_util.h>
5 #include <zlib.h>
6 
7 #if HAVE_LZMA
8 #include <lzma.h>
9 #endif
10 
11 // set a maximum output buffer of 50MB
12 #define MAXOUT 50000000
13 
18 RZ_API ut8 *rz_inflate(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen) {
20  rz_return_val_if_fail(srcLen > 0, NULL);
21  return rz_inflatew(src, srcLen, srcConsumed, dstLen, MAX_WBITS + 32);
22 }
23 
28 RZ_API ut8 *rz_inflate_ignore_header(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen) {
30  rz_return_val_if_fail(srcLen > 0, NULL);
31  return rz_inflatew(src, srcLen, srcConsumed, dstLen, -MAX_WBITS);
32 }
33 
34 #if HAVE_ZLIB
35 static const char *gzerr(int n) {
36  const char *errors[] = {
37  "",
38  "file error", /* Z_ERRNO (-1) */
39  "stream error", /* Z_STREAM_ERROR (-2) */
40  "data error", /* Z_DATA_ERROR (-3) */
41  "insufficient memory", /* Z_MEM_ERROR (-4) */
42  "buffer error", /* Z_BUF_ERROR (-5) */
43  "incompatible version", /* Z_VERSION_ERROR (-6) */
44  };
45  if (n < 1 || n > 6) {
46  return "unknown";
47  }
48  return errors[n];
49 }
50 
60 RZ_API ut8 *rz_inflatew(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen, int wbits) {
62  rz_return_val_if_fail(srcLen > 0, NULL);
63 
64  int err = 0;
65  int out_size = 0;
66  ut8 *dst = NULL;
67  ut8 *tmp_ptr;
69 
70  memset(&stream, 0, sizeof(z_stream));
71  stream.avail_in = srcLen;
72  stream.next_in = (Bytef *)src;
73 
74  stream.zalloc = Z_NULL;
75  stream.zfree = Z_NULL;
76  stream.opaque = Z_NULL;
77 
78  if (inflateInit2(&stream, wbits) != Z_OK) {
79  return NULL;
80  }
81 
82  do {
83  if (stream.avail_out == 0) {
84  tmp_ptr = realloc(dst, stream.total_out + srcLen * 2);
85  if (!tmp_ptr) {
86  goto err_exit;
87  }
88  dst = tmp_ptr;
89  out_size += srcLen * 2;
90  if (out_size > MAXOUT) {
91  goto err_exit;
92  }
93  stream.next_out = dst + stream.total_out;
94  stream.avail_out = srcLen * 2;
95  }
97  if (err < 0) {
98  RZ_LOG_ERROR("inflate error: %d %s\n", err, gzerr(-err));
99  goto err_exit;
100  }
101  } while (err != Z_STREAM_END);
102 
103  if (dstLen) {
104  *dstLen = stream.total_out;
105  }
106  if (srcConsumed) {
107  *srcConsumed = (const ut8 *)stream.next_in - (const ut8 *)src;
108  }
109 
110  inflateEnd(&stream);
111  return dst;
112 
113 err_exit:
114  inflateEnd(&stream);
115  free(dst);
116  return NULL;
117 }
118 
128 RZ_API ut8 *rz_deflatew(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen, int wbits) {
130  rz_return_val_if_fail(srcLen > 0, NULL);
131 
132  int err = 0;
133  int out_size = 0;
134  ut8 *dst = NULL;
135  ut8 *tmp_ptr;
137 
138  memset(&stream, 0, sizeof(z_stream));
139 
140  stream.avail_in = srcLen;
141  stream.next_in = (Bytef *)src;
142  stream.zalloc = Z_NULL;
143  stream.zfree = Z_NULL;
144  stream.opaque = Z_NULL;
145 
147  return NULL;
148  }
149 
150  do {
151  if (stream.avail_out == 0) {
152  tmp_ptr = realloc(dst, stream.total_out + srcLen);
153  if (!tmp_ptr) {
154  goto err_exit;
155  }
156  dst = tmp_ptr;
157  out_size += srcLen;
158  if (out_size > MAXOUT) {
159  goto err_exit;
160  }
161  stream.next_out = dst + stream.total_out;
162  stream.avail_out = srcLen;
163  }
164  err = deflate(&stream, Z_FINISH);
165  if (err < 0) {
166  RZ_LOG_ERROR("deflate error: %d %s\n", err, gzerr(-err));
167  goto err_exit;
168  }
169  } while (err != Z_STREAM_END);
170 
171  if (dstLen) {
172  *dstLen = stream.total_out;
173  }
174  if (srcConsumed) {
175  *srcConsumed = (const ut8 *)stream.next_in - (const ut8 *)src;
176  }
177 
178  deflateEnd(&stream);
179  return dst;
180 
181 err_exit:
182  deflateEnd(&stream);
183  free(dst);
184  return NULL;
185 }
186 
196 RZ_API bool rz_deflatew_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, int wbits) {
197  rz_return_val_if_fail(src && dst, false);
198  rz_return_val_if_fail(block_size > 0, false);
199 
200  int err = 0, flush = Z_NO_FLUSH;
201  bool ret = true;
202  ut64 dst_cursor = 0, src_cursor = 0;
203  ut64 src_readlen = 0;
205 
206  memset(&stream, 0, sizeof(z_stream));
207 
208  stream.zalloc = Z_NULL;
209  stream.zfree = Z_NULL;
210  stream.opaque = Z_NULL;
211 
213  return false;
214  }
215 
216  ut8 *src_tmpbuf = malloc(block_size), *dst_tmpbuf = malloc(block_size);
217 
218  dst_cursor = rz_buf_tell(dst);
219  while ((src_readlen = rz_buf_read_at(src, src_cursor, src_tmpbuf, block_size)) > 0) {
220  src_cursor += src_readlen;
221  stream.avail_in = src_readlen;
222  stream.next_in = (Bytef *)src_tmpbuf;
223  stream.next_out = dst_tmpbuf;
224  stream.avail_out = block_size;
225  stream.total_out = 0;
226 
227  if (src_readlen < block_size) {
228  flush = Z_FINISH;
229  }
230  err = deflate(&stream, flush);
231  if (err < 0) {
232  RZ_LOG_ERROR("deflate error: %d %s\n", err, gzerr(-err));
233  ret = false;
234  goto return_goto;
235  }
236 
237  dst_cursor += rz_buf_write(dst, dst_tmpbuf, stream.total_out);
238  }
239 
240  if (src_consumed) {
241  *src_consumed = src_cursor;
242  }
243  ret = rz_buf_resize(dst, dst_cursor);
244 
245 return_goto:
246  deflateEnd(&stream);
247  free(src_tmpbuf);
248  free(dst_tmpbuf);
249 
250  return ret;
251 }
252 
262 RZ_API bool rz_inflatew_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, int wbits) {
263  rz_return_val_if_fail(src && dst, false);
264  rz_return_val_if_fail(block_size > 0, false);
265 
266  int err = 0, flush = Z_NO_FLUSH;
267  bool ret = true;
268  ut64 src_cursor = 0;
269  ut64 src_readlen = 0;
271 
272  memset(&stream, 0, sizeof(z_stream));
273 
274  stream.zalloc = Z_NULL;
275  stream.zfree = Z_NULL;
276  stream.opaque = Z_NULL;
277 
278  if (inflateInit2(&stream, wbits) != Z_OK) {
279  return false;
280  }
281 
282  int comp_factor = 1032; // maximum compression ratio
283  ut8 *src_tmpbuf = malloc(block_size), *dst_tmpbuf = malloc(comp_factor * block_size);
284 
285  while ((src_readlen = rz_buf_read_at(src, src_cursor, src_tmpbuf, block_size)) > 0) {
286  src_cursor += src_readlen;
287  stream.avail_in = src_readlen;
288  stream.next_in = (Bytef *)src_tmpbuf;
289  stream.next_out = dst_tmpbuf;
290  stream.avail_out = comp_factor * block_size;
291  stream.total_out = 0;
292 
293  if (src_readlen < block_size) {
294  flush = Z_FINISH;
295  }
296  err = inflate(&stream, flush);
297  if (err < 0) {
298  RZ_LOG_ERROR("inflate error: %d %s\n", err, gzerr(-err));
299  ret = false;
300  goto return_goto;
301  }
302 
303  rz_buf_write(dst, dst_tmpbuf, stream.total_out);
304  }
305 
306  if (src_consumed) {
307  *src_consumed = src_cursor;
308  }
309 
310 return_goto:
311  inflateEnd(&stream);
312  free(src_tmpbuf);
313  free(dst_tmpbuf);
314 
315  return ret;
316 }
317 
318 #else
319 RZ_API ut8 *rz_inflatew(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen, int wbits) {
320  return NULL;
321 }
322 
323 RZ_API ut8 *rz_deflatew(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen, int wbits) {
324  return NULL;
325 }
326 
327 RZ_API bool rz_deflatew_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, int wbits) {
328  return false;
329 }
330 
331 RZ_API bool rz_inflatew_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, int wbits) {
332  return false;
333 }
334 #endif
335 
340 RZ_API ut8 *rz_deflate(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen) {
342  rz_return_val_if_fail(srcLen > 0, NULL);
343  return rz_deflatew(src, srcLen, srcConsumed, dstLen, MAX_WBITS + 16);
344 }
345 
350 RZ_API bool rz_deflate_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed) {
351  rz_return_val_if_fail(src && dst, false);
352  rz_return_val_if_fail(block_size > 0, false);
353  return rz_deflatew_buf(src, dst, block_size, src_consumed, MAX_WBITS + 16);
354 }
355 
360 RZ_API bool rz_inflate_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed) {
361  rz_return_val_if_fail(src && dst, false);
362  rz_return_val_if_fail(block_size > 0, false);
363  return rz_inflatew_buf(src, dst, block_size, src_consumed, MAX_WBITS + 32);
364 }
365 
366 #if HAVE_LZMA
367 static bool lzma_action_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, bool encode) {
368  bool res = true;
370  lzma_ret ret;
371  if (encode) {
372  ret = lzma_easy_encoder(&strm, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
373  } else {
374  const ut64 memusage_limit = 0x1000000;
375  ret = lzma_stream_decoder(&strm, memusage_limit, 0);
376  }
377  if (ret != LZMA_OK) {
378  res = false;
379  goto strm_exit;
380  }
381 
383 
384  ut8 *inbuf = RZ_NEWS(ut8, block_size);
385  ut8 *outbuf = RZ_NEWS(ut8, block_size);
386  ut64 src_cursor = 0;
387  ut64 src_readlen = 0;
388 
389  strm.next_in = NULL;
390  strm.avail_in = 0;
391  strm.next_out = outbuf;
392  strm.avail_out = block_size;
393 
394  while (true) {
395  if (strm.avail_in == 0) {
396  strm.next_in = inbuf;
397  src_readlen = rz_buf_read_at(src, src_cursor, inbuf, block_size);
398  if (src_readlen < 0) {
399  res = false;
400  goto buf_exit;
401  }
402  if (src_readlen == 0) {
404  }
405 
406  strm.avail_in = src_readlen;
407  src_cursor += src_readlen;
408  }
409  ret = lzma_code(&strm, action);
410  if (strm.avail_out == 0 || ret == LZMA_STREAM_END) {
411  // When lzma_code() has returned LZMA_STREAM_END,
412  // the output buffer is likely to be only partially
413  // full. Calculate how much new data there is to
414  // be written to the output file.
415  size_t write_size = block_size - strm.avail_out;
416 
417  if (rz_buf_write(dst, outbuf, write_size) != write_size) {
418  res = false;
419  goto buf_exit;
420  }
421 
422  // Reset next_out and avail_out.
423  strm.next_out = outbuf;
424  strm.avail_out = block_size;
425  }
426 
427  if (ret == LZMA_STREAM_END) {
428  break;
429  }
430  if (ret != LZMA_OK) {
431  res = false;
432  goto buf_exit;
433  }
434  }
435 
436  if (src_consumed) {
437  *src_consumed = src_cursor;
438  }
439 
440 buf_exit:
441  free(inbuf);
442  free(outbuf);
443 strm_exit:
444  lzma_end(&strm);
445 
446  return res;
447 }
448 #else
449 static bool lzma_action_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, bool encode) {
450  return false;
451 }
452 #endif
453 
463  return lzma_action_buf(src, dst, block_size, src_consumed, false);
464 }
465 
475  return lzma_action_buf(src, dst, block_size, src_consumed, true);
476 }
@ LZMA_CHECK_CRC64
Definition: check.h:42
lzma_index * src
Definition: index.h:567
static bool err
Definition: armass.c:435
RZ_API bool rz_inflate_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed)
inflate compressed data in RzBbuffer, use MAX_WBITS as the window size logarithm.
Definition: compression.c:360
RZ_API ut8 * rz_deflate(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen)
deflate uncompressed data to zlib or gzipped, use MAX_WBITS as the window size logarithm.
Definition: compression.c:340
RZ_API ut8 * rz_inflate_ignore_header(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen)
inflate zlib compressed or gzipped. The input must be a raw stream with no header or trailer.
Definition: compression.c:28
RZ_API bool rz_lzma_enc_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed)
Compress the src buffer with LZMA algorithm and put the compressed data in dst.
Definition: compression.c:474
RZ_API bool rz_deflate_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed)
deflate uncompressed data in RzBbuffer to zlib or gzipped, use MAX_WBITS as the window size logarithm...
Definition: compression.c:350
static bool lzma_action_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, bool encode)
Definition: compression.c:449
RZ_API bool rz_inflatew_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, int wbits)
Definition: compression.c:331
RZ_API ut8 * rz_inflatew(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen, int wbits)
Definition: compression.c:319
RZ_API ut8 * rz_inflate(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen)
inflate zlib compressed or gzipped, automatically accepts either the zlib or gzip format,...
Definition: compression.c:18
RZ_API bool rz_deflatew_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed, int wbits)
Definition: compression.c:327
RZ_API bool rz_lzma_dec_buf(RZ_NONNULL RzBuffer *src, RZ_NONNULL RzBuffer *dst, ut64 block_size, ut8 *src_consumed)
Decompress the src buffer with LZMA algorithm and put the decompressed data in dst.
Definition: compression.c:462
#define MAXOUT
Definition: compression.c:12
RZ_API ut8 * rz_deflatew(RZ_NONNULL const ut8 *src, int srcLen, int *srcConsumed, int *dstLen, int wbits)
Definition: compression.c:323
#define LZMA_PRESET_DEFAULT
Default compression preset.
Definition: container.h:31
#define RZ_API
#define NULL
Definition: cris-opc.c:27
int ZEXPORT deflateEnd(z_streamp strm)
Definition: deflate.c:1119
int ZEXPORT deflate(z_streamp strm, int flush)
Definition: deflate.c:804
#define MAX_WBITS
Definition: flirt.c:105
static lzma_stream strm
Definition: full_flush.c:20
static void encode(size_t size, lzma_action action)
Definition: full_flush.c:25
unsigned char outbuf[SIZE]
Definition: gun.c:162
unsigned char inbuf[SIZE]
Definition: gun.c:161
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
int ZEXPORT inflate(z_streamp strm, int flush)
Definition: inflate.c:623
int ZEXPORT inflateEnd(z_streamp strm)
Definition: inflate.c:1301
voidpf stream
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
char * dst
Definition: lz4.h:724
The public API of liblzma data compression library.
int n
Definition: mipsasm.c:19
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API ut64 rz_buf_tell(RZ_NONNULL RzBuffer *b)
Return the current cursor position.
Definition: buf.c:1238
RZ_API bool rz_buf_resize(RZ_NONNULL RzBuffer *b, ut64 newsize)
Resize the buffer size.
Definition: buf.c:890
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API st64 rz_buf_write(RZ_NONNULL RzBuffer *b, RZ_NONNULL const ut8 *buf, ut64 len)
Write len bytes of the buffer at the cursor.
Definition: buf.c:1181
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define RZ_NEWS(x, y)
Definition: rz_types.h:283
#define RZ_NONNULL
Definition: rz_types.h:64
Passing data to and from liblzma.
Definition: base.h:485
uint8_t * next_out
Definition: base.h:490
size_t avail_out
Definition: base.h:491
const uint8_t * next_in
Definition: base.h:486
size_t avail_in
Definition: base.h:487
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
lzma_ret
Return values used by several functions in liblzma.
Definition: base.h:57
@ LZMA_STREAM_END
End of stream was reached.
Definition: base.h:63
@ LZMA_OK
Operation completed successfully.
Definition: base.h:58
lzma_action
The ‘action’ argument for lzma_code()
Definition: base.h:250
@ LZMA_FINISH
Finish the coding operation.
Definition: base.h:328
@ LZMA_RUN
Continue coding.
Definition: base.h:251
#define LZMA_STREAM_INIT
Initialization for lzma_stream.
Definition: base.h:545
Byte FAR Bytef
Definition: zconf.h:400
#define Z_DEFLATED
Definition: zlib.h:209
#define Z_DEFAULT_STRATEGY
Definition: zlib.h:200
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy)
Definition: zlib.h:1814
#define inflateInit2(strm, windowBits)
Definition: zlib.h:1817
#define Z_STREAM_END
Definition: zlib.h:178
#define Z_FINISH
Definition: zlib.h:172
#define Z_OK
Definition: zlib.h:177
#define Z_NO_FLUSH
Definition: zlib.h:168
#define Z_NULL
Definition: zlib.h:212
#define Z_DEFAULT_COMPRESSION
Definition: zlib.h:193