/src/libfsntfs/libfwnt/libfwnt_lzx.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * LZX (un)compression functions |
3 | | * |
4 | | * Copyright (C) 2009-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 <byte_stream.h> |
24 | | #include <memory.h> |
25 | | #include <types.h> |
26 | | |
27 | | #include "libfwnt_bit_stream.h" |
28 | | #include "libfwnt_huffman_tree.h" |
29 | | #include "libfwnt_libcerror.h" |
30 | | #include "libfwnt_libcnotify.h" |
31 | | #include "libfwnt_lzx.h" |
32 | | |
33 | | #if !defined( LIBFWNT_LZX_ATTRIBUTE_FALLTHROUGH ) |
34 | | #if defined( __GNUC__ ) && __GNUC__ >= 7 |
35 | | #define LIBFWNT_LZX_ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough)) |
36 | | #else |
37 | | #define LIBFWNT_LZX_ATTRIBUTE_FALLTHROUGH |
38 | | #endif |
39 | | #endif |
40 | | |
41 | | /* Base position - 2 |
42 | | */ |
43 | | const int32_t libfwnt_lzx_compression_offset_base[ 50 ] = { |
44 | | -2, -1, 0, 1, 2, 4, 6, 10, 14, 22, 30, 46, 62, 94, 126, 190, |
45 | | 254, 382, 510, 766, 1022, 1534, 2046, 3070, 4094, 6142, 8190, 12286, 16382, 24574, 32766, 49150, |
46 | | 65534, 98302, 131070, 196606, 262142, 393214, 524286, 655358, 786430, 917502, 1048574, 1179646, 1310718, 1441790, 1572862, 1703934, |
47 | | 1835006, 1966078 }; |
48 | | |
49 | | const uint8_t libfwnt_lzx_number_of_footer_bits[ 50 ] = { |
50 | | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, |
51 | | 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, |
52 | | 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, |
53 | | 17, 17, 17 }; |
54 | | |
55 | | /* Reads the Huffman code sizes |
56 | | * Returns 1 on success or -1 on error |
57 | | */ |
58 | | int libfwnt_lzx_read_huffman_code_sizes( |
59 | | libfwnt_bit_stream_t *bit_stream, |
60 | | uint8_t *code_size_array, |
61 | | int number_of_code_sizes, |
62 | | libcerror_error_t **error ) |
63 | 0 | { |
64 | 0 | uint8_t pre_code_size_array[ 20 ]; |
65 | |
|
66 | 0 | libfwnt_huffman_tree_t *pre_codes_huffman_tree = NULL; |
67 | 0 | static char *function = "libfwnt_lzx_read_huffman_code_sizes"; |
68 | 0 | uint32_t symbol = 0; |
69 | 0 | uint32_t times_to_repeat = 0; |
70 | 0 | uint32_t value_32bit = 0; |
71 | 0 | int32_t code_size = 0; |
72 | 0 | uint8_t pre_code_index = 0; |
73 | 0 | int code_size_index = 0; |
74 | |
|
75 | 0 | if( bit_stream == NULL ) |
76 | 0 | { |
77 | 0 | libcerror_error_set( |
78 | 0 | error, |
79 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
80 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
81 | 0 | "%s: invalid bit-stream.", |
82 | 0 | function ); |
83 | |
|
84 | 0 | return( -1 ); |
85 | 0 | } |
86 | 0 | for( pre_code_index = 0; |
87 | 0 | pre_code_index < 20; |
88 | 0 | pre_code_index++ ) |
89 | 0 | { |
90 | 0 | if( libfwnt_bit_stream_get_value( |
91 | 0 | bit_stream, |
92 | 0 | 4, |
93 | 0 | &value_32bit, |
94 | 0 | error ) != 1 ) |
95 | 0 | { |
96 | 0 | libcerror_error_set( |
97 | 0 | error, |
98 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
99 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
100 | 0 | "%s: unable to retrieve pre-code: %" PRIu8 " size from bit stream.", |
101 | 0 | function, |
102 | 0 | pre_code_index ); |
103 | |
|
104 | 0 | goto on_error; |
105 | 0 | } |
106 | 0 | if( libcnotify_verbose != 0 ) |
107 | 0 | { |
108 | 0 | libcnotify_printf( |
109 | 0 | "%s: pre-code: % 2" PRIu8 " value\t\t\t: %" PRIu32 "\n", |
110 | 0 | function, |
111 | 0 | pre_code_index, |
112 | 0 | value_32bit) ; |
113 | 0 | } |
114 | 0 | pre_code_size_array[ pre_code_index ] = (uint8_t) value_32bit; |
115 | 0 | } |
116 | 0 | if( libcnotify_verbose != 0 ) |
117 | 0 | { |
118 | 0 | libcnotify_printf( |
119 | 0 | "\n" ); |
120 | 0 | } |
121 | 0 | if( libfwnt_huffman_tree_initialize( |
122 | 0 | &pre_codes_huffman_tree, |
123 | 0 | 20, |
124 | 0 | 15, |
125 | 0 | error ) != 1 ) |
126 | 0 | { |
127 | 0 | libcerror_error_set( |
128 | 0 | error, |
129 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
130 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
131 | 0 | "%s: unable to create pre-codes Huffman tree.", |
132 | 0 | function ); |
133 | |
|
134 | 0 | goto on_error; |
135 | 0 | } |
136 | 0 | if( libfwnt_huffman_tree_build( |
137 | 0 | pre_codes_huffman_tree, |
138 | 0 | pre_code_size_array, |
139 | 0 | 20, |
140 | 0 | error ) != 1 ) |
141 | 0 | { |
142 | 0 | libcerror_error_set( |
143 | 0 | error, |
144 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
145 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
146 | 0 | "%s: unable to build pre-codes Huffman tree.", |
147 | 0 | function ); |
148 | |
|
149 | 0 | goto on_error; |
150 | 0 | } |
151 | 0 | code_size_index = 0; |
152 | |
|
153 | 0 | while( code_size_index < number_of_code_sizes ) |
154 | 0 | { |
155 | 0 | if( libfwnt_huffman_tree_get_symbol_from_bit_stream( |
156 | 0 | pre_codes_huffman_tree, |
157 | 0 | bit_stream, |
158 | 0 | &symbol, |
159 | 0 | error ) != 1 ) |
160 | 0 | { |
161 | 0 | libcerror_error_set( |
162 | 0 | error, |
163 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
164 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
165 | 0 | "%s: unable to retrieve symbol from pre-codes Huffman tree.", |
166 | 0 | function ); |
167 | |
|
168 | 0 | goto on_error; |
169 | 0 | } |
170 | 0 | if( libcnotify_verbose != 0 ) |
171 | 0 | { |
172 | 0 | libcnotify_printf( |
173 | 0 | "%s: code size: % 3" PRIu32 " symbol\t\t: %" PRIu32 "\n", |
174 | 0 | function, |
175 | 0 | code_size_index, |
176 | 0 | symbol ); |
177 | 0 | } |
178 | 0 | if( symbol < 17 ) |
179 | 0 | { |
180 | 0 | code_size = code_size_array[ code_size_index ] - symbol; |
181 | |
|
182 | 0 | if( code_size < 0 ) |
183 | 0 | { |
184 | 0 | code_size += 17; |
185 | 0 | } |
186 | 0 | if( libcnotify_verbose != 0 ) |
187 | 0 | { |
188 | 0 | libcnotify_printf( |
189 | 0 | "%s: code size: % 3" PRIu32 " value\t\t: %" PRIi32 "\n", |
190 | 0 | function, |
191 | 0 | code_size_index, |
192 | 0 | code_size ); |
193 | 0 | } |
194 | 0 | code_size_array[ code_size_index++ ] = (uint8_t) code_size; |
195 | |
|
196 | 0 | continue; |
197 | 0 | } |
198 | 0 | code_size = 0; |
199 | |
|
200 | 0 | if( symbol == 17 ) |
201 | 0 | { |
202 | 0 | if( libfwnt_bit_stream_get_value( |
203 | 0 | bit_stream, |
204 | 0 | 4, |
205 | 0 | ×_to_repeat, |
206 | 0 | error ) != 1 ) |
207 | 0 | { |
208 | 0 | libcerror_error_set( |
209 | 0 | error, |
210 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
211 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
212 | 0 | "%s: unable to retrieve times to repeat from bit stream.", |
213 | 0 | function ); |
214 | |
|
215 | 0 | goto on_error; |
216 | 0 | } |
217 | 0 | times_to_repeat += 4; |
218 | 0 | } |
219 | 0 | else if( symbol == 18 ) |
220 | 0 | { |
221 | 0 | if( libfwnt_bit_stream_get_value( |
222 | 0 | bit_stream, |
223 | 0 | 5, |
224 | 0 | ×_to_repeat, |
225 | 0 | error ) != 1 ) |
226 | 0 | { |
227 | 0 | libcerror_error_set( |
228 | 0 | error, |
229 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
230 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
231 | 0 | "%s: unable to retrieve times to repeat from bit stream.", |
232 | 0 | function ); |
233 | |
|
234 | 0 | goto on_error; |
235 | 0 | } |
236 | 0 | times_to_repeat += 20; |
237 | 0 | } |
238 | 0 | else if( symbol == 19 ) |
239 | 0 | { |
240 | 0 | if( libfwnt_bit_stream_get_value( |
241 | 0 | bit_stream, |
242 | 0 | 1, |
243 | 0 | ×_to_repeat, |
244 | 0 | error ) != 1 ) |
245 | 0 | { |
246 | 0 | libcerror_error_set( |
247 | 0 | error, |
248 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
249 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
250 | 0 | "%s: unable to retrieve times to repeat from bit stream.", |
251 | 0 | function ); |
252 | |
|
253 | 0 | goto on_error; |
254 | 0 | } |
255 | 0 | times_to_repeat += 4; |
256 | |
|
257 | 0 | if( libfwnt_huffman_tree_get_symbol_from_bit_stream( |
258 | 0 | pre_codes_huffman_tree, |
259 | 0 | bit_stream, |
260 | 0 | &symbol, |
261 | 0 | error ) != 1 ) |
262 | 0 | { |
263 | 0 | libcerror_error_set( |
264 | 0 | error, |
265 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
266 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
267 | 0 | "%s: unable to retrieve symbol from pre-codes Huffman tree.", |
268 | 0 | function ); |
269 | |
|
270 | 0 | goto on_error; |
271 | 0 | } |
272 | 0 | if( symbol > 17 ) |
273 | 0 | { |
274 | 0 | libcerror_error_set( |
275 | 0 | error, |
276 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
277 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
278 | 0 | "%s: invalid code size symbol value out of bounds.", |
279 | 0 | function ); |
280 | |
|
281 | 0 | goto on_error; |
282 | 0 | } |
283 | 0 | code_size = code_size_array[ code_size_index ] - symbol; |
284 | |
|
285 | 0 | if( code_size < 0 ) |
286 | 0 | { |
287 | 0 | code_size += 17; |
288 | 0 | } |
289 | 0 | } |
290 | 0 | else |
291 | 0 | { |
292 | 0 | libcerror_error_set( |
293 | 0 | error, |
294 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
295 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
296 | 0 | "%s: invalid code size symbol value out of bounds.", |
297 | 0 | function ); |
298 | |
|
299 | 0 | goto on_error; |
300 | 0 | } |
301 | 0 | if( libcnotify_verbose != 0 ) |
302 | 0 | { |
303 | 0 | libcnotify_printf( |
304 | 0 | "%s: times to repeat\t\t\t: %" PRIu32 "\n", |
305 | 0 | function, |
306 | 0 | times_to_repeat ); |
307 | 0 | } |
308 | 0 | if( times_to_repeat > (uint32_t) ( number_of_code_sizes - code_size_index ) ) |
309 | 0 | { |
310 | 0 | if( libcnotify_verbose != 0 ) |
311 | 0 | { |
312 | 0 | libcnotify_printf( |
313 | 0 | "%s: times to repeat value out of bounds.\n", |
314 | 0 | function ); |
315 | 0 | } |
316 | 0 | times_to_repeat = (uint32_t) ( number_of_code_sizes - code_size_index ); |
317 | 0 | } |
318 | 0 | while( times_to_repeat > 0 ) |
319 | 0 | { |
320 | 0 | if( libcnotify_verbose != 0 ) |
321 | 0 | { |
322 | 0 | libcnotify_printf( |
323 | 0 | "%s: code size: % 3" PRIu32 " value\t\t: %" PRIi32 "\n", |
324 | 0 | function, |
325 | 0 | code_size_index, |
326 | 0 | code_size ); |
327 | 0 | } |
328 | 0 | code_size_array[ code_size_index++ ] = (uint8_t) code_size; |
329 | |
|
330 | 0 | times_to_repeat--; |
331 | 0 | } |
332 | 0 | } |
333 | 0 | if( libfwnt_huffman_tree_free( |
334 | 0 | &pre_codes_huffman_tree, |
335 | 0 | error ) != 1 ) |
336 | 0 | { |
337 | 0 | libcerror_error_set( |
338 | 0 | error, |
339 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
340 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
341 | 0 | "%s: unable to free pre-codes Huffman tree.", |
342 | 0 | function ); |
343 | |
|
344 | 0 | goto on_error; |
345 | 0 | } |
346 | 0 | if( libcnotify_verbose != 0 ) |
347 | 0 | { |
348 | 0 | libcnotify_printf( |
349 | 0 | "\n" ); |
350 | 0 | } |
351 | 0 | return( 1 ); |
352 | | |
353 | 0 | on_error: |
354 | 0 | if( pre_codes_huffman_tree != NULL ) |
355 | 0 | { |
356 | 0 | libfwnt_huffman_tree_free( |
357 | 0 | &pre_codes_huffman_tree, |
358 | 0 | NULL ); |
359 | 0 | } |
360 | 0 | return( -1 ); |
361 | 0 | } |
362 | | |
363 | | /* Reads and builds the literals and match headers Huffman tree |
364 | | * Returns 1 on success or -1 on error |
365 | | */ |
366 | | int libfwnt_lzx_build_main_huffman_tree( |
367 | | libfwnt_bit_stream_t *bit_stream, |
368 | | uint8_t *code_size_array, |
369 | | libfwnt_huffman_tree_t *huffman_tree, |
370 | | libcerror_error_t **error ) |
371 | 0 | { |
372 | 0 | static char *function = "libfwnt_lzx_build_main_huffman_tree"; |
373 | |
|
374 | 0 | if( libfwnt_lzx_read_huffman_code_sizes( |
375 | 0 | bit_stream, |
376 | 0 | code_size_array, |
377 | 0 | 256, |
378 | 0 | error ) != 1 ) |
379 | 0 | { |
380 | 0 | libcerror_error_set( |
381 | 0 | error, |
382 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
383 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
384 | 0 | "%s: unable to read literals Huffman code sizes.", |
385 | 0 | function ); |
386 | |
|
387 | 0 | return( -1 ); |
388 | 0 | } |
389 | 0 | if( libfwnt_lzx_read_huffman_code_sizes( |
390 | 0 | bit_stream, |
391 | 0 | &( code_size_array[ 256 ] ), |
392 | 0 | 240, |
393 | 0 | error ) != 1 ) |
394 | 0 | { |
395 | 0 | libcerror_error_set( |
396 | 0 | error, |
397 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
398 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
399 | 0 | "%s: unable to read literals Huffman code sizes.", |
400 | 0 | function ); |
401 | |
|
402 | 0 | return( -1 ); |
403 | 0 | } |
404 | 0 | if( libfwnt_huffman_tree_build( |
405 | 0 | huffman_tree, |
406 | 0 | code_size_array, |
407 | 0 | 256 + 240, |
408 | 0 | error ) != 1 ) |
409 | 0 | { |
410 | 0 | libcerror_error_set( |
411 | 0 | error, |
412 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
413 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
414 | 0 | "%s: unable to build literals and match headers Huffman tree.", |
415 | 0 | function ); |
416 | |
|
417 | 0 | return( -1 ); |
418 | 0 | } |
419 | 0 | return( 1 ); |
420 | 0 | } |
421 | | |
422 | | /* Reads and builds the lengths Huffman tree |
423 | | * Returns 1 on success or -1 on error |
424 | | */ |
425 | | int libfwnt_lzx_build_lengths_huffman_tree( |
426 | | libfwnt_bit_stream_t *bit_stream, |
427 | | uint8_t *code_size_array, |
428 | | libfwnt_huffman_tree_t *huffman_tree, |
429 | | libcerror_error_t **error ) |
430 | 0 | { |
431 | 0 | static char *function = "libfwnt_lzx_build_lengths_huffman_tree"; |
432 | |
|
433 | 0 | if( libfwnt_lzx_read_huffman_code_sizes( |
434 | 0 | bit_stream, |
435 | 0 | code_size_array, |
436 | 0 | 249, |
437 | 0 | error ) != 1 ) |
438 | 0 | { |
439 | 0 | libcerror_error_set( |
440 | 0 | error, |
441 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
442 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
443 | 0 | "%s: unable to read literals Huffman code sizes.", |
444 | 0 | function ); |
445 | |
|
446 | 0 | return( -1 ); |
447 | 0 | } |
448 | 0 | if( libfwnt_huffman_tree_build( |
449 | 0 | huffman_tree, |
450 | 0 | code_size_array, |
451 | 0 | 249, |
452 | 0 | error ) != 1 ) |
453 | 0 | { |
454 | 0 | libcerror_error_set( |
455 | 0 | error, |
456 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
457 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
458 | 0 | "%s: unable to build lengths Huffman tree.", |
459 | 0 | function ); |
460 | |
|
461 | 0 | return( -1 ); |
462 | 0 | } |
463 | 0 | return( 1 ); |
464 | 0 | } |
465 | | |
466 | | /* Reads and builds the aligned offsets Huffman tree |
467 | | * Returns 1 on success or -1 on error |
468 | | */ |
469 | | int libfwnt_lzx_build_aligned_offsets_huffman_tree( |
470 | | libfwnt_bit_stream_t *bit_stream, |
471 | | uint8_t *code_size_array, |
472 | | libfwnt_huffman_tree_t *huffman_tree, |
473 | | libcerror_error_t **error ) |
474 | 0 | { |
475 | 0 | static char *function = "libfwnt_lzx_build_aligned_offsets_huffman_tree"; |
476 | 0 | uint32_t code_size = 0; |
477 | 0 | int code_size_index = 0; |
478 | |
|
479 | 0 | for( code_size_index = 0; |
480 | 0 | code_size_index < 8; |
481 | 0 | code_size_index++ ) |
482 | 0 | { |
483 | 0 | if( libfwnt_bit_stream_get_value( |
484 | 0 | bit_stream, |
485 | 0 | 3, |
486 | 0 | &code_size, |
487 | 0 | error ) != 1 ) |
488 | 0 | { |
489 | 0 | libcerror_error_set( |
490 | 0 | error, |
491 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
492 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
493 | 0 | "%s: unable to retrieve value from bit stream.", |
494 | 0 | function ); |
495 | |
|
496 | 0 | return( -1 ); |
497 | 0 | } |
498 | 0 | if( libcnotify_verbose != 0 ) |
499 | 0 | { |
500 | 0 | libcnotify_printf( |
501 | 0 | "%s: code size: % 2d value\t: %" PRIu32 "\n", |
502 | 0 | function, |
503 | 0 | code_size_index, |
504 | 0 | code_size ); |
505 | 0 | } |
506 | 0 | code_size_array[ code_size_index ] = (uint8_t) code_size; |
507 | 0 | } |
508 | 0 | if( libfwnt_huffman_tree_build( |
509 | 0 | huffman_tree, |
510 | 0 | code_size_array, |
511 | 0 | 8, |
512 | 0 | error ) != 1 ) |
513 | 0 | { |
514 | 0 | libcerror_error_set( |
515 | 0 | error, |
516 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
517 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
518 | 0 | "%s: unable to build aligned offsets Huffman tree.", |
519 | 0 | function ); |
520 | |
|
521 | 0 | return( -1 ); |
522 | 0 | } |
523 | 0 | return( 1 ); |
524 | 0 | } |
525 | | |
526 | | /* Decodes a Huffman compressed block |
527 | | * Returns 1 on success or -1 on error |
528 | | */ |
529 | | int libfwnt_lzx_decode_huffman( |
530 | | libfwnt_bit_stream_t *bit_stream, |
531 | | uint32_t block_size, |
532 | | libfwnt_huffman_tree_t *main_huffman_tree, |
533 | | libfwnt_huffman_tree_t *lengths_huffman_tree, |
534 | | libfwnt_huffman_tree_t *aligned_offsets_huffman_tree, |
535 | | uint32_t *recent_compression_offsets, |
536 | | uint8_t *uncompressed_data, |
537 | | size_t uncompressed_data_size, |
538 | | size_t *uncompressed_data_offset, |
539 | | libcerror_error_t **error ) |
540 | 0 | { |
541 | 0 | static char *function = "libfwnt_lzx_decode_huffman"; |
542 | 0 | size_t data_end_offset = 0; |
543 | 0 | size_t data_offset = 0; |
544 | 0 | uint32_t aligned_offset = 0; |
545 | 0 | uint32_t compression_offset = 0; |
546 | 0 | uint32_t compression_offset_slot = 0; |
547 | 0 | uint32_t compression_size = 0; |
548 | 0 | uint32_t symbol = 0; |
549 | 0 | uint8_t number_of_bits = 0; |
550 | |
|
551 | 0 | if( recent_compression_offsets == NULL ) |
552 | 0 | { |
553 | 0 | libcerror_error_set( |
554 | 0 | error, |
555 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
556 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
557 | 0 | "%s: invalid recent compression offsets.", |
558 | 0 | function ); |
559 | |
|
560 | 0 | return( -1 ); |
561 | 0 | } |
562 | 0 | if( uncompressed_data == NULL ) |
563 | 0 | { |
564 | 0 | libcerror_error_set( |
565 | 0 | error, |
566 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
567 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
568 | 0 | "%s: invalid uncompressed data.", |
569 | 0 | function ); |
570 | |
|
571 | 0 | return( -1 ); |
572 | 0 | } |
573 | 0 | if( uncompressed_data_size > (size_t) SSIZE_MAX ) |
574 | 0 | { |
575 | 0 | libcerror_error_set( |
576 | 0 | error, |
577 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
578 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, |
579 | 0 | "%s: invalid uncompressed data size value exceeds maximum.", |
580 | 0 | function ); |
581 | |
|
582 | 0 | return( -1 ); |
583 | 0 | } |
584 | 0 | if( uncompressed_data_offset == NULL ) |
585 | 0 | { |
586 | 0 | libcerror_error_set( |
587 | 0 | error, |
588 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
589 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
590 | 0 | "%s: invalid uncompressed data offset.", |
591 | 0 | function ); |
592 | |
|
593 | 0 | return( -1 ); |
594 | 0 | } |
595 | 0 | data_offset = *uncompressed_data_offset; |
596 | 0 | data_end_offset = data_offset + block_size; |
597 | |
|
598 | 0 | while( data_offset < data_end_offset ) |
599 | 0 | { |
600 | 0 | if( libfwnt_huffman_tree_get_symbol_from_bit_stream( |
601 | 0 | main_huffman_tree, |
602 | 0 | bit_stream, |
603 | 0 | &symbol, |
604 | 0 | error ) != 1 ) |
605 | 0 | { |
606 | 0 | libcerror_error_set( |
607 | 0 | error, |
608 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
609 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
610 | 0 | "%s: unable to retrieve symbol from literals and match headers Huffman tree.", |
611 | 0 | function ); |
612 | |
|
613 | 0 | return( -1 ); |
614 | 0 | } |
615 | 0 | if( libcnotify_verbose != 0 ) |
616 | 0 | { |
617 | 0 | libcnotify_printf( |
618 | 0 | "%s: symbol\t\t\t\t\t: %" PRIu32 "\n", |
619 | 0 | function, |
620 | 0 | symbol ); |
621 | 0 | } |
622 | 0 | if( symbol < 256 ) |
623 | 0 | { |
624 | 0 | if( data_offset >= uncompressed_data_size ) |
625 | 0 | { |
626 | 0 | libcerror_error_set( |
627 | 0 | error, |
628 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
629 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, |
630 | 0 | "%s: invalid uncompressed data value too small.", |
631 | 0 | function ); |
632 | |
|
633 | 0 | return( -1 ); |
634 | 0 | } |
635 | 0 | uncompressed_data[ data_offset++ ] = (uint8_t) symbol; |
636 | 0 | } |
637 | 0 | else |
638 | 0 | { |
639 | 0 | compression_size = symbol % 8; |
640 | 0 | compression_offset_slot = ( symbol - 256 ) / 8; |
641 | |
|
642 | 0 | if( compression_size == 7 ) |
643 | 0 | { |
644 | 0 | if( libfwnt_huffman_tree_get_symbol_from_bit_stream( |
645 | 0 | lengths_huffman_tree, |
646 | 0 | bit_stream, |
647 | 0 | &compression_size, |
648 | 0 | error ) != 1 ) |
649 | 0 | { |
650 | 0 | libcerror_error_set( |
651 | 0 | error, |
652 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
653 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
654 | 0 | "%s: unable to retrieve symbol from lengths Huffman tree.", |
655 | 0 | function ); |
656 | |
|
657 | 0 | return( -1 ); |
658 | 0 | } |
659 | 0 | compression_size += 7; |
660 | 0 | } |
661 | 0 | compression_size += 2; |
662 | |
|
663 | 0 | if( compression_offset_slot < 3 ) |
664 | 0 | { |
665 | 0 | compression_offset = recent_compression_offsets[ compression_offset_slot ]; |
666 | |
|
667 | 0 | recent_compression_offsets[ compression_offset_slot ] = recent_compression_offsets[ 0 ]; |
668 | 0 | } |
669 | 0 | else |
670 | 0 | { |
671 | 0 | number_of_bits = libfwnt_lzx_number_of_footer_bits[ compression_offset_slot ]; |
672 | |
|
673 | 0 | if( ( aligned_offsets_huffman_tree != NULL ) |
674 | 0 | && ( compression_offset_slot >= 8 ) ) |
675 | 0 | { |
676 | 0 | number_of_bits -= 3; |
677 | 0 | } |
678 | 0 | if( libcnotify_verbose != 0 ) |
679 | 0 | { |
680 | 0 | libcnotify_printf( |
681 | 0 | "%s: number of footer bits\t\t\t: %" PRIu8 "\n", |
682 | 0 | function, |
683 | 0 | number_of_bits ); |
684 | 0 | } |
685 | 0 | if( libfwnt_bit_stream_get_value( |
686 | 0 | bit_stream, |
687 | 0 | number_of_bits, |
688 | 0 | &compression_offset, |
689 | 0 | error ) != 1 ) |
690 | 0 | { |
691 | 0 | libcerror_error_set( |
692 | 0 | error, |
693 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
694 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
695 | 0 | "%s: unable to retrieve compression offset from bit stream.", |
696 | 0 | function ); |
697 | |
|
698 | 0 | return( -1 ); |
699 | 0 | } |
700 | 0 | if( ( aligned_offsets_huffman_tree != NULL ) |
701 | 0 | && ( compression_offset_slot >= 8 ) ) |
702 | 0 | { |
703 | 0 | if( libfwnt_huffman_tree_get_symbol_from_bit_stream( |
704 | 0 | aligned_offsets_huffman_tree, |
705 | 0 | bit_stream, |
706 | 0 | &aligned_offset, |
707 | 0 | error ) != 1 ) |
708 | 0 | { |
709 | 0 | libcerror_error_set( |
710 | 0 | error, |
711 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
712 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
713 | 0 | "%s: unable to retrieve symbol from literals and match headers Huffman tree.", |
714 | 0 | function ); |
715 | |
|
716 | 0 | return( -1 ); |
717 | 0 | } |
718 | 0 | if( libcnotify_verbose != 0 ) |
719 | 0 | { |
720 | 0 | libcnotify_printf( |
721 | 0 | "%s: aligned offset\t\t\t\t: %" PRIu32 "\n", |
722 | 0 | function, |
723 | 0 | aligned_offset ); |
724 | 0 | } |
725 | 0 | compression_offset <<= 3; |
726 | 0 | compression_offset |= aligned_offset; |
727 | 0 | } |
728 | 0 | compression_offset += libfwnt_lzx_compression_offset_base[ compression_offset_slot ]; |
729 | |
|
730 | 0 | recent_compression_offsets[ 2 ] = recent_compression_offsets[ 1 ]; |
731 | 0 | recent_compression_offsets[ 1 ] = recent_compression_offsets[ 0 ]; |
732 | 0 | } |
733 | 0 | recent_compression_offsets[ 0 ] = compression_offset; |
734 | |
|
735 | 0 | if( libcnotify_verbose != 0 ) |
736 | 0 | { |
737 | 0 | libcnotify_printf( |
738 | 0 | "%s: compression size\t\t\t\t: %" PRIu32 "\n", |
739 | 0 | function, |
740 | 0 | compression_size ); |
741 | |
|
742 | 0 | libcnotify_printf( |
743 | 0 | "%s: compression offset slot\t\t\t: %" PRIu32 "\n", |
744 | 0 | function, |
745 | 0 | compression_offset_slot ); |
746 | |
|
747 | 0 | libcnotify_printf( |
748 | 0 | "%s: compression offset\t\t\t\t: %" PRIu32 "\n", |
749 | 0 | function, |
750 | 0 | compression_offset ); |
751 | 0 | } |
752 | 0 | if( compression_offset > data_offset ) |
753 | 0 | { |
754 | 0 | libcerror_error_set( |
755 | 0 | error, |
756 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
757 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, |
758 | 0 | "%s: invalid compression offset value out of bounds.", |
759 | 0 | function ); |
760 | |
|
761 | 0 | return( -1 ); |
762 | 0 | } |
763 | 0 | if( ( data_offset + compression_size ) > uncompressed_data_size ) |
764 | 0 | { |
765 | 0 | libcerror_error_set( |
766 | 0 | error, |
767 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
768 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, |
769 | 0 | "%s: invalid uncompressed data value too small.", |
770 | 0 | function ); |
771 | |
|
772 | 0 | return( -1 ); |
773 | 0 | } |
774 | 0 | while( compression_size > 0 ) |
775 | 0 | { |
776 | 0 | uncompressed_data[ data_offset ] = uncompressed_data[ data_offset - compression_offset ]; |
777 | |
|
778 | 0 | data_offset++; |
779 | 0 | compression_size--; |
780 | 0 | } |
781 | 0 | } |
782 | 0 | } |
783 | 0 | *uncompressed_data_offset = data_offset; |
784 | |
|
785 | 0 | return( 1 ); |
786 | 0 | } |
787 | | |
788 | | /* Adjusts the 32-bit Intel 80x86 CALL (0xe8) instructions after decompression |
789 | | * Returns 1 on success or -1 on error |
790 | | */ |
791 | | int libfwnt_lzx_decompress_adjust_call_instructions( |
792 | | uint8_t *uncompressed_data, |
793 | | size_t uncompressed_data_size, |
794 | | libcerror_error_t **error ) |
795 | 0 | { |
796 | 0 | static char *function = "libfwnt_lzx_decompress_adjust_call_instructions"; |
797 | 0 | size_t uncompressed_data_offset = 0; |
798 | 0 | uint32_t address = 0; |
799 | |
|
800 | 0 | if( uncompressed_data == NULL ) |
801 | 0 | { |
802 | 0 | libcerror_error_set( |
803 | 0 | error, |
804 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
805 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
806 | 0 | "%s: invalid uncompressed data.", |
807 | 0 | function ); |
808 | |
|
809 | 0 | return( -1 ); |
810 | 0 | } |
811 | 0 | if( ( uncompressed_data_size < 6 ) |
812 | 0 | || ( uncompressed_data_size > (size_t) SSIZE_MAX ) ) |
813 | 0 | { |
814 | 0 | libcerror_error_set( |
815 | 0 | error, |
816 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
817 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, |
818 | 0 | "%s: invalid uncompressed data size value out of bounds.", |
819 | 0 | function ); |
820 | |
|
821 | 0 | return( -1 ); |
822 | 0 | } |
823 | 0 | for( uncompressed_data_offset = 0; |
824 | 0 | uncompressed_data_offset < ( uncompressed_data_size - 6 ); |
825 | 0 | uncompressed_data_offset++ ) |
826 | 0 | { |
827 | 0 | if( uncompressed_data[ uncompressed_data_offset ] != 0xe8 ) |
828 | 0 | { |
829 | 0 | continue; |
830 | 0 | } |
831 | 0 | byte_stream_copy_to_uint32_little_endian( |
832 | 0 | &( uncompressed_data[ uncompressed_data_offset + 1 ] ), |
833 | 0 | address ); |
834 | |
|
835 | 0 | if( address > (uint32_t) INT32_MAX ) |
836 | 0 | { |
837 | 0 | if( (int32_t) address > ( -1 * (int32_t) uncompressed_data_offset ) ) |
838 | 0 | { |
839 | 0 | address = (uint32_t) ( (int32_t) address + 12000000 ); |
840 | |
|
841 | 0 | byte_stream_copy_from_uint32_little_endian( |
842 | 0 | &( uncompressed_data[ uncompressed_data_offset + 1 ] ), |
843 | 0 | address ); |
844 | 0 | } |
845 | 0 | } |
846 | 0 | else |
847 | 0 | { |
848 | 0 | if( address < 12000000 ) |
849 | 0 | { |
850 | 0 | address = (uint32_t) ( (int32_t) address - uncompressed_data_offset ); |
851 | |
|
852 | 0 | byte_stream_copy_from_uint32_little_endian( |
853 | 0 | &( uncompressed_data[ uncompressed_data_offset + 1 ] ), |
854 | 0 | address ); |
855 | 0 | } |
856 | 0 | } |
857 | 0 | uncompressed_data_offset += 4; |
858 | 0 | } |
859 | 0 | return( 1 ); |
860 | 0 | } |
861 | | |
862 | | /* Decompresses LZX compressed data |
863 | | * Returns 1 on success or -1 on error |
864 | | */ |
865 | | int libfwnt_lzx_decompress( |
866 | | const uint8_t *compressed_data, |
867 | | size_t compressed_data_size, |
868 | | uint8_t *uncompressed_data, |
869 | | size_t *uncompressed_data_size, |
870 | | libcerror_error_t **error ) |
871 | 0 | { |
872 | 0 | uint8_t aligned_offsets_code_size_array[ 8 ]; |
873 | 0 | uint8_t lengths_code_size_array[ 249 ]; |
874 | 0 | uint8_t main_code_size_array[ 256 + 240 ]; |
875 | |
|
876 | 0 | uint32_t recent_compression_offsets[ 3 ] = { 1, 1, 1 }; |
877 | |
|
878 | 0 | libfwnt_bit_stream_t *bit_stream = NULL; |
879 | 0 | libfwnt_huffman_tree_t *aligned_offsets_huffman_tree = NULL; |
880 | 0 | libfwnt_huffman_tree_t *lengths_huffman_tree = NULL; |
881 | 0 | libfwnt_huffman_tree_t *main_huffman_tree = NULL; |
882 | 0 | static char *function = "libfwnt_lzx_decompress"; |
883 | 0 | size_t safe_uncompressed_data_size = 0; |
884 | 0 | size_t uncompressed_data_offset = 0; |
885 | 0 | uint32_t block_size = 0; |
886 | 0 | uint32_t block_type = 0; |
887 | 0 | int initialized_aligned_offsets_code_size_array = 0; |
888 | 0 | int initialized_main_and_length_code_size_arrays = 0; |
889 | |
|
890 | 0 | if( compressed_data == NULL ) |
891 | 0 | { |
892 | 0 | libcerror_error_set( |
893 | 0 | error, |
894 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
895 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
896 | 0 | "%s: invalid compressed data.", |
897 | 0 | function ); |
898 | |
|
899 | 0 | return( -1 ); |
900 | 0 | } |
901 | 0 | if( compressed_data_size > (size_t) SSIZE_MAX ) |
902 | 0 | { |
903 | 0 | libcerror_error_set( |
904 | 0 | error, |
905 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
906 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, |
907 | 0 | "%s: invalid compressed data size value exceeds maximum.", |
908 | 0 | function ); |
909 | |
|
910 | 0 | return( -1 ); |
911 | 0 | } |
912 | 0 | if( uncompressed_data == NULL ) |
913 | 0 | { |
914 | 0 | libcerror_error_set( |
915 | 0 | error, |
916 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
917 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
918 | 0 | "%s: invalid uncompressed data.", |
919 | 0 | function ); |
920 | |
|
921 | 0 | return( -1 ); |
922 | 0 | } |
923 | 0 | if( uncompressed_data_size == NULL ) |
924 | 0 | { |
925 | 0 | libcerror_error_set( |
926 | 0 | error, |
927 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
928 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
929 | 0 | "%s: invalid uncompressed data size.", |
930 | 0 | function ); |
931 | |
|
932 | 0 | return( -1 ); |
933 | 0 | } |
934 | 0 | if( *uncompressed_data_size > (size_t) SSIZE_MAX ) |
935 | 0 | { |
936 | 0 | libcerror_error_set( |
937 | 0 | error, |
938 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
939 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, |
940 | 0 | "%s: invalid uncompressed data size value exceeds maximum.", |
941 | 0 | function ); |
942 | |
|
943 | 0 | return( -1 ); |
944 | 0 | } |
945 | 0 | safe_uncompressed_data_size = *uncompressed_data_size; |
946 | |
|
947 | 0 | if( libfwnt_bit_stream_initialize( |
948 | 0 | &bit_stream, |
949 | 0 | compressed_data, |
950 | 0 | compressed_data_size, |
951 | 0 | error ) != 1 ) |
952 | 0 | { |
953 | 0 | libcerror_error_set( |
954 | 0 | error, |
955 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
956 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
957 | 0 | "%s: unable to create bit-stream.", |
958 | 0 | function ); |
959 | |
|
960 | 0 | goto on_error; |
961 | 0 | } |
962 | | /* TODO find optimized solution to read bit stream from bytes */ |
963 | 0 | while( bit_stream->byte_stream_offset < bit_stream->byte_stream_size ) |
964 | 0 | { |
965 | 0 | if( uncompressed_data_offset >= safe_uncompressed_data_size ) |
966 | 0 | { |
967 | 0 | break; |
968 | 0 | } |
969 | 0 | if( libfwnt_bit_stream_get_value( |
970 | 0 | bit_stream, |
971 | 0 | 3, |
972 | 0 | &block_type, |
973 | 0 | error ) != 1 ) |
974 | 0 | { |
975 | 0 | libcerror_error_set( |
976 | 0 | error, |
977 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
978 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
979 | 0 | "%s: unable to retrieve value from bit stream.", |
980 | 0 | function ); |
981 | |
|
982 | 0 | goto on_error; |
983 | 0 | } |
984 | 0 | if( libfwnt_bit_stream_get_value( |
985 | 0 | bit_stream, |
986 | 0 | 1, |
987 | 0 | &block_size, |
988 | 0 | error ) != 1 ) |
989 | 0 | { |
990 | 0 | libcerror_error_set( |
991 | 0 | error, |
992 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
993 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
994 | 0 | "%s: unable to retrieve value from bit stream.", |
995 | 0 | function ); |
996 | |
|
997 | 0 | goto on_error; |
998 | 0 | } |
999 | 0 | if( block_size != 0 ) |
1000 | 0 | { |
1001 | 0 | block_size = 32768; |
1002 | 0 | } |
1003 | 0 | else |
1004 | 0 | { |
1005 | 0 | if( libfwnt_bit_stream_get_value( |
1006 | 0 | bit_stream, |
1007 | 0 | 16, |
1008 | 0 | &block_size, |
1009 | 0 | error ) != 1 ) |
1010 | 0 | { |
1011 | 0 | libcerror_error_set( |
1012 | 0 | error, |
1013 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1014 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
1015 | 0 | "%s: unable to retrieve value from bit stream.", |
1016 | 0 | function ); |
1017 | |
|
1018 | 0 | goto on_error; |
1019 | 0 | } |
1020 | | /* TODO add extended block size support ? */ |
1021 | 0 | } |
1022 | 0 | if( libcnotify_verbose != 0 ) |
1023 | 0 | { |
1024 | 0 | libcnotify_printf( |
1025 | 0 | "%s: block header block type\t\t\t\t: %" PRIu32 " (", |
1026 | 0 | function, |
1027 | 0 | block_type ); |
1028 | |
|
1029 | 0 | switch( block_type ) |
1030 | 0 | { |
1031 | 0 | case LIBFWNT_LZX_BLOCK_TYPE_ALIGNED: |
1032 | 0 | libcnotify_printf( |
1033 | 0 | "Aligned" ); |
1034 | 0 | break; |
1035 | | |
1036 | 0 | case LIBFWNT_LZX_BLOCK_TYPE_VERBATIM: |
1037 | 0 | libcnotify_printf( |
1038 | 0 | "Verbatim" ); |
1039 | 0 | break; |
1040 | | |
1041 | 0 | case LIBFWNT_LZX_BLOCK_TYPE_UNCOMPRESSED: |
1042 | 0 | libcnotify_printf( |
1043 | 0 | "Uncompressed" ); |
1044 | 0 | break; |
1045 | | |
1046 | 0 | default: |
1047 | 0 | libcnotify_printf( |
1048 | 0 | "Invalid" ); |
1049 | 0 | break; |
1050 | 0 | } |
1051 | 0 | libcnotify_printf( |
1052 | 0 | ")\n" ); |
1053 | |
|
1054 | 0 | libcnotify_printf( |
1055 | 0 | "%s: block header block size\t\t\t\t: %" PRIu32 "\n", |
1056 | 0 | function, |
1057 | 0 | block_size ); |
1058 | |
|
1059 | 0 | libcnotify_printf( |
1060 | 0 | "\n" ); |
1061 | 0 | } |
1062 | 0 | switch( block_type ) |
1063 | 0 | { |
1064 | 0 | case LIBFWNT_LZX_BLOCK_TYPE_ALIGNED: |
1065 | 0 | if( initialized_aligned_offsets_code_size_array == 0 ) |
1066 | 0 | { |
1067 | 0 | if( memory_set( |
1068 | 0 | aligned_offsets_code_size_array, |
1069 | 0 | 0, |
1070 | 0 | sizeof( uint8_t ) * 8 ) == NULL ) |
1071 | 0 | { |
1072 | 0 | libcerror_error_set( |
1073 | 0 | error, |
1074 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
1075 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
1076 | 0 | "%s: unable to clear aligned offsets code size array.", |
1077 | 0 | function ); |
1078 | |
|
1079 | 0 | goto on_error; |
1080 | 0 | } |
1081 | 0 | initialized_aligned_offsets_code_size_array = 1; |
1082 | 0 | } |
1083 | 0 | if( libfwnt_huffman_tree_initialize( |
1084 | 0 | &aligned_offsets_huffman_tree, |
1085 | 0 | 256, |
1086 | 0 | 16, |
1087 | 0 | error ) != 1 ) |
1088 | 0 | { |
1089 | 0 | libcerror_error_set( |
1090 | 0 | error, |
1091 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1092 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1093 | 0 | "%s: unable to create aligned offsets Huffman tree.", |
1094 | 0 | function ); |
1095 | |
|
1096 | 0 | goto on_error; |
1097 | 0 | } |
1098 | 0 | if( libfwnt_lzx_build_aligned_offsets_huffman_tree( |
1099 | 0 | bit_stream, |
1100 | 0 | aligned_offsets_code_size_array, |
1101 | 0 | aligned_offsets_huffman_tree, |
1102 | 0 | error ) != 1 ) |
1103 | 0 | { |
1104 | 0 | libcerror_error_set( |
1105 | 0 | error, |
1106 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1107 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1108 | 0 | "%s: unable to build aligned offsets Huffman tree.", |
1109 | 0 | function ); |
1110 | |
|
1111 | 0 | goto on_error; |
1112 | 0 | } |
1113 | | |
1114 | 0 | LIBFWNT_LZX_ATTRIBUTE_FALLTHROUGH; |
1115 | 0 | case LIBFWNT_LZX_BLOCK_TYPE_VERBATIM: |
1116 | 0 | if( initialized_main_and_length_code_size_arrays == 0 ) |
1117 | 0 | { |
1118 | 0 | if( memory_set( |
1119 | 0 | main_code_size_array, |
1120 | 0 | 0, |
1121 | 0 | sizeof( uint8_t ) * ( 256 + 240 ) ) == NULL ) |
1122 | 0 | { |
1123 | 0 | libcerror_error_set( |
1124 | 0 | error, |
1125 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
1126 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
1127 | 0 | "%s: unable to clear main code size array.", |
1128 | 0 | function ); |
1129 | |
|
1130 | 0 | goto on_error; |
1131 | 0 | } |
1132 | 0 | if( memory_set( |
1133 | 0 | lengths_code_size_array, |
1134 | 0 | 0, |
1135 | 0 | sizeof( uint8_t ) * 249 ) == NULL ) |
1136 | 0 | { |
1137 | 0 | libcerror_error_set( |
1138 | 0 | error, |
1139 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
1140 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
1141 | 0 | "%s: unable to clear lengths code size array.", |
1142 | 0 | function ); |
1143 | |
|
1144 | 0 | goto on_error; |
1145 | 0 | } |
1146 | 0 | initialized_main_and_length_code_size_arrays = 1; |
1147 | 0 | } |
1148 | 0 | if( libfwnt_huffman_tree_initialize( |
1149 | 0 | &main_huffman_tree, |
1150 | 0 | 256 + 240, |
1151 | 0 | 16, |
1152 | 0 | error ) != 1 ) |
1153 | 0 | { |
1154 | 0 | libcerror_error_set( |
1155 | 0 | error, |
1156 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1157 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1158 | 0 | "%s: unable to create literals and match headers Huffman tree.", |
1159 | 0 | function ); |
1160 | |
|
1161 | 0 | goto on_error; |
1162 | 0 | } |
1163 | 0 | if( libfwnt_lzx_build_main_huffman_tree( |
1164 | 0 | bit_stream, |
1165 | 0 | main_code_size_array, |
1166 | 0 | main_huffman_tree, |
1167 | 0 | error ) != 1 ) |
1168 | 0 | { |
1169 | 0 | libcerror_error_set( |
1170 | 0 | error, |
1171 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1172 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1173 | 0 | "%s: unable to build literals and match headers Huffman tree.", |
1174 | 0 | function ); |
1175 | |
|
1176 | 0 | goto on_error; |
1177 | 0 | } |
1178 | 0 | if( libfwnt_huffman_tree_initialize( |
1179 | 0 | &lengths_huffman_tree, |
1180 | 0 | 249, |
1181 | 0 | 16, |
1182 | 0 | error ) != 1 ) |
1183 | 0 | { |
1184 | 0 | libcerror_error_set( |
1185 | 0 | error, |
1186 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1187 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1188 | 0 | "%s: unable to create lengths Huffman tree.", |
1189 | 0 | function ); |
1190 | |
|
1191 | 0 | goto on_error; |
1192 | 0 | } |
1193 | 0 | if( libfwnt_lzx_build_lengths_huffman_tree( |
1194 | 0 | bit_stream, |
1195 | 0 | lengths_code_size_array, |
1196 | 0 | lengths_huffman_tree, |
1197 | 0 | error ) != 1 ) |
1198 | 0 | { |
1199 | 0 | libcerror_error_set( |
1200 | 0 | error, |
1201 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1202 | 0 | LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, |
1203 | 0 | "%s: unable to build lengths Huffman tree.", |
1204 | 0 | function ); |
1205 | |
|
1206 | 0 | goto on_error; |
1207 | 0 | } |
1208 | 0 | if( libfwnt_lzx_decode_huffman( |
1209 | 0 | bit_stream, |
1210 | 0 | block_size, |
1211 | 0 | main_huffman_tree, |
1212 | 0 | lengths_huffman_tree, |
1213 | 0 | aligned_offsets_huffman_tree, |
1214 | 0 | recent_compression_offsets, |
1215 | 0 | uncompressed_data, |
1216 | 0 | safe_uncompressed_data_size, |
1217 | 0 | &uncompressed_data_offset, |
1218 | 0 | error ) != 1 ) |
1219 | 0 | { |
1220 | 0 | libcerror_error_set( |
1221 | 0 | error, |
1222 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1223 | 0 | LIBCERROR_RUNTIME_ERROR_GET_FAILED, |
1224 | 0 | "%s: unable to decode fixed Huffman encoded bit stream.", |
1225 | 0 | function ); |
1226 | |
|
1227 | 0 | goto on_error; |
1228 | 0 | } |
1229 | 0 | if( aligned_offsets_huffman_tree != NULL ) |
1230 | 0 | { |
1231 | 0 | if( libfwnt_huffman_tree_free( |
1232 | 0 | &aligned_offsets_huffman_tree, |
1233 | 0 | error ) != 1 ) |
1234 | 0 | { |
1235 | 0 | libcerror_error_set( |
1236 | 0 | error, |
1237 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1238 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
1239 | 0 | "%s: unable to free aligned offsets Huffman tree.", |
1240 | 0 | function ); |
1241 | |
|
1242 | 0 | goto on_error; |
1243 | 0 | } |
1244 | 0 | } |
1245 | 0 | if( libfwnt_huffman_tree_free( |
1246 | 0 | &lengths_huffman_tree, |
1247 | 0 | error ) != 1 ) |
1248 | 0 | { |
1249 | 0 | libcerror_error_set( |
1250 | 0 | error, |
1251 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1252 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
1253 | 0 | "%s: unable to free lengths Huffman tree.", |
1254 | 0 | function ); |
1255 | |
|
1256 | 0 | goto on_error; |
1257 | 0 | } |
1258 | 0 | if( libfwnt_huffman_tree_free( |
1259 | 0 | &main_huffman_tree, |
1260 | 0 | error ) != 1 ) |
1261 | 0 | { |
1262 | 0 | libcerror_error_set( |
1263 | 0 | error, |
1264 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1265 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
1266 | 0 | "%s: unable to free literals and match headers Huffman tree.", |
1267 | 0 | function ); |
1268 | |
|
1269 | 0 | goto on_error; |
1270 | 0 | } |
1271 | 0 | break; |
1272 | | |
1273 | 0 | case LIBFWNT_LZX_BLOCK_TYPE_UNCOMPRESSED: |
1274 | | /* TODO align byte stream */ |
1275 | 0 | if( ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) < 12 ) |
1276 | 0 | { |
1277 | 0 | libcerror_error_set( |
1278 | 0 | error, |
1279 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
1280 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, |
1281 | 0 | "%s: invalid compressed data value too small.", |
1282 | 0 | function ); |
1283 | |
|
1284 | 0 | goto on_error; |
1285 | 0 | } |
1286 | 0 | byte_stream_copy_to_uint32_little_endian( |
1287 | 0 | &( compressed_data[ bit_stream->byte_stream_offset ] ), |
1288 | 0 | recent_compression_offsets[ 0 ] ); |
1289 | |
|
1290 | 0 | bit_stream->byte_stream_offset += 4; |
1291 | |
|
1292 | 0 | byte_stream_copy_to_uint32_little_endian( |
1293 | 0 | &( compressed_data[ bit_stream->byte_stream_offset ] ), |
1294 | 0 | recent_compression_offsets[ 1 ] ); |
1295 | |
|
1296 | 0 | bit_stream->byte_stream_offset += 4; |
1297 | |
|
1298 | 0 | byte_stream_copy_to_uint32_little_endian( |
1299 | 0 | &( compressed_data[ bit_stream->byte_stream_offset ] ), |
1300 | 0 | recent_compression_offsets[ 2 ] ); |
1301 | |
|
1302 | 0 | bit_stream->byte_stream_offset += 4; |
1303 | |
|
1304 | 0 | if( recent_compression_offsets[ 0 ] == 0 ) |
1305 | 0 | { |
1306 | 0 | libcerror_error_set( |
1307 | 0 | error, |
1308 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1309 | 0 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
1310 | 0 | "%s: unsupported R0 value.", |
1311 | 0 | function ); |
1312 | |
|
1313 | 0 | goto on_error; |
1314 | 0 | } |
1315 | 0 | if( recent_compression_offsets[ 1 ] == 0 ) |
1316 | 0 | { |
1317 | 0 | libcerror_error_set( |
1318 | 0 | error, |
1319 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1320 | 0 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
1321 | 0 | "%s: unsupported R1 value.", |
1322 | 0 | function ); |
1323 | |
|
1324 | 0 | goto on_error; |
1325 | 0 | } |
1326 | 0 | if( recent_compression_offsets[ 2 ] == 0 ) |
1327 | 0 | { |
1328 | 0 | libcerror_error_set( |
1329 | 0 | error, |
1330 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1331 | 0 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
1332 | 0 | "%s: unsupported R2 value.", |
1333 | 0 | function ); |
1334 | |
|
1335 | 0 | goto on_error; |
1336 | 0 | } |
1337 | 0 | if( libcnotify_verbose != 0 ) |
1338 | 0 | { |
1339 | 0 | libcnotify_printf( |
1340 | 0 | "%s: R0 value\t\t\t\t\t: 0x%08" PRIx32 "\n", |
1341 | 0 | function, |
1342 | 0 | recent_compression_offsets[ 0 ] ); |
1343 | |
|
1344 | 0 | libcnotify_printf( |
1345 | 0 | "%s: R1 value\t\t\t\t\t: 0x%08" PRIx32 "\n", |
1346 | 0 | function, |
1347 | 0 | recent_compression_offsets[ 1 ] ); |
1348 | |
|
1349 | 0 | libcnotify_printf( |
1350 | 0 | "%s: R2 value\t\t\t\t\t: 0x%08" PRIx32 "\n", |
1351 | 0 | function, |
1352 | 0 | recent_compression_offsets[ 2 ] ); |
1353 | |
|
1354 | 0 | libcnotify_printf( |
1355 | 0 | "\n" ); |
1356 | 0 | } |
1357 | 0 | if( (size_t) block_size > ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) ) |
1358 | 0 | { |
1359 | 0 | block_size = (uint32_t) ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ); |
1360 | 0 | } |
1361 | 0 | if( (size_t) block_size > ( safe_uncompressed_data_size - uncompressed_data_offset ) ) |
1362 | 0 | { |
1363 | 0 | libcerror_error_set( |
1364 | 0 | error, |
1365 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
1366 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, |
1367 | 0 | "%s: invalid uncompressed data value too small.", |
1368 | 0 | function ); |
1369 | |
|
1370 | 0 | goto on_error; |
1371 | 0 | } |
1372 | 0 | if( memory_copy( |
1373 | 0 | &( uncompressed_data[ uncompressed_data_offset ] ), |
1374 | 0 | &( compressed_data[ bit_stream->byte_stream_offset ] ), |
1375 | 0 | (size_t) block_size ) == NULL ) |
1376 | 0 | { |
1377 | 0 | libcerror_error_set( |
1378 | 0 | error, |
1379 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
1380 | 0 | LIBCERROR_MEMORY_ERROR_COPY_FAILED, |
1381 | 0 | "%s: unable to initialize lz buffer.", |
1382 | 0 | function ); |
1383 | |
|
1384 | 0 | goto on_error; |
1385 | 0 | } |
1386 | 0 | bit_stream->byte_stream_offset += block_size; |
1387 | 0 | uncompressed_data_offset += block_size; |
1388 | | |
1389 | | /* Flush the bit-stream buffer |
1390 | | */ |
1391 | 0 | bit_stream->bit_buffer = 0; |
1392 | 0 | bit_stream->bit_buffer_size = 0; |
1393 | |
|
1394 | 0 | break; |
1395 | | |
1396 | 0 | default: |
1397 | 0 | libcerror_error_set( |
1398 | 0 | error, |
1399 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1400 | 0 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
1401 | 0 | "%s: unsupported block type.", |
1402 | 0 | function ); |
1403 | |
|
1404 | 0 | goto on_error; |
1405 | 0 | } |
1406 | 0 | } |
1407 | 0 | if( libfwnt_bit_stream_free( |
1408 | 0 | &bit_stream, |
1409 | 0 | error ) != 1 ) |
1410 | 0 | { |
1411 | 0 | libcerror_error_set( |
1412 | 0 | error, |
1413 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1414 | 0 | LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, |
1415 | 0 | "%s: unable to free bit-stream.", |
1416 | 0 | function ); |
1417 | |
|
1418 | 0 | goto on_error; |
1419 | 0 | } |
1420 | 0 | if( libfwnt_lzx_decompress_adjust_call_instructions( |
1421 | 0 | uncompressed_data, |
1422 | 0 | uncompressed_data_offset, |
1423 | 0 | error ) != 1 ) |
1424 | 0 | { |
1425 | 0 | libcerror_error_set( |
1426 | 0 | error, |
1427 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
1428 | 0 | LIBCERROR_RUNTIME_ERROR_SET_FAILED, |
1429 | 0 | "%s: unable to adjust call instructions.", |
1430 | 0 | function ); |
1431 | |
|
1432 | 0 | goto on_error; |
1433 | 0 | } |
1434 | 0 | *uncompressed_data_size = uncompressed_data_offset; |
1435 | |
|
1436 | 0 | return( 1 ); |
1437 | | |
1438 | 0 | on_error: |
1439 | 0 | if( lengths_huffman_tree != NULL ) |
1440 | 0 | { |
1441 | 0 | libfwnt_huffman_tree_free( |
1442 | 0 | &lengths_huffman_tree, |
1443 | 0 | NULL ); |
1444 | 0 | } |
1445 | 0 | if( main_huffman_tree != NULL ) |
1446 | 0 | { |
1447 | 0 | libfwnt_huffman_tree_free( |
1448 | 0 | &main_huffman_tree, |
1449 | 0 | NULL ); |
1450 | 0 | } |
1451 | 0 | if( aligned_offsets_huffman_tree != NULL ) |
1452 | 0 | { |
1453 | 0 | libfwnt_huffman_tree_free( |
1454 | 0 | &aligned_offsets_huffman_tree, |
1455 | 0 | NULL ); |
1456 | 0 | } |
1457 | 0 | if( bit_stream != NULL ) |
1458 | 0 | { |
1459 | 0 | libfwnt_bit_stream_free( |
1460 | 0 | &bit_stream, |
1461 | 0 | NULL ); |
1462 | 0 | } |
1463 | 0 | return( -1 ); |
1464 | 0 | } |
1465 | | |