Coverage Report

Created: 2025-07-04 07:01

/src/libmodi/libmodi/libmodi_compression.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Compression functions
3
 *
4
 * Copyright (C) 2012-2024, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <memory.h>
24
#include <types.h>
25
26
#if defined( HAVE_STDLIB_H ) || defined( WINAPI )
27
#include <stdlib.h>
28
#endif
29
30
#if defined( HAVE_BZLIB ) || defined( BZ_DLL )
31
#include <bzlib.h>
32
#endif
33
34
#if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
35
#include <lzma.h>
36
#endif
37
38
#if defined( HAVE_ZLIB ) || defined( ZLIB_DLL )
39
#include <zlib.h>
40
#endif
41
42
#include "libmodi_bzip.h"
43
#include "libmodi_compression.h"
44
#include "libmodi_definitions.h"
45
#include "libmodi_deflate.h"
46
#include "libmodi_libcerror.h"
47
#include "libmodi_libcnotify.h"
48
#include "libmodi_libfmos.h"
49
50
/* Decompresses data using the compression method
51
 * Returns 1 on success or -1 on error
52
 */
53
int libmodi_decompress_data(
54
     const uint8_t *compressed_data,
55
     size_t compressed_data_size,
56
     int compression_method,
57
     uint8_t *uncompressed_data,
58
     size_t *uncompressed_data_size,
59
     libcerror_error_t **error )
60
0
{
61
0
  static char *function                     = "libmodi_decompress_data";
62
63
#if defined( HAVE_BZLIB ) || defined( BZ_DLL )
64
  unsigned int bzip2_uncompressed_data_size = 0;
65
  int bzlib_result                          = 0;
66
#endif
67
#if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
68
  lzma_stream lzma_compressed_stream        = LZMA_STREAM_INIT;
69
  lzma_ret lzma_result                      = 0;
70
#endif
71
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
72
  uLongf zlib_uncompressed_data_size        = 0;
73
  int zlib_result                           = 0;
74
#endif
75
76
0
  if( compressed_data == NULL )
77
0
  {
78
0
    libcerror_error_set(
79
0
     error,
80
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
81
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
82
0
     "%s: invalid compressed data buffer.",
83
0
     function );
84
85
0
    return( -1 );
86
0
  }
87
0
  if( uncompressed_data == NULL )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
92
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
93
0
     "%s: invalid uncompressed data buffer.",
94
0
     function );
95
96
0
    return( -1 );
97
0
  }
98
0
  if( uncompressed_data == compressed_data )
99
0
  {
100
0
    libcerror_error_set(
101
0
     error,
102
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
103
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
104
0
     "%s: invalid compressed data buffer equals uncompressed data buffer.",
105
0
     function );
106
107
0
    return( -1 );
108
0
  }
109
0
  if( uncompressed_data_size == NULL )
110
0
  {
111
0
    libcerror_error_set(
112
0
     error,
113
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
114
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
115
0
     "%s: invalid uncompressed data size.",
116
0
     function );
117
118
0
    return( -1 );
119
0
  }
120
0
  if( compression_method == LIBMODI_COMPRESSION_METHOD_ADC )
121
0
  {
122
0
    if( libfmos_adc_decompress(
123
0
         compressed_data,
124
0
         compressed_data_size,
125
0
         uncompressed_data,
126
0
         uncompressed_data_size,
127
0
         error ) != 1 )
128
0
    {
129
0
      libcerror_error_set(
130
0
       error,
131
0
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
132
0
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
133
0
       "%s: unable to decompress ADC compressed data.",
134
0
       function );
135
136
0
      goto on_error;
137
0
    }
138
0
  }
139
0
  else if( compression_method == LIBMODI_COMPRESSION_METHOD_BZIP2 )
