Coverage Report

Created: 2023-06-07 06:53

/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-2022, 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
8.95k
{
64
8.95k
  uint8_t pre_code_size_array[ 20 ];
65
66
8.95k
  libfwnt_huffman_tree_t *pre_codes_huffman_tree = NULL;
67
8.95k
  static char *function                          = "libfwnt_lzx_read_huffman_code_sizes";
68
8.95k
  uint32_t symbol                                = 0;
69
8.95k
  uint32_t times_to_repeat                       = 0;
70
8.95k
  uint32_t value_32bit                           = 0;
71
8.95k
  int32_t code_size                              = 0;
72
8.95k
  uint8_t pre_code_index                         = 0;
73
8.95k
  int code_size_index                            = 0;
74
75
8.95k
  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
8.95k
  for( pre_code_index = 0;
87
188k
       pre_code_index < 20;
88
179k
       pre_code_index++ )
89
179k
  {
90
179k
    if( libfwnt_bit_stream_get_value(
91
179k
         bit_stream,
92
179k
         4,
93
179k
         &value_32bit,
94
179k
         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
179k
    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
179k
    pre_code_size_array[ pre_code_index ] = (uint8_t) value_32bit;
115
179k
  }
116
8.95k
  if( libcnotify_verbose != 0 )
117
0
  {
118
0
    libcnotify_printf(
119
0
     "\n" );
120
0
  }
121
8.95k
  if( libfwnt_huffman_tree_initialize(
122
8.95k
       &pre_codes_huffman_tree,
123
8.95k
       20,
124
8.95k
       15,
125
8.95k
       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
8.95k
  if( libfwnt_huffman_tree_build(
137
8.95k
       pre_codes_huffman_tree,
138
8.95k
       pre_code_size_array,
139
8.95k
       20,
140
8.95k
       error ) != 1 )
141
181
  {
142
181
    libcerror_error_set(
143
181
     error,
144
181
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
145
181
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
146
181
     "%s: unable to build pre-codes Huffman tree.",
147
181
     function );
148
149
181
    goto on_error;
150
181
  }
151
8.77k
  code_size_index = 0;
152
153
151k
  while( code_size_index < number_of_code_sizes )
154
142k
  {
155
142k
    if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
156
142k
         pre_codes_huffman_tree,
157
142k
         bit_stream,
158
142k
         &symbol,
159
142k
         error ) != 1 )
160
39
    {
161
39
      libcerror_error_set(
162
39
       error,
163
39
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
164
39
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
165
39
       "%s: unable to retrieve symbol from pre-codes Huffman tree.",
166
39
       function );
167
168
39
      goto on_error;
169
39
    }
170
142k
    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
142k
    if( symbol < 17 )
179
86.4k
    {
180
86.4k
      code_size = code_size_array[ code_size_index ] - symbol;
181
182
86.4k
      if( code_size < 0 )
183
61.3k
      {
184
61.3k
        code_size += 17;
185
61.3k
      }
186
86.4k
      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
86.4k
      code_size_array[ code_size_index++ ] = (uint8_t) code_size;
195
196
86.4k
      continue;
197
86.4k
    }
198
56.0k
    code_size = 0;
199
200
56.0k
    if( symbol == 17 )
201
1.03k
    {
202
1.03k
      if( libfwnt_bit_stream_get_value(
203
1.03k
           bit_stream,
204
1.03k
           4,
205
1.03k
           &times_to_repeat,
206
1.03k
           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
1.03k
      times_to_repeat += 4;
218
1.03k
    }
219
54.9k
    else if( symbol == 18 )
220
54.2k
    {
221
54.2k
      if( libfwnt_bit_stream_get_value(
222
54.2k
           bit_stream,
223
54.2k
           5,
224
54.2k
           &times_to_repeat,
225
54.2k
           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
54.2k
      times_to_repeat += 20;
237
54.2k
    }
238
745
    else if( symbol == 19 )
239
745
    {
240
745
      if( libfwnt_bit_stream_get_value(
241
745
           bit_stream,
242
745
           1,
243
745
           &times_to_repeat,
244
745
           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
745
      times_to_repeat += 4;
256
257
745
      if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
258
745
           pre_codes_huffman_tree,
259
745
           bit_stream,
260
745
           &symbol,
261
745
           error ) != 1 )
262
2
      {
263
2
        libcerror_error_set(
264
2
         error,
265
2
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
266
2
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
267
2
         "%s: unable to retrieve symbol from pre-codes Huffman tree.",
268
2
         function );
269
270
2
        goto on_error;
271
2
      }
272
743
      if( symbol > 17 )
273
9
      {
274
9
        libcerror_error_set(
275
9
         error,
276
9
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
277
9
         LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
278
9
         "%s: invalid code size symbol value out of bounds.",
279
9
         function );
280
281
9
        goto on_error;
282
9
      }
283
734
      code_size = code_size_array[ code_size_index ] - symbol;
284
285
734
      if( code_size < 0 )
286
452
      {
287
452
        code_size += 17;
288
452
      }
289
734
    }
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
56.0k
    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
56.0k
    if( times_to_repeat > (uint32_t) ( number_of_code_sizes - code_size_index ) )
309
6.67k
    {
310
6.67k
      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
6.67k
      times_to_repeat = (uint32_t) ( number_of_code_sizes - code_size_index );
317
6.67k
    }
318
2.13M
    while( times_to_repeat > 0 )
319
2.08M
    {
320
2.08M
      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
2.08M
      code_size_array[ code_size_index++ ] = (uint8_t) code_size;
329
330
2.08M
      times_to_repeat--;
331
2.08M
    }
332
56.0k
  }
333
8.72k
  if( libfwnt_huffman_tree_free(
334
8.72k
       &pre_codes_huffman_tree,
335
8.72k
       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
8.72k
  if( libcnotify_verbose != 0 )
347
0
  {
348
0
    libcnotify_printf(
349
0
     "\n" );
350
0
  }
351
8.72k
  return( 1 );
352
353
231
on_error:
354
231
  if( pre_codes_huffman_tree != NULL )
355
231
  {
356
231
    libfwnt_huffman_tree_free(
357
231
     &pre_codes_huffman_tree,
358
231
     NULL );
359
231
  }
360
231
  return( -1 );
361
8.72k
}
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
3.08k
{
372
3.08k
  static char *function = "libfwnt_lzx_build_main_huffman_tree";
373
374
3.08k
  if( libfwnt_lzx_read_huffman_code_sizes(
375
3.08k
       bit_stream,
376
3.08k
       code_size_array,
377
3.08k
       256,
378
3.08k
       error ) != 1 )
379
80
  {
380
80
    libcerror_error_set(
381
80
     error,
382
80
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
383
80
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
384
80
     "%s: unable to read literals Huffman code sizes.",
385
80
     function );
386
387
80
    return( -1 );
388
80
  }
389
3.00k
  if( libfwnt_lzx_read_huffman_code_sizes(
390
3.00k
       bit_stream,
391
3.00k
       &( code_size_array[ 256 ] ),
392
3.00k
       240,
393
3.00k
       error ) != 1 )
394
113
  {
395
113
    libcerror_error_set(
396
113
     error,
397
113
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
398
113
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
399
113
     "%s: unable to read literals Huffman code sizes.",
400
113
     function );
401
402
113
    return( -1 );
403
113
  }
404
2.88k
  if( libfwnt_huffman_tree_build(
405
2.88k
       huffman_tree,
406
2.88k
       code_size_array,
407
2.88k
       256 + 240,
408
2.88k
       error ) != 1 )
409
14
  {
410
14
    libcerror_error_set(
411
14
     error,
412
14
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
413
14
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
414
14
     "%s: unable to build literals and match headers Huffman tree.",
415
14
     function );
416
417
14
    return( -1 );
418
14
  }
419
2.87k
  return( 1 );
420
2.88k
}
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
2.87k
{
431
2.87k
  static char *function = "libfwnt_lzx_build_lengths_huffman_tree";
432
433
2.87k
  if( libfwnt_lzx_read_huffman_code_sizes(
434
2.87k
       bit_stream,
435
2.87k
       code_size_array,
436
2.87k
       249,
437
2.87k
       error ) != 1 )
438
38
  {
439
38
    libcerror_error_set(
440
38
     error,
441
38
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
442
38
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
443
38
     "%s: unable to read literals Huffman code sizes.",
444
38
     function );
445
446
38
    return( -1 );
447
38
  }
448
2.83k
  if( libfwnt_huffman_tree_build(
449
2.83k
       huffman_tree,
450
2.83k
       code_size_array,
451
2.83k
       249,
452
2.83k
       error ) != 1 )
453
8
  {
454
8
    libcerror_error_set(
455
8
     error,
456
8
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
457
8
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
458
8
     "%s: unable to build lengths Huffman tree.",
459
8
     function );
460
461
8
    return( -1 );
462
8
  }
463
2.82k
  return( 1 );
464
2.83k
}
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
1.12k
{
475
1.12k
  static char *function = "libfwnt_lzx_build_aligned_offsets_huffman_tree";
476
1.12k
  uint32_t code_size    = 0;
477
1.12k
  int code_size_index   = 0;
478
479
1.12k
  for( code_size_index = 0;
480
10.1k
       code_size_index < 8;
481
9.03k
       code_size_index++ )
482
9.03k
  {
483
9.03k
    if( libfwnt_bit_stream_get_value(
484
9.03k
         bit_stream,
485
9.03k
         3,
486
9.03k
         &code_size,
487
9.03k
         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
9.03k
    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
9.03k
    code_size_array[ code_size_index ] = (uint8_t) code_size;
507
9.03k
  }
508
1.12k
  if( libfwnt_huffman_tree_build(
509
1.12k
       huffman_tree,
510
1.12k
       code_size_array,
511
1.12k
       8,
512
1.12k
       error ) != 1 )
513
4
  {
514
4
    libcerror_error_set(
515
4
     error,
516
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
517
4
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
518
4
     "%s: unable to build aligned offsets Huffman tree.",
519
4
     function );
520
521
4
    return( -1 );
522
4
  }
523
1.12k
  return( 1 );
524
1.12k
}
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
2.82k
{
541
2.82k
  static char *function            = "libfwnt_lzx_decode_huffman";
542
2.82k
  size_t data_end_offset           = 0;
543
2.82k
  size_t data_offset               = 0;
544
2.82k
  uint32_t aligned_offset          = 0;
545
2.82k
  uint32_t compression_offset      = 0;
546
2.82k
  uint32_t compression_offset_slot = 0;
547
2.82k
  uint32_t compression_size        = 0;
548
2.82k
  uint32_t symbol                  = 0;
549
2.82k
  uint8_t number_of_bits           = 0;
550
551
2.82k
  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
2.82k
  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
2.82k
  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
2.82k
  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
2.82k
  data_offset     = *uncompressed_data_offset;
596
2.82k
  data_end_offset = data_offset + block_size;
597
598
3.00M
  while( data_offset < data_end_offset )
599
3.00M
  {
600
3.00M
    if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
601
3.00M
         main_huffman_tree,
602
3.00M
         bit_stream,
603
3.00M
         &symbol,
604
3.00M
         error ) != 1 )
605
4
    {
606
4
      libcerror_error_set(
607
4
       error,
608
4
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
609
4
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
610
4
       "%s: unable to retrieve symbol from literals and match headers Huffman tree.",
611
4
       function );
612
613
4
      return( -1 );
614
4
    }
615
3.00M
    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
3.00M
    if( symbol < 256 )
623
2.76M
    {
624
2.76M
      if( data_offset >= uncompressed_data_size )
625
3
      {
626
3
        libcerror_error_set(
627
3
         error,
628
3
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
629
3
         LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
630
3
         "%s: invalid uncompressed data value too small.",
631
3
         function );
632
633
3
        return( -1 );
634
3
      }
635
2.76M
      uncompressed_data[ data_offset++ ] = (uint8_t) symbol;
636
2.76M
    }
637
239k
    else
638
239k
    {
639
239k
      compression_size        = symbol % 8;
640
239k
      compression_offset_slot = ( symbol - 256 ) / 8;
641
642
239k
      if( compression_size == 7 )
643
56.2k
      {
644
56.2k
        if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
645
56.2k
             lengths_huffman_tree,
646
56.2k
             bit_stream,
647
56.2k
             &compression_size,
648
56.2k
             error ) != 1 )
649
2
        {
650
2
          libcerror_error_set(
651
2
           error,
652
2
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
653
2
           LIBCERROR_RUNTIME_ERROR_GET_FAILED,
654
2
           "%s: unable to retrieve symbol from lengths Huffman tree.",
655
2
           function );
656
657
2
          return( -1 );
658
2
        }
659
56.2k
        compression_size += 7;
660
56.2k
      }
661
239k
      compression_size += 2;
662
663
239k
      if( compression_offset_slot < 3 )
664
80.3k
      {
665
80.3k
        compression_offset = recent_compression_offsets[ compression_offset_slot ];
666
667
80.3k
        recent_compression_offsets[ compression_offset_slot ] = recent_compression_offsets[ 0 ];
668
80.3k
      }
669
159k
      else
670
159k
      {
671
159k
        number_of_bits = libfwnt_lzx_number_of_footer_bits[ compression_offset_slot ];
672
673
159k
        if( ( aligned_offsets_huffman_tree != NULL )
674
159k
         && ( compression_offset_slot >= 8 ) )
675
11.7k
        {
676
11.7k
          number_of_bits -= 3;
677
11.7k
        }
678
159k
        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
159k
        if( libfwnt_bit_stream_get_value(
686
159k
             bit_stream,
687
159k
             number_of_bits,
688
159k
             &compression_offset,
689
159k
             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
159k
        if( ( aligned_offsets_huffman_tree != NULL )
701
159k
         && ( compression_offset_slot >= 8 ) )
702
11.7k
        {
703
11.7k
          if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
704
11.7k
               aligned_offsets_huffman_tree,
705
11.7k
               bit_stream,
706
11.7k
               &aligned_offset,
707
11.7k
               error ) != 1 )
708
1
          {
709
1
            libcerror_error_set(
710
1
             error,
711
1
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
712
1
             LIBCERROR_RUNTIME_ERROR_GET_FAILED,
713
1
             "%s: unable to retrieve symbol from literals and match headers Huffman tree.",
714
1
             function );
715
716
1
            return( -1 );
717
1
          }
718
11.7k
          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
11.7k
          compression_offset <<= 3;
726
11.7k
          compression_offset  |= aligned_offset;
727
11.7k
        }
728
159k
        compression_offset += libfwnt_lzx_compression_offset_base[ compression_offset_slot ];
729
730
159k
        recent_compression_offsets[ 2 ] = recent_compression_offsets[ 1 ];
731
159k
        recent_compression_offsets[ 1 ] = recent_compression_offsets[ 0 ];
732
159k
      }
733
239k
      recent_compression_offsets[ 0 ] = compression_offset;
734
735
239k
      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
239k
      if( compression_offset > data_offset )
753
54
      {
754
54
        libcerror_error_set(
755
54
         error,
756
54
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
757
54
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
758
54
         "%s: invalid compression offset value out of bounds.",
759
54
         function );
760
761
54
        return( -1 );
762
54
      }
763
239k
      if( ( data_offset + compression_size ) > uncompressed_data_size )
764
14
      {
765
14
        libcerror_error_set(
766
14
         error,
767
14
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
768
14
         LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
769
14
         "%s: invalid uncompressed data value too small.",
770
14
         function );
771
772
14
        return( -1 );
773
14
      }
774
3.89M
      while( compression_size > 0 )
775
3.65M
      {
776
3.65M
        uncompressed_data[ data_offset ] = uncompressed_data[ data_offset - compression_offset ];
777
778
3.65M
        data_offset++;
779
3.65M
        compression_size--;
780
3.65M
      }
781
239k
    }
782
3.00M
  }
783
2.74k
  *uncompressed_data_offset = data_offset;
784
785
2.74k
  return( 1 );
786
2.82k
}
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
366
{
796
366
  static char *function           = "libfwnt_lzx_decompress_adjust_call_instructions";
797
366
  size_t uncompressed_data_offset = 0;
798
366
  uint32_t address                = 0;
799
800
366
  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
366
  if( ( uncompressed_data_size < 6 )
812
366
   || ( uncompressed_data_size > (size_t) SSIZE_MAX ) )
813
113
  {
814
113
    libcerror_error_set(
815
113
     error,
816
113
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
817
113
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
818
113
     "%s: invalid uncompressed data size value out of bounds.",
819
113
     function );
820
821
113
    return( -1 );
822
113
  }
823
253
  for( uncompressed_data_offset = 0;
824
4.06M
       uncompressed_data_offset < ( uncompressed_data_size - 6 );
825
4.06M
       uncompressed_data_offset++ )
826
4.06M
  {
827
4.06M
    if( uncompressed_data[ uncompressed_data_offset ] != 0xe8 )
828
3.98M
    {
829
3.98M
      continue;
830
3.98M
    }
831
78.3k
    byte_stream_copy_to_uint32_little_endian(
832
78.3k
     &( uncompressed_data[ uncompressed_data_offset + 1 ] ),
833
78.3k
     address );
834
835
78.3k
    if( address > (uint32_t) INT32_MAX )
836
48.1k
    {
837
48.1k
      if( (int32_t) address > ( -1 * (int32_t) uncompressed_data_offset ) )
838
21.0k
      {
839
21.0k
        address = (uint32_t) ( (int32_t) address + 12000000 );
840
841
21.0k
        byte_stream_copy_from_uint32_little_endian(
842
21.0k
         &( uncompressed_data[ uncompressed_data_offset + 1 ] ),
843
21.0k
         address );
844
21.0k
      }
845
48.1k
    }
846
30.2k
    else
847
30.2k
    {
848
30.2k
      if( address < 12000000 )
849
12.6k
      {
850
12.6k
        address = (uint32_t) ( (int32_t) address - uncompressed_data_offset );
851
852
12.6k
        byte_stream_copy_from_uint32_little_endian(
853
12.6k
         &( uncompressed_data[ uncompressed_data_offset + 1 ] ),
854
12.6k
         address );
855
12.6k
      }
856
30.2k
    }
857
78.3k
    uncompressed_data_offset += 4;
858
78.3k
  }
859
253
  return( 1 );
860
366
}
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
779
{
872
779
  uint8_t aligned_offsets_code_size_array[ 8 ];
873
779
  uint8_t lengths_code_size_array[ 249 ];
874
779
  uint8_t main_code_size_array[ 256 + 240 ];
875
876
779
  uint32_t recent_compression_offsets[ 3 ]             = { 1, 1, 1 };
877
878
779
  libfwnt_bit_stream_t *bit_stream                     = NULL;
879
779
  libfwnt_huffman_tree_t *aligned_offsets_huffman_tree = NULL;
880
779
  libfwnt_huffman_tree_t *lengths_huffman_tree         = NULL;
881
779
  libfwnt_huffman_tree_t *main_huffman_tree            = NULL;
882
779
  static char *function                                = "libfwnt_lzx_decompress";
883
779
  size_t safe_uncompressed_data_size                   = 0;
884
779
  size_t uncompressed_data_offset                      = 0;
885
779
  uint32_t block_size                                  = 0;
886
779
  uint32_t block_type                                  = 0;
887
779
  int initialized_aligned_offsets_code_size_array      = 0;
888
779
  int initialized_main_and_length_code_size_arrays     = 0;
889
890
779
  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
779
  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
779
  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
779
  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
779
  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
779
  safe_uncompressed_data_size = *uncompressed_data_size;
946
947
779
  if( libfwnt_bit_stream_initialize(
948
779
       &bit_stream,
949
779
       compressed_data,
950
779
       compressed_data_size,
951
779
       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
4.55k
  while( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
964
4.19k
  {
965
4.19k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
966
1
    {
967
1
      break;
968
1
    }
969
4.19k
    if( libfwnt_bit_stream_get_value(
970
4.19k
         bit_stream,
971
4.19k
         3,
972
4.19k
         &block_type,
973
4.19k
         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
4.19k
    if( libfwnt_bit_stream_get_value(
985
4.19k
         bit_stream,
986
4.19k
         1,
987
4.19k
         &block_size,
988
4.19k
         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
4.19k
    if( block_size != 0 )
1000
594
    {
1001
594
      block_size = 32768;
1002
594
    }
1003
3.59k
    else
1004
3.59k
    {
1005
3.59k
      if( libfwnt_bit_stream_get_value(
1006
3.59k
           bit_stream,
1007
3.59k
           16,
1008
3.59k
           &block_size,
1009
3.59k
           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
3.59k
    }
1022
4.19k
    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
4.19k
    switch( block_type )
1063
4.19k
    {
1064
1.12k
      case LIBFWNT_LZX_BLOCK_TYPE_ALIGNED:
1065
1.12k
        if( initialized_aligned_offsets_code_size_array == 0 )
1066
112
        {
1067
112
          if( memory_set(
1068
112
               aligned_offsets_code_size_array,
1069
112
               0,
1070
112
               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
112
          initialized_aligned_offsets_code_size_array = 1;
1082
112
        }
1083
1.12k
        if( libfwnt_huffman_tree_initialize(
1084
1.12k
             &aligned_offsets_huffman_tree,
1085
1.12k
             256,
1086
1.12k
             16,
1087
1.12k
             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
1.12k
        if( libfwnt_lzx_build_aligned_offsets_huffman_tree(
1099
1.12k
             bit_stream,
1100
1.12k
             aligned_offsets_code_size_array,
1101
1.12k
             aligned_offsets_huffman_tree,
1102
1.12k
             error ) != 1 )
1103
4
        {
1104
4
          libcerror_error_set(
1105
4
           error,
1106
4
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1107
4
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1108
4
           "%s: unable to build aligned offsets Huffman tree.",
1109
4
           function );
1110
1111
4
          goto on_error;
1112
4
        }
1113
1114
1.12k
      LIBFWNT_LZX_ATTRIBUTE_FALLTHROUGH;
1115
3.08k
      case LIBFWNT_LZX_BLOCK_TYPE_VERBATIM:
1116
3.08k
        if( initialized_main_and_length_code_size_arrays == 0 )
1117
478
        {
1118
478
          if( memory_set(
1119
478
               main_code_size_array,
1120
478
               0,
1121
478
               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
478
          if( memory_set(
1133
478
               lengths_code_size_array,
1134
478
               0,
1135
478
               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
478
          initialized_main_and_length_code_size_arrays = 1;
1147
478
        }
1148
3.08k
        if( libfwnt_huffman_tree_initialize(
1149
3.08k
             &main_huffman_tree,
1150
3.08k
             256 + 240,
1151
3.08k
             16,
1152
3.08k
             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
3.08k
        if( libfwnt_lzx_build_main_huffman_tree(
1164
3.08k
             bit_stream,
1165
3.08k
             main_code_size_array,
1166
3.08k
             main_huffman_tree,
1167
3.08k
             error ) != 1 )
1168
207
        {
1169
207
          libcerror_error_set(
1170
207
           error,
1171
207
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1172
207
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1173
207
           "%s: unable to build literals and match headers Huffman tree.",
1174
207
           function );
1175
1176
207
          goto on_error;
1177
207
        }
1178
2.87k
        if( libfwnt_huffman_tree_initialize(
1179
2.87k
             &lengths_huffman_tree,
1180
2.87k
             249,
1181
2.87k
             16,
1182
2.87k
             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
2.87k
        if( libfwnt_lzx_build_lengths_huffman_tree(
1194
2.87k
             bit_stream,
1195
2.87k
             lengths_code_size_array,
1196
2.87k
             lengths_huffman_tree,
1197
2.87k
             error ) != 1 )
1198
46
        {
1199
46
          libcerror_error_set(
1200
46
           error,
1201
46
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1202
46
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1203
46
           "%s: unable to build lengths Huffman tree.",
1204
46
           function );
1205
1206
46
          goto on_error;
1207
46
        }
1208
2.82k
        if( libfwnt_lzx_decode_huffman(
1209
2.82k
             bit_stream,
1210
2.82k
             block_size,
1211
2.82k
             main_huffman_tree,
1212
2.82k
             lengths_huffman_tree,
1213
2.82k
             aligned_offsets_huffman_tree,
1214
2.82k
             recent_compression_offsets,
1215
2.82k
             uncompressed_data,
1216
2.82k
             safe_uncompressed_data_size,
1217
2.82k
             &uncompressed_data_offset,
1218
2.82k
             error ) != 1 )
1219
78
        {
1220
78
          libcerror_error_set(
1221
78
           error,
1222
78
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1223
78
           LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1224
78
           "%s: unable to decode fixed Huffman encoded bit stream.",
1225
78
           function );
1226
1227
78
          goto on_error;
1228
78
        }
1229
2.74k
        if( aligned_offsets_huffman_tree != NULL )
1230
1.04k
        {
1231
1.04k
          if( libfwnt_huffman_tree_free(
1232
1.04k
               &aligned_offsets_huffman_tree,
1233
1.04k
               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
1.04k
        }
1245
2.74k
        if( libfwnt_huffman_tree_free(
1246
2.74k
             &lengths_huffman_tree,
1247
2.74k
             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
2.74k
        if( libfwnt_huffman_tree_free(
1259
2.74k
             &main_huffman_tree,
1260
2.74k
             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
2.74k
        break;
1272
1273
2.74k
      case LIBFWNT_LZX_BLOCK_TYPE_UNCOMPRESSED:
1274
/* TODO align byte stream */
1275
1.04k
        if( ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) < 12 )
1276
8
        {
1277
8
          libcerror_error_set(
1278
8
           error,
1279
8
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1280
8
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1281
8
           "%s: invalid compressed data value too small.",
1282
8
           function );
1283
1284
8
          goto on_error;
1285
8
        }
1286
1.04k
        byte_stream_copy_to_uint32_little_endian(
1287
1.04k
         &( compressed_data[ bit_stream->byte_stream_offset ] ),
1288
1.04k
         recent_compression_offsets[ 0 ] );
1289
1290
1.04k
        bit_stream->byte_stream_offset += 4;
1291
1292
1.04k
        byte_stream_copy_to_uint32_little_endian(
1293
1.04k
         &( compressed_data[ bit_stream->byte_stream_offset ] ),
1294
1.04k
         recent_compression_offsets[ 1 ] );
1295
1296
1.04k
        bit_stream->byte_stream_offset += 4;
1297
1298
1.04k
        byte_stream_copy_to_uint32_little_endian(
1299
1.04k
         &( compressed_data[ bit_stream->byte_stream_offset ] ),
1300
1.04k
         recent_compression_offsets[ 2 ] );
1301
1302
1.04k
        bit_stream->byte_stream_offset += 4;
1303
1304
1.04k
        if( recent_compression_offsets[ 0 ] == 0 )
1305
1
        {
1306
1
          libcerror_error_set(
1307
1
           error,
1308
1
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1309
1
           LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1310
1
           "%s: unsupported R0 value.",
1311
1
           function );
1312
1313
1
          goto on_error;
1314
1
        }
1315
1.04k
        if( recent_compression_offsets[ 1 ] == 0 )
1316
1
        {
1317
1
          libcerror_error_set(
1318
1
           error,
1319
1
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1320
1
           LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1321
1
           "%s: unsupported R1 value.",
1322
1
           function );
1323
1324
1
          goto on_error;
1325
1
        }
1326
1.03k
        if( recent_compression_offsets[ 2 ] == 0 )
1327
4
        {
1328
4
          libcerror_error_set(
1329
4
           error,
1330
4
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1331
4
           LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1332
4
           "%s: unsupported R2 value.",
1333
4
           function );
1334
1335
4
          goto on_error;
1336
4
        }
1337
1.03k
        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
1.03k
        if( (size_t) block_size > ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) )
1358
258
        {
1359
258
          block_size = (uint32_t) ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset );
1360
258
        }
1361
1.03k
        if( (size_t) block_size > ( safe_uncompressed_data_size - uncompressed_data_offset ) )
1362
7
        {
1363
7
          libcerror_error_set(
1364
7
           error,
1365
7
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1366
7
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1367
7
           "%s: invalid uncompressed data value too small.",
1368
7
           function );
1369
1370
7
          goto on_error;
1371
7
        }
1372
1.02k
        if( memory_copy(
1373
1.02k
             &( uncompressed_data[ uncompressed_data_offset ] ),
1374
1.02k
             &( compressed_data[ bit_stream->byte_stream_offset ] ),
1375
1.02k
             (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
1.02k
        bit_stream->byte_stream_offset += block_size;
1387
1.02k
        uncompressed_data_offset       += block_size;
1388
1389
        /* Flush the bit-stream buffer
1390
         */
1391
1.02k
        bit_stream->bit_buffer      = 0;
1392
1.02k
        bit_stream->bit_buffer_size = 0;
1393
1394
1.02k
        break;
1395
1396
57
      default:
1397
57
        libcerror_error_set(
1398
57
         error,
1399
57
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1400
57
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1401
57
         "%s: unsupported block type.",
1402
57
         function );
1403
1404
57
        goto on_error;
1405
4.19k
    }
1406
4.19k
  }
1407
366
  if( libfwnt_bit_stream_free(
1408
366
       &bit_stream,
1409
366
       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
366
  if( libfwnt_lzx_decompress_adjust_call_instructions(
1421
366
       uncompressed_data,
1422
366
       uncompressed_data_offset,
1423
366
       error ) != 1 )
1424
113
  {
1425
113
    libcerror_error_set(
1426
113
     error,
1427
113
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1428
113
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1429
113
     "%s: unable to adjust call instructions.",
1430
113
     function );
1431
1432
113
    goto on_error;
1433
113
  }
1434
253
  *uncompressed_data_size = uncompressed_data_offset;
1435
1436
253
  return( 1 );
1437
1438
526
on_error:
1439
526
  if( lengths_huffman_tree != NULL )
1440
124
  {
1441
124
    libfwnt_huffman_tree_free(
1442
124
     &lengths_huffman_tree,
1443
124
     NULL );
1444
124
  }
1445
526
  if( main_huffman_tree != NULL )
1446
331
  {
1447
331
    libfwnt_huffman_tree_free(
1448
331
     &main_huffman_tree,
1449
331
     NULL );
1450
331
  }
1451
526
  if( aligned_offsets_huffman_tree != NULL )
1452
84
  {
1453
84
    libfwnt_huffman_tree_free(
1454
84
     &aligned_offsets_huffman_tree,
1455
84
     NULL );
1456
84
  }
1457
526
  if( bit_stream != NULL )
1458
413
  {
1459
413
    libfwnt_bit_stream_free(
1460
413
     &bit_stream,
1461
413
     NULL );
1462
413
  }
1463
526
  return( -1 );
1464
366
}
1465