1 /*
2 * Compression functions
3 *
4 * Copyright (C) 2012-2021, 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_adc.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
49 /* Decompresses data using the compression method
50 * Returns 1 on success or -1 on error
51 */
libmodi_decompress_data(const uint8_t * compressed_data,size_t compressed_data_size,int compression_method,uint8_t * uncompressed_data,size_t * uncompressed_data_size,libcerror_error_t ** error)52 int libmodi_decompress_data(
53 const uint8_t *compressed_data,
54 size_t compressed_data_size,
55 int compression_method,
56 uint8_t *uncompressed_data,
57 size_t *uncompressed_data_size,
58 libcerror_error_t **error )
59 {
60 static char *function = "libmodi_decompress_data";
61
62 #if defined( HAVE_BZLIB ) || defined( BZ_DLL )
63 unsigned int bzip2_uncompressed_data_size = 0;
64 int bzlib_result = 0;
65 #endif
66 #if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
67 lzma_stream lzma_compressed_stream = LZMA_STREAM_INIT;
68 lzma_ret lzma_result = 0;
69 #endif
70 #if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
71 uLongf zlib_uncompressed_data_size = 0;
72 int zlib_result = 0;
73 #endif
74
75 if( compressed_data == NULL )
76 {
77 libcerror_error_set(
78 error,
79 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
80 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
81 "%s: invalid compressed data buffer.",
82 function );
83
84 return( -1 );
85 }
86 if( uncompressed_data == NULL )
87 {
88 libcerror_error_set(
89 error,
90 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
91 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
92 "%s: invalid uncompressed data buffer.",
93 function );
94
95 return( -1 );
96 }
97 if( uncompressed_data == compressed_data )
98 {
99 libcerror_error_set(
100 error,
101 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
102 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
103 "%s: invalid compressed data buffer equals uncompressed data buffer.",
104 function );
105
106 return( -1 );
107 }
108 if( uncompressed_data_size == NULL )
109 {
110 libcerror_error_set(
111 error,
112 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
113 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
114 "%s: invalid uncompressed data size.",
115 function );
116
117 return( -1 );
118 }
119 if( compression_method == LIBMODI_COMPRESSION_METHOD_ADC )
120 {
121 if( libmodi_adc_decompress(
122 compressed_data,
123 compressed_data_size,
124 uncompressed_data,
125 uncompressed_data_size,
126 error ) != 1 )
127 {
128 libcerror_error_set(
129 error,
130 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
131 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
132 "%s: unable to decompress ADC compressed data.",
133 function );
134
135 goto on_error;
136 }
137 }
138 else if( compression_method == LIBMODI_COMPRESSION_METHOD_BZIP2 )
139 {
140 #if defined( HAVE_BZLIB ) || defined( BZ_DLL )
141 if( compressed_data_size > (size_t) UINT_MAX )
142 {
143 libcerror_error_set(
144 error,
145 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
146 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
147 "%s: invalid compressed data size value exceeds maximum.",
148 function );
149
150 goto on_error;
151 }
152 if( *uncompressed_data_size > (size_t) UINT_MAX )
153 {
154 libcerror_error_set(
155 error,
156 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
157 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
158 "%s: invalid uncompressed data size value exceeds maximum.",
159 function );
160
161 goto on_error;
162 }
163 bzip2_uncompressed_data_size = (unsigned int) *uncompressed_data_size;
164
165 bzlib_result = BZ2_bzBuffToBuffDecompress(
166 (char *) uncompressed_data,
167 &bzip2_uncompressed_data_size,
168 (char *) compressed_data,
169 (unsigned int) compressed_data_size,
170 0,
171 0 );
172
173 if( ( bzlib_result == BZ_DATA_ERROR )
174 || ( bzlib_result == BZ_DATA_ERROR_MAGIC ) )
175 {
176 libcerror_error_set(
177 error,
178 LIBCERROR_ERROR_DOMAIN_MEMORY,
179 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
180 "%s: unable to decompress data: data error.",
181 function );
182
183 goto on_error;
184 }
185 else if( bzlib_result == BZ_OUTBUFF_FULL )
186 {
187 libcerror_error_set(
188 error,
189 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
190 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
191 "%s: unable to decompress data: target buffer too small.",
192 function );
193
194 goto on_error;
195 }
196 else if( bzlib_result == BZ_MEM_ERROR )
197 {
198 libcerror_error_set(
199 error,
200 LIBCERROR_ERROR_DOMAIN_MEMORY,
201 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
202 "%s: unable to decompress data: insufficient memory.",
203 function );
204
205 goto on_error;
206 }
207 else if( bzlib_result != BZ_OK )
208 {
209 libcerror_error_set(
210 error,
211 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
212 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
213 "%s: bzlib returned undefined error: %d.",
214 function,
215 bzlib_result );
216
217 goto on_error;
218 }
219 *uncompressed_data_size = (size_t) bzip2_uncompressed_data_size;
220 #else
221 libcerror_error_set(
222 error,
223 LIBCERROR_ERROR_DOMAIN_RUNTIME,
224 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
225 "%s: missing support for bzip2 compression.",
226 function );
227
228 goto on_error;
229 #endif /* defined( HAVE_BZLIB ) || defined( BZ_DLL ) */
230 }
231 else if( compression_method == LIBMODI_COMPRESSION_METHOD_DEFLATE )
232 {
233 #if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
234 if( compressed_data_size > (size_t) ULONG_MAX )
235 {
236 libcerror_error_set(
237 error,
238 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
239 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
240 "%s: invalid compressed data size value exceeds maximum.",
241 function );
242
243 goto on_error;
244 }
245 if( *uncompressed_data_size > (size_t) ULONG_MAX )
246 {
247 libcerror_error_set(
248 error,
249 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
250 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
251 "%s: invalid uncompressed data size value exceeds maximum.",
252 function );
253
254 goto on_error;
255 }
256 zlib_uncompressed_data_size = (uLongf) *uncompressed_data_size;
257
258 zlib_result = uncompress(
259 (Bytef *) uncompressed_data,
260 &zlib_uncompressed_data_size,
261 (Bytef *) compressed_data,
262 (uLong) compressed_data_size );
263
264 if( zlib_result == Z_DATA_ERROR )
265 {
266 libcerror_error_set(
267 error,
268 LIBCERROR_ERROR_DOMAIN_MEMORY,
269 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
270 "%s: unable to decompress data: data error.",
271 function );
272
273 goto on_error;
274 }
275 else if( zlib_result == Z_BUF_ERROR )
276 {
277 libcerror_error_set(
278 error,
279 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
280 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
281 "%s: unable to decompress data: target buffer too small.",
282 function );
283
284 goto on_error;
285 }
286 else if( zlib_result == Z_MEM_ERROR )
287 {
288 libcerror_error_set(
289 error,
290 LIBCERROR_ERROR_DOMAIN_MEMORY,
291 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
292 "%s: unable to read compressed data: insufficient memory.",
293 function );
294
295 goto on_error;
296 }
297 else if( zlib_result != Z_OK )
298 {
299 libcerror_error_set(
300 error,
301 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
302 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
303 "%s: zlib returned undefined error: %d.",
304 function,
305 zlib_result );
306
307 goto on_error;
308 }
309 *uncompressed_data_size = (size_t) zlib_uncompressed_data_size;
310 #else
311 if( libmodi_deflate_decompress_zlib(
312 compressed_data,
313 compressed_data_size,
314 uncompressed_data,
315 uncompressed_data_size,
316 error ) != 1 )
317 {
318 libcerror_error_set(
319 error,
320 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
321 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
322 "%s: unable to decompress zlib+DEFLATE compressed data.",
323 function );
324
325 goto on_error;
326 }
327 #endif /* ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL ) */
328 }
329 else if( compression_method == LIBMODI_COMPRESSION_METHOD_LZFSE )
330 {
331 libcerror_error_set(
332 error,
333 LIBCERROR_ERROR_DOMAIN_RUNTIME,
334 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
335 "%s: missing support for LZFSE compression.",
336 function );
337
338 goto on_error;
339 }
340 else if( compression_method == LIBMODI_COMPRESSION_METHOD_LZMA )
341 {
342 #if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
343 lzma_result = lzma_stream_decoder(
344 &lzma_compressed_stream,
345 UINT64_MAX,
346 0 );
347
348 if( lzma_result != LZMA_OK )
349 {
350 libcerror_error_set(
351 error,
352 LIBCERROR_ERROR_DOMAIN_RUNTIME,
353 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
354 "%s: unable to create LZMA stream.",
355 function );
356
357 goto on_error;
358 }
359 lzma_compressed_stream.next_in = compressed_data;
360 lzma_compressed_stream.avail_in = compressed_data_size;
361 lzma_compressed_stream.next_out = uncompressed_data;
362 lzma_compressed_stream.avail_out = *uncompressed_data_size;
363
364 lzma_result = lzma_code(
365 &lzma_compressed_stream,
366 LZMA_RUN );
367
368 if( ( lzma_result == LZMA_DATA_ERROR )
369 || ( lzma_result == LZMA_FORMAT_ERROR ) )
370 {
371 libcerror_error_set(
372 error,
373 LIBCERROR_ERROR_DOMAIN_MEMORY,
374 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
375 "%s: unable to decompress data: data error.",
376 function );
377
378 goto on_error;
379 }
380 else if( lzma_result == LZMA_BUF_ERROR )
381 {
382 libcerror_error_set(
383 error,
384 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
385 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
386 "%s: unable to decompress data: target buffer too small.",
387 function );
388
389 goto on_error;
390 }
391 else if( lzma_result == LZMA_MEM_ERROR )
392 {
393 libcerror_error_set(
394 error,
395 LIBCERROR_ERROR_DOMAIN_MEMORY,
396 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
397 "%s: unable to read compressed data: insufficient memory.",
398 function );
399
400 goto on_error;
401 }
402 else if( lzma_result != LZMA_STREAM_END )
403 {
404 libcerror_error_set(
405 error,
406 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
407 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
408 "%s: liblzma returned undefined error: %d.",
409 function,
410 lzma_result );
411
412 goto on_error;
413 }
414 *uncompressed_data_size = (size_t) lzma_compressed_stream.total_out;
415
416 lzma_end(
417 &lzma_compressed_stream );
418 #else
419 libcerror_error_set(
420 error,
421 LIBCERROR_ERROR_DOMAIN_RUNTIME,
422 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
423 "%s: missing support for LZMA compression.",
424 function );
425
426 goto on_error;
427 #endif /* defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL ) */
428 }
429 else
430 {
431 libcerror_error_set(
432 error,
433 LIBCERROR_ERROR_DOMAIN_RUNTIME,
434 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
435 "%s: unsupported compression method.",
436 function );
437
438 goto on_error;
439 }
440 return( 1 );
441
442 on_error:
443 #if defined( HAVE_LIBLZMA ) || defined( LIBLZMA_DLL )
444 lzma_end(
445 &lzma_compressed_stream );
446 #endif
447 return( -1 );
448 }
449
450