140
0
  {
141
#if defined( HAVE_BZLIB ) || defined( BZ_DLL )
142
    if( compressed_data_size > (size_t) UINT_MAX )
143
    {
144
      libcerror_error_set(
145
       error,
146
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
147
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
148
       "%s: invalid compressed data size value exceeds maximum.",
149
       function );
150
151
      goto on_error;
152
    }
153
    if( *uncompressed_data_size > (size_t) UINT_MAX )
154
    {
155
      libcerror_error_set(
156
       error,
157
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
158
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
159
       "%s: invalid uncompressed data size value exceeds maximum.",
160
       function );
161
162
      goto on_error;
163
    }
164
    bzip2_uncompressed_data_size = (unsigned int) *uncompressed_data_size;
165
166
    bzlib_result = BZ2_bzBuffToBuffDecompress(
167
                    (char *) uncompressed_data,
168
                    &bzip2_uncompressed_data_size,
169
                    (char *) compressed_data,
170
                    (unsigned int) compressed_data_size,
171
                    0,
172
                    0 );
173
174
    if( ( bzlib_result == BZ_DATA_ERROR )
175
     || ( bzlib_result == BZ_DATA_ERROR_MAGIC ) )
176
    {
177
      libcerror_error_set(
178
       error,
179
       LIBCERROR_ERROR_DOMAIN_MEMORY,
180
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
181
       "%s: unable to decompress data: data error.",
182
       function );
183
184
      goto on_error;
185
    }
186
    else if( bzlib_result == BZ_OUTBUFF_FULL )
187
    {
188
      libcerror_error_set(
189
       error,
190
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
191
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
192
       "%s: unable to decompress data: target buffer too small.",
193
       function );
194
195
      goto on_error;
196
    }
197
    else if( bzlib_result == BZ_MEM_ERROR )
198
    {
199
      libcerror_error_set(
200
       error,
201
       LIBCERROR_ERROR_DOMAIN_MEMORY,
202
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
203
       "%s: unable to decompress data: insufficient memory.",
204
       function );
205
206
      goto on_error;
207
    }
208
    else if( bzlib_result != BZ_OK )
209
    {
210
      libcerror_error_set(
211
       error,
212
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
213
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
214
       "%s: bzlib returned undefined error: %d.",
215
       function,
216
       bzlib_result );
217
218
      goto on_error;
219
    }
220
    *uncompressed_data_size = (size_t) bzip2_uncompressed_data_size;
221
#else
222
0
    if( libmodi_bzip_decompress(
223
0
         compressed_data,
224
0
         compressed_data_size,
225
0
         uncompressed_data,
226
0
         uncompressed_data_size,
227
0
         error ) != 1 )
228
0
    {
229
0
      libcerror_error_set(
230
0
       error,
231
0
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
232
0
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
233
0
       "%s: unable to decompress BZIP2 compressed data.",
234
0
       function );
235
236
0
      goto on_error;
237
0
    }
238
0
#endif /* defined( HAVE_BZLIB ) || defined( BZ_DLL ) */
239
0
  }
240
0
  else if( compression_method == LIBMODI_COMPRESSION_METHOD_DEFLATE )
241
0
  {
242
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
243
    if( compressed_data_size > (size_t) ULONG_MAX )
244
    {
245
      libcerror_error_set(
246
       error,
247
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
248
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
249
       "%s: invalid compressed data size value exceeds maximum.",
250
       function );
251
252
      goto on_error;
253
    }
254
    if( *uncompressed_data_size > (size_t) ULONG_MAX )
255
    {
256
      libcerror_error_set(
257
       error,
258
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
259
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
260
       "%s: invalid uncompressed data size value exceeds maximum.",
261
       function );
262
263
      goto on_error;
264
    }
265
    zlib_uncompressed_data_size = (uLongf) *uncompressed_data_size;
266
267
    zlib_result = uncompress(
268
                   (Bytef *) uncompressed_data,
269
                   &zlib_uncompressed_data_size,
270
                   (Bytef *) compressed_data,
271
                   (uLong) compressed_data_size );
272
273
    if( zlib_result == Z_DATA_ERROR )
274
    {
275
      libcerror_error_set(
276
       error,
277
       LIBCERROR_ERROR_DOMAIN_MEMORY,
278
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
279
       "%s: unable to decompress data: data error.",
280
       function );
281
282
      goto on_error;
283
    }
284
    else if( zlib_result == Z_BUF_ERROR )
285
    {
286
      libcerror_error_set(
287
       error,
288
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
289
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
290
       "%s: unable to decompress data: target buffer too small.",
291
       function );
292
293
      goto on_error;
294
    }
295
    else if( zlib_result == Z_MEM_ERROR )
296
    {
297
      libcerror_error_set(
298
       error,
299
       LIBCERROR_ERROR_DOMAIN_MEMORY,
300
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
301
       "%s: unable to read compressed data: insufficient memory.",
302
       function );
303
304
      goto on_error;
305
    }
306
    else if( zlib_result != Z_OK )
307
    {
308
      libcerror_error_set(
309
       error,
310
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
311
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
312
       "%s: zlib returned undefined error: %d.",
313
       function,
314
       zlib_result );
315
316
      goto on_error;
317
    }
318
    *uncompressed_data_size = (size_t) zlib_uncompressed_data_size;
319
#else
320
0
    if( libmodi_deflate_decompress_zlib(
321
0
         compressed_data,
322
0
         compressed_data_size,
323
0
         uncompressed_data,
324
0
         uncompressed_data_size,
325
0
         error ) != 1 )
326
0
    {
327
0
      libcerror_error_set(
328
0
       error,
329
0
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
330
0
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
331
0
       "%s: unable to decompress zlib/DEFLATE compressed data.",
332
0
       function );
333
334
0
      goto on_error;
335
0
    }
336
0
#endif /* ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL ) */
337
0
  }
338
0
  else if( compression_method == LIBMODI_COMPRESSION_METHOD_LZFSE )
339
0
  {
340
0
    if( libfmos_lzfse_decompress(
341
0
         compressed_data,
342
0
         compressed_data_size,
343
0
         uncompressed_data,
344
0
         uncompressed_data_size,
345
0
         error ) != 1 )
346
0
    {
347
0
      libcerror_error_set(
348
0
       error,
349
0
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
350
0
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
351
0
       "%s: unable to decompress LZFSE/LZVN compressed data.",
352
0
       function );
353
354
0
      goto on_error;
355
0
    }
356
0
  }
357
0
  else if( compression_method == LIBMODI_COMPRESSION_METHOD_LZMA )
358
0
  {
359
#if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
360
    lzma_result = lzma_stream_decoder(
361
                   &lzma_compressed_stream,
362
                   UINT64_MAX,
363
                   0 );
364
365
    if( lzma_result != LZMA_OK )
366
    {
367
      libcerror_error_set(
368
       error,
369
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
370
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
371
       "%s: unable to create LZMA stream.",
372
       function );
373
374
      goto on_error;
375
    }
376
    lzma_compressed_stream.next_in   = compressed_data;
377
    lzma_compressed_stream.avail_in  = compressed_data_size;
378
    lzma_compressed_stream.next_out  = uncompressed_data;
379
    lzma_compressed_stream.avail_out = *uncompressed_data_size;
380
381
    lzma_result = lzma_code(
382
                   &lzma_compressed_stream,
383
                   LZMA_RUN );
384
385
    if( ( lzma_result == LZMA_DATA_ERROR )
386
     || ( lzma_result == LZMA_FORMAT_ERROR ) )
387
    {
388
      libcerror_error_set(
389
       error,
390
       LIBCERROR_ERROR_DOMAIN_MEMORY,
391
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
392
       "%s: unable to decompress data: data error.",
393
       function );
394
395
      goto on_error;
396
    }
397
    else if( lzma_result == LZMA_BUF_ERROR )
398
    {
399
      libcerror_error_set(
400
       error,
401
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
402
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
403
       "%s: unable to decompress data: target buffer too small.",
404
       function );
405
406
      goto on_error;
407
    }
408
    else if( lzma_result == LZMA_MEM_ERROR )
409
    {
410
      libcerror_error_set(
411
       error,
412
       LIBCERROR_ERROR_DOMAIN_MEMORY,
413
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
414
       "%s: unable to read compressed data: insufficient memory.",
415
       function );
416
417
      goto on_error;
418
    }
419
    else if( lzma_result != LZMA_STREAM_END )
420
    {
421
      libcerror_error_set(
422
       error,
423
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
424
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
425
       "%s: liblzma returned undefined error: %d.",
426
       function,
427
       lzma_result );
428
429
      goto on_error;
430
    }
431
    *uncompressed_data_size = (size_t) lzma_compressed_stream.total_out;
432
433
    lzma_end(
434
     &lzma_compressed_stream );
435
#else
436
0
    libcerror_error_set(
437
0
     error,
438
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
439
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
440
0
     "%s: missing support for LZMA compression.",
441
0
     function );
442
443
0
    goto on_error;
444
0
#endif /* defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL ) */
445
0
  }
446
0
  else
447
0
  {
448
0
    libcerror_error_set(
449
0
     error,
450
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
451
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
452
0
     "%s: unsupported compression method.",
453
0
     function );
454
455
0
    goto on_error;
456
0
  }
457
0
  return( 1 );
458
459
0
on_error:
460
#if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
461
  lzma_end(
462
   &lzma_compressed_stream );
463
#endif
464
0
  return( -1 );
465
0
}
466