Coverage Report

Created: 2025-06-13 07:22

/src/libagdb/libfwnt/libfwnt_lzxpress.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * LZXPRESS (de)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_lzxpress.h"
32
33
/* Compresses data using LZXPRESS (LZ77 + DIRECT2) compression
34
 * Returns 1 on success or -1 on error
35
 */
36
int libfwnt_lzxpress_compress(
37
     const uint8_t *uncompressed_data,
38
     size_t uncompressed_data_size,
39
     uint8_t *compressed_data,
40
     size_t *compressed_data_size,
41
     libcerror_error_t **error )
42
0
{
43
0
  static char *function = "libfwnt_lzxpress_compress";
44
45
0
  if( uncompressed_data == NULL )
46
0
  {
47
0
    libcerror_error_set(
48
0
     error,
49
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
50
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
51
0
     "%s: invalid uncompressed data.",
52
0
     function );
53
54
0
    return( -1 );
55
0
  }
56
0
  if( uncompressed_data_size > (size_t) SSIZE_MAX )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
61
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
62
0
     "%s: invalid uncompressed data size value exceeds maximum.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
0
  if( compressed_data == NULL )
68
0
  {
69
0
    libcerror_error_set(
70
0
     error,
71
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
72
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
73
0
     "%s: invalid compressed data.",
74
0
     function );
75
76
0
    return( -1 );
77
0
  }
78
0
  if( compressed_data_size == NULL )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
83
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
84
0
     "%s: invalid compressed data size.",
85
0
     function );
86
87
0
    return( -1 );
88
0
  }
89
/* TODO implement */
90
0
  return( -1 );
91
0
}
92
93
/* Decompresses data using LZXPRESS (LZ77 + DIRECT2) compression
94
 * Return 1 on success or -1 on error
95
 */
96
int libfwnt_lzxpress_decompress(
97
     const uint8_t *compressed_data,
98
     size_t compressed_data_size,
99
     uint8_t *uncompressed_data,
100
     size_t *uncompressed_data_size,
101
     libcerror_error_t **error )
102
344
{
103
344
  static char *function                  = "libfwnt_lzxpress_decompress";
104
344
  size_t compressed_data_offset          = 0;
105
344
  size_t compression_index               = 0;
106
344
  size_t compression_shared_byte_index   = 0;
107
344
  size_t safe_uncompressed_data_size     = 0;
108
344
  size_t uncompressed_data_offset        = 0;
109
344
  uint32_t compression_indicator         = 0;
110
344
  uint32_t compression_indicator_bitmask = 0;
111
344
  uint16_t compression_tuple             = 0;
112
344
  uint16_t compression_tuple_size        = 0;
113
344
  int16_t compression_tuple_offset       = 0;
114
115
344
  if( compressed_data == NULL )
116
0
  {
117
0
    libcerror_error_set(
118
0
     error,
119
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
120
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
121
0
     "%s: invalid compressed data.",
122
0
     function );
123
124
0
    return( -1 );
125
0
  }
126
344
  if( ( compressed_data_size < 2 )
127
344
   || ( compressed_data_size > (size_t) SSIZE_MAX ) )
128
1
  {
129
1
    libcerror_error_set(
130
1
     error,
131
1
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
132
1
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
133
1
     "%s: invalid compressed data size value out of bounds.",
134
1
     function );
135
136
1
    return( -1 );
137
1
  }
138
343
  if( uncompressed_data == NULL )
139
0
  {
140
0
    libcerror_error_set(
141
0
     error,
142
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
143
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
144
0
     "%s: invalid uncompressed data.",
145
0
     function );
146
147
0
    return( -1 );
148
0
  }
149
343
  if( uncompressed_data_size == NULL )
150
0
  {
151
0
    libcerror_error_set(
152
0
     error,
153
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
154
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
155
0
     "%s: invalid uncompressed data size.",
156
0
     function );
157
158
0
    return( -1 );
159
0
  }
160
343
  if( *uncompressed_data_size > (size_t) SSIZE_MAX )
161
0
  {
162
0
    libcerror_error_set(
163
0
     error,
164
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
165
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
166
0
     "%s: invalid uncompressed data size value exceeds maximum.",
167
0
     function );
168
169
0
    return( -1 );
170
0
  }
171
343
  safe_uncompressed_data_size = *uncompressed_data_size;
172
173
42.7k
  while( compressed_data_offset < compressed_data_size )
174
42.6k
  {
175
42.6k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
176
12
    {
177
12
      break;
178
12
    }
179
42.6k
    if( ( compressed_data_size < 4 )
180
42.6k
     || ( compressed_data_offset > ( compressed_data_size - 4 ) ) )
181
32
    {
182
32
      libcerror_error_set(
183
32
       error,
184
32
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
185
32
       LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
186
32
       "%s: compressed data too small.",
187
32
       function );
188
189
32
      return( -1 );
190
32
    }
191
42.6k
    byte_stream_copy_to_uint32_little_endian(
192
42.6k
     &( compressed_data[ compressed_data_offset ] ),
193
42.6k
     compression_indicator );
194
195
#if defined( HAVE_DEBUG_OUTPUT )
196
    if( libcnotify_verbose != 0 )
197
    {
198
      libcnotify_printf(
199
       "%s: compressed data offset\t\t\t: %" PRIzd " (0x%08" PRIzx ")\n",
200
       function,
201
       compressed_data_offset,
202
       compressed_data_offset );
203
204
      libcnotify_printf(
205
       "%s: compression indicator\t\t\t: 0x%08" PRIx32 "\n",
206
       function,
207
       compression_indicator );
208
209
      libcnotify_printf(
210
       "\n" );
211
    }
212
#endif
213
42.6k
    compressed_data_offset += 4;
214
215
42.6k
    for( compression_indicator_bitmask = 0x80000000UL;
216
1.39M
         compression_indicator_bitmask > 0;
217
1.35M
         compression_indicator_bitmask >>= 1 )
218
1.35M
    {
219
1.35M
      if( uncompressed_data_offset >= safe_uncompressed_data_size )
220
13
      {
221
13
        break;
222
13
      }
223
1.35M
      if( compressed_data_offset >= compressed_data_size )
224
98
      {
225
98
        break;
226
98
      }
227
      /* If the indicator bit is 0 the data is uncompressed
228
       * or 1 if the data is compressed
229
       */
230
1.35M
      if( ( compression_indicator & compression_indicator_bitmask ) != 0 )
231
601k
      {
232
601k
        if( compressed_data_offset > ( compressed_data_size - 2 ) )
233
27
        {
234
27
          libcerror_error_set(
235
27
           error,
236
27
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
237
27
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
238
27
           "%s: compressed data too small.",
239
27
           function );
240
241
27
          return( -1 );
242
27
        }
243
601k
                    byte_stream_copy_to_uint16_little_endian(
244
601k
                     &( compressed_data[ compressed_data_offset ] ),
245
601k
                     compression_tuple );
246
247
601k
        compressed_data_offset += 2;
248
249
        /* The compression tuple contains:
250
         * 0 - 2  the size
251
         * 3 - 15 the offset - 1
252
         */
253
601k
        compression_tuple_size   = ( compression_tuple & 0x0007 );
254
601k
        compression_tuple_offset = ( compression_tuple >> 3 ) + 1;
255
256
        /* Check for a first level extended size
257
         * stored in the 4-bits of a shared extended compression tuple size byte
258
         * the size is added to the previous size
259
         */
260
601k
        if( compression_tuple_size == 0x07 )
261
593k
        {
262
593k
          if( compression_shared_byte_index == 0 )
263
296k
          {
264
296k
            if( compressed_data_offset >= compressed_data_size )
265
4
            {
266
4
              libcerror_error_set(
267
4
               error,
268
4
               LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
269
4
               LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
270
4
               "%s: compressed data too small.",
271
4
               function );
272
273
4
              return( -1 );
274
4
            }
275
296k
            compression_tuple_size += compressed_data[ compressed_data_offset ] & 0x0f;
276
277
296k
            compression_shared_byte_index = compressed_data_offset++;
278
296k
          }
279
296k
          else
280
296k
          {
281
296k
            compression_tuple_size += compressed_data[ compression_shared_byte_index ] >> 4;
282
283
296k
            compression_shared_byte_index = 0;
284
296k
          }
285
593k
        }
286
        /* Check for a second level extended size
287
         * stored in the 8-bits of the next byte
288
         * the size is added to the previous size
289
         */
290
601k
        if( compression_tuple_size == ( 0x07 + 0x0f ) )
291
587k
        {
292
587k
          if( compressed_data_offset >= compressed_data_size )
293
10
          {
294
10
            libcerror_error_set(
295
10
             error,
296
10
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
297
10
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
298
10
             "%s: compressed data too small.",
299
10
             function );
300
301
10
            return( -1 );
302
10
          }
303
587k
          compression_tuple_size += compressed_data[ compressed_data_offset++ ];
304
587k
        }
305
        /* Check for a third level extended size
306
         * stored in the 16-bits of the next two bytes
307
         * the previous size is ignored
308
         */
309
601k
        if( compression_tuple_size == ( 0x07 + 0x0f + 0xff ) )
310
585k
        {
311
585k
          if( compressed_data_offset > ( compressed_data_size - 2 ) )
312
29
          {
313
29
            libcerror_error_set(
314
29
             error,
315
29
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
316
29
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
317
29
             "%s: compressed data too small.",
318
29
             function );
319
320
29
            return( -1 );
321
29
          }
322
585k
                      byte_stream_copy_to_uint16_little_endian(
323
585k
                       &( compressed_data[ compressed_data_offset ] ),
324
585k
                       compression_tuple_size );
325
    
326
585k
          compressed_data_offset += 2;
327
585k
        }
328
        /* The size value is stored as
329
         * size - 3
330
         */
331
601k
        compression_tuple_size += 3;
332
333
#if defined( HAVE_DEBUG_OUTPUT )
334
        if( libcnotify_verbose != 0 )
335
        {
336
          libcnotify_printf(
337
           "%s: compressed data offset\t\t\t: %" PRIzd " (0x%08" PRIzx ")\n",
338
           function,
339
           compressed_data_offset,
340
           compressed_data_offset );
341
342
          libcnotify_printf(
343
           "%s: compression tuple offset\t\t\t: %" PRIi16 "\n",
344
           function,
345
           compression_tuple_offset );
346
347
          libcnotify_printf(
348
           "%s: compression tuple size\t\t\t: %" PRIu16 "\n",
349
           function,
350
           compression_tuple_size );
351
352
          libcnotify_printf(
353
           "%s: uncompressed data offset\t\t\t: %" PRIzd " (0x%08" PRIzx ")\n",
354
           function,
355
           uncompressed_data_offset,
356
           uncompressed_data_offset );
357
358
          libcnotify_printf(
359
           "\n" );
360
        }
361
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
362
363
601k
        if( compression_tuple_size > 32771 )
364
18
        {
365
18
          libcerror_error_set(
366
18
           error,
367
18
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
368
18
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
369
18
           "%s: compression tuple size value out of bounds.",
370
18
           function );
371
372
18
          return( -1 );
373
18
        }
374
600k
        compression_index = uncompressed_data_offset - compression_tuple_offset;
375
376
6.47M
        while( compression_tuple_size > 0 )
377
5.87M
        {
378
5.87M
          if( compression_index >= uncompressed_data_offset )
379
88
          {
380
88
            libcerror_error_set(
381
88
             error,
382
88
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
383
88
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
384
88
             "%s: invalid compressed data at offset: %" PRIzd " - compression index: %" PRIzd " out of range: %" PRIzd ".",
385
88
             function,
386
88
             compressed_data_offset,
387
88
             compression_index,
388
88
             uncompressed_data_offset );
389
390
88
            return( -1 );
391
88
          }
392
5.87M
          if( uncompressed_data_offset >= safe_uncompressed_data_size )
393
10
          {
394
10
            libcerror_error_set(
395
10
             error,
396
10
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
397
10
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
398
10
             "%s: uncompressed data too small.",
399
10
             function );
400
401
10
            return( -1 );
402
10
          }
403
5.87M
          uncompressed_data[ uncompressed_data_offset++ ] = uncompressed_data[ compression_index++ ];
404
405
5.87M
          compression_tuple_size--;
406
5.87M
        }
407
600k
      }
408
755k
      else
409
755k
      {
410
755k
        if( compressed_data_offset >= compressed_data_size )
411
0
        {
412
0
          libcerror_error_set(
413
0
           error,
414
0
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
415
0
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
416
0
           "%s: compressed data too small.",
417
0
           function );
418
419
0
          return( -1 );
420
0
        }
421
755k
        if( uncompressed_data_offset > safe_uncompressed_data_size )
422
0
        {
423
0
          libcerror_error_set(
424
0
           error,
425
0
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
426
0
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
427
0
           "%s: uncompressed data too small.",
428
0
           function );
429
430
0
          return( -1 );
431
0
        }
432
755k
        uncompressed_data[ uncompressed_data_offset++ ] = compressed_data[ compressed_data_offset++ ];
433
755k
      }
434
1.35M
    }
435
42.6k
  }
436
125
  *uncompressed_data_size = uncompressed_data_offset;
437
438
125
  return( 1 );
439
343
}
440
441
/* Decompresses a LZXPRESS Huffman compressed chunk
442
 * Return 1 on success or -1 on error
443
 */
444
int libfwnt_lzxpress_huffman_decompress_chunk(
445
     libfwnt_bit_stream_t *bit_stream,
446
     uint8_t *uncompressed_data,
447
     size_t uncompressed_data_size,
448
     size_t *uncompressed_data_offset,
449
     libcerror_error_t **error )
450
6.92k
{
451
6.92k
  uint8_t code_size_array[ 512 ];
452
453
6.92k
  libfwnt_huffman_tree_t *huffman_tree       = NULL;
454
6.92k
  static char *function                      = "libfwnt_lzxpress_huffman_decompress_chunk";
455
6.92k
  size_t next_chunk_uncompressed_data_offset = 0;
456
6.92k
  size_t safe_uncompressed_data_offset       = 0;
457
6.92k
  uint32_t compression_offset                = 0;
458
6.92k
  uint32_t compression_size                  = 0;
459
6.92k
  uint32_t symbol                            = 0;
460
6.92k
  uint8_t byte_value                         = 0;
461
462
6.92k
  if( bit_stream == NULL )
463
0
  {
464
0
    libcerror_error_set(
465
0
     error,
466
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
467
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
468
0
     "%s: invalid bit stream.",
469
0
     function );
470
471
0
    return( -1 );
472
0
  }
473
6.92k
  if( ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) < 260 )
474
244
  {
475
244
    libcerror_error_set(
476
244
     error,
477
244
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
478
244
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
479
244
     "%s: invalid bit stream - byte stream value too small.",
480
244
     function );
481
482
244
    return( -1 );
483
244
  }
484
6.68k
  if( uncompressed_data == NULL )
485
0
  {
486
0
    libcerror_error_set(
487
0
     error,
488
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
489
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
490
0
     "%s: invalid uncompressed data.",
491
0
     function );
492
493
0
    return( -1 );
494
0
  }
495
6.68k
  if( uncompressed_data_size > (size_t) SSIZE_MAX )
496
0
  {
497
0
    libcerror_error_set(
498
0
     error,
499
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
500
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
501
0
     "%s: invalid uncompressed data size value exceeds maximum.",
502
0
     function );
503
504
0
    return( -1 );
505
0
  }
506
6.68k
  if( uncompressed_data_offset == NULL )
507
0
  {
508
0
    libcerror_error_set(
509
0
     error,
510
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
511
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
512
0
     "%s: invalid uncompressed data offset.",
513
0
     function );
514
515
0
    return( -1 );
516
0
  }
517
6.68k
  safe_uncompressed_data_offset = *uncompressed_data_offset;
518
519
6.68k
  if( safe_uncompressed_data_offset >= uncompressed_data_size )
520
0
  {
521
0
    libcerror_error_set(
522
0
     error,
523
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
524
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
525
0
     "%s: uncompressed data offset value out of bounds.",
526
0
     function );
527
528
0
    return( -1 );
529
0
  }
530
  /* The table contains 4-bits code size per symbol
531
   */
532
1.71M
  while( symbol < 512 )
533
1.71M
  {
534
1.71M
    byte_value = bit_stream->byte_stream[ bit_stream->byte_stream_offset ];
535
536
1.71M
    code_size_array[ symbol++ ] = byte_value & 0x0f;
537
538
1.71M
    byte_value >>= 4;
539
540
1.71M
    code_size_array[ symbol++ ] = byte_value & 0x0f;
541
542
1.71M
    bit_stream->byte_stream_offset += 1;
543
1.71M
  }
544
6.68k
  if( libfwnt_huffman_tree_initialize(
545
6.68k
       &huffman_tree,
546
6.68k
       512,
547
6.68k
       15,
548
6.68k
       error ) != 1 )
549
0
  {
550
0
    libcerror_error_set(
551
0
     error,
552
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
553
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
554
0
     "%s: unable to create Huffman tree.",
555
0
     function );
556
557
0
    goto on_error;
558
0
  }
559
6.68k
  if( libfwnt_huffman_tree_build(
560
6.68k
       huffman_tree,
561
6.68k
       code_size_array,
562
6.68k
       512,
563
6.68k
       error ) != 1 )
564
91
  {
565
91
    libcerror_error_set(
566
91
     error,
567
91
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
568
91
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
569
91
     "%s: unable to build Huffman tree.",
570
91
     function );
571
572
91
    goto on_error;
573
91
  }
574
6.59k
  if( libfwnt_bit_stream_read(
575
6.59k
       bit_stream,
576
6.59k
       32,
577
6.59k
       error ) == -1 )
578
0
  {
579
0
    libcerror_error_set(
580
0
     error,
581
0
     LIBCERROR_ERROR_DOMAIN_IO,
582
0
     LIBCERROR_IO_ERROR_READ_FAILED,
583
0
     "%s: unable to read 32-bit from bit stream.",
584
0
     function );
585
586
0
    goto on_error;
587
0
  }
588
6.59k
  next_chunk_uncompressed_data_offset = safe_uncompressed_data_offset + 65536;
589
590
6.59k
  if( next_chunk_uncompressed_data_offset > uncompressed_data_size )
591
161
  {
592
161
    next_chunk_uncompressed_data_offset = uncompressed_data_size;
593
161
  }
594
19.6M
        while( ( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
595
19.6M
            || ( bit_stream->bit_buffer_size > 0 ) )
596
19.6M
  {
597
19.6M
    if( safe_uncompressed_data_offset >= next_chunk_uncompressed_data_offset )
598
5.95k
    {
599
#if defined( HAVE_DEBUG_OUTPUT )
600
      if( libcnotify_verbose != 0 )
601
      {
602
        libcnotify_printf(
603
         "%s: end of chunk at compressed data offset: %" PRIzd " (0x%08" PRIzx "), uncompressed data offset: %" PRIzd " (0x%08" PRIzx ")\n",
604
         function,
605
         bit_stream->byte_stream_offset,
606
         bit_stream->byte_stream_offset,
607
         safe_uncompressed_data_offset,
608
         safe_uncompressed_data_offset );
609
610
        libcnotify_printf(
611
         "\n" );
612
      }
613
#endif
614
5.95k
      bit_stream->bit_buffer_size = 0;
615
616
5.95k
      break;
617
5.95k
    }
618
#if defined( HAVE_DEBUG_OUTPUT )
619
    if( libcnotify_verbose != 0 )
620
    {
621
      libcnotify_printf(
622
       "%s: compressed data offset\t: %" PRIzd " (0x%08" PRIzx ")\n",
623
       function,
624
       bit_stream->byte_stream_offset,
625
       bit_stream->byte_stream_offset );
626
    }
627
#endif
628
19.6M
    if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
629
19.6M
         huffman_tree,
630
19.6M
         bit_stream,
631
19.6M
         &symbol,
632
19.6M
         error ) != 1 )
633
77
    {
634
77
      libcerror_error_set(
635
77
       error,
636
77
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
637
77
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
638
77
       "%s: unable to read symbol.",
639
77
       function );
640
641
77
      goto on_error;
642
77
    }
643
#if defined( HAVE_DEBUG_OUTPUT )
644
    if( libcnotify_verbose != 0 )
645
    {
646
      libcnotify_printf(
647
       "%s: huffman symbol\t\t: 0x%04" PRIx16 "\n",
648
       function,
649
       symbol );
650
    }
651
#endif
652
19.6M
    if( symbol < 256 )
653
12.9M
    {
654
12.9M
      uncompressed_data[ safe_uncompressed_data_offset++ ] = (uint8_t) symbol;
655
12.9M
    }
656
    /* Make sure the bit buffer contains at least 16-bit to ensure end-of-block marker is read correctly
657
     */
658
19.6M
    if( bit_stream->bit_buffer_size < 16 )
659
6.30M
    {
660
6.30M
      if( libfwnt_bit_stream_read(
661
6.30M
           bit_stream,
662
6.30M
           16,
663
6.30M
           error ) == -1 )
664
0
      {
665
0
        libcerror_error_set(
666
0
         error,
667
0
         LIBCERROR_ERROR_DOMAIN_IO,
668
0
         LIBCERROR_IO_ERROR_READ_FAILED,
669
0
         "%s: unable to read 16-bit from bit stream.",
670
0
         function );
671
672
0
        goto on_error;
673
0
      }
674
6.30M
    }
675
#if defined( HAVE_DEBUG_OUTPUT )
676
    if( libcnotify_verbose != 0 )
677
    {
678
      libcnotify_printf(
679
       "%s: number of bits\t\t: %" PRId8 "\n",
680
       function,
681
       bit_stream->bit_buffer_size );
682
    }
683
#endif
684
    /* Check if we have an end-of-block marker (symbol 256) and the number of remaining bits are 0
685
     */
686
/* TODO add ( symbol == 256 ) */
687
19.6M
    if( ( bit_stream->bit_buffer == 0 )
688
19.6M
     && ( safe_uncompressed_data_offset >= uncompressed_data_size ) )
689
173
    {
690
173
      break;
691
173
    }
692
19.6M
    if( symbol >= 256 )
693
6.69M
    {
694
6.69M
      symbol            -= 256;
695
6.69M
      compression_offset = 0;
696
6.69M
      compression_size   = symbol & 0x000f;
697
6.69M
      symbol           >>= 4;
698
699
6.69M
      if( symbol != 0 )
700
6.28M
      {
701
6.28M
        if( libfwnt_bit_stream_get_value(
702
6.28M
             bit_stream,
703
6.28M
             (uint8_t) symbol,
704
6.28M
             &compression_offset,
705
6.28M
             error ) != 1 )
706
0
        {
707
0
          libcerror_error_set(
708
0
           error,
709
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
710
0
           LIBCERROR_RUNTIME_ERROR_GET_FAILED,
711
0
           "%s: unable to retrieve compression offset from bit stream.",
712
0
           function );
713
714
0
          goto on_error;
715
0
        }
716
#if defined( HAVE_DEBUG_OUTPUT )
717
        if( libcnotify_verbose != 0 )
718
        {
719
          libcnotify_printf(
720
           "%s: compression offset\t\t: %" PRIu32 "\n",
721
           function,
722
           compression_offset );
723
        }
724
#endif
725
6.28M
      }
726
6.69M
      compression_offset = (uint32_t) ( ( 1 << symbol ) | compression_offset );
727
728
#if defined( HAVE_DEBUG_OUTPUT )
729
      if( libcnotify_verbose != 0 )
730
      {
731
        libcnotify_printf(
732
         "%s: compression size\t\t: %" PRIu32 "\n",
733
         function,
734
         compression_size );
735
      }
736
#endif
737
      /* Ignore any data beyond the uncompressed block size
738
       */
739
6.69M
      if( compression_size == 15 )
740
274k
      {
741
274k
        if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 1 ) )
742
112
        {
743
112
          libcerror_error_set(
744
112
           error,
745
112
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
746
112
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
747
112
           "%s: compressed data size value too small.",
748
112
           function );
749
750
112
          goto on_error;
751
112
        }
752
274k
        compression_size = bit_stream->byte_stream[ bit_stream->byte_stream_offset ] + 15;
753
754
#if defined( HAVE_DEBUG_OUTPUT )
755
        if( libcnotify_verbose != 0 )
756
        {
757
          libcnotify_printf(
758
           "%s: extended compression offset\t: %" PRIzd " (0x%08" PRIzx ")\n",
759
           function,
760
           bit_stream->byte_stream_offset,
761
           bit_stream->byte_stream_offset );
762
763
          libcnotify_printf(
764
           "%s: extended compression size\t: %" PRIu32 "\n",
765
           function,
766
           compression_size );
767
        }
768
#endif
769
274k
        bit_stream->byte_stream_offset += 1;
770
771
274k
        if( compression_size == 270 )
772
8.38k
        {
773
8.38k
          if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 2 ) )
774
29
          {
775
29
            libcerror_error_set(
776
29
             error,
777
29
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
778
29
             LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
779
29
             "%s: compressed data size value too small.",
780
29
             function );
781
782
29
            goto on_error;
783
29
          }
784
8.35k
          byte_stream_copy_to_uint16_little_endian(
785
8.35k
           &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
786
8.35k
           compression_size );
787
788
#if defined( HAVE_DEBUG_OUTPUT )
789
          if( libcnotify_verbose != 0 )
790
          {
791
            libcnotify_printf(
792
             "%s: extended compression offset\t: %" PRIzd " (0x%08" PRIzx ")\n",
793
             function,
794
             bit_stream->byte_stream_offset,
795
             bit_stream->byte_stream_offset );
796
797
            libcnotify_printf(
798
             "%s: extended compression size\t: %" PRIu32 "\n",
799
             function,
800
             compression_size );
801
          }
802
#endif
803
8.35k
          bit_stream->byte_stream_offset += 2;
804
805
8.35k
          if( compression_size == 0 )
806
2.12k
          {
807
2.12k
            if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 4 ) )
808
25
            {
809
25
              libcerror_error_set(
810
25
               error,
811
25
               LIBCERROR_ERROR_DOMAIN_RUNTIME,
812
25
               LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
813
25
               "%s: compressed data size value too small.",
814
25
               function );
815
816
25
              goto on_error;
817
25
            }
818
2.09k
            byte_stream_copy_to_uint32_little_endian(
819
2.09k
             &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
820
2.09k
             compression_size );
821
822
#if defined( HAVE_DEBUG_OUTPUT )
823
            if( libcnotify_verbose != 0 )
824
            {
825
              libcnotify_printf(
826
               "%s: extended compression offset\t: %" PRIzd " (0x%08" PRIzx ")\n",
827
               function,
828
               bit_stream->byte_stream_offset,
829
               bit_stream->byte_stream_offset );
830
831
              libcnotify_printf(
832
               "%s: extended compression size\t: %" PRIu32 "\n",
833
               function,
834
               compression_size );
835
            }
836
#endif
837
2.09k
            bit_stream->byte_stream_offset += 4;
838
839
2.09k
          }
840
8.35k
        }
841
274k
      }
842
6.69M
      compression_size += 3;
843
844
#if defined( HAVE_DEBUG_OUTPUT )
845
      if( libcnotify_verbose != 0 )
846
      {
847
        libcnotify_printf(
848
         "%s: compression offset\t\t: %" PRIu32 "\n",
849
         function,
850
         compression_offset );
851
852
        libcnotify_printf(
853
         "%s: compression size\t\t: %" PRIu32 "\n",
854
         function,
855
         compression_size );
856
857
        libcnotify_printf(
858
         "%s: uncompressed data offset\t: %" PRIzd " (0x%08" PRIzx ")\n",
859
         function,
860
         safe_uncompressed_data_offset,
861
         safe_uncompressed_data_offset );
862
      }
863
#endif
864
6.69M
      if( compression_offset > safe_uncompressed_data_offset )
865
103
      {
866
103
        libcerror_error_set(
867
103
         error,
868
103
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
869
103
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
870
103
         "%s: compression offset value out of bounds.",
871
103
         function );
872
873
103
        goto on_error;
874
103
      }
875
6.69M
      if( compression_size > ( uncompressed_data_size - safe_uncompressed_data_offset ) )
876
117
      {
877
117
        libcerror_error_set(
878
117
         error,
879
117
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
880
117
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
881
117
         "%s: compression size value out of bounds.",
882
117
         function );
883
884
117
        goto on_error;
885
117
      }
886
6.69M
      compression_offset = safe_uncompressed_data_offset - compression_offset;
887
888
1.39G
      while( compression_size > 0 )
889
1.38G
      {
890
1.38G
        uncompressed_data[ safe_uncompressed_data_offset++ ] = uncompressed_data[ compression_offset++ ];
891
892
1.38G
        compression_size--;
893
1.38G
      }
894
      /* Make sure the bit buffer contains at least 16-bit to ensure successive chunks in a stream are read correctly
895
       */
896
6.69M
      if( bit_stream->bit_buffer_size < 16 )
897
2.08M
      {
898
2.08M
        if( libfwnt_bit_stream_read(
899
2.08M
             bit_stream,
900
2.08M
             16,
901
2.08M
             error ) == -1 )
902
0
        {
903
0
          libcerror_error_set(
904
0
           error,
905
0
           LIBCERROR_ERROR_DOMAIN_IO,
906
0
           LIBCERROR_IO_ERROR_READ_FAILED,
907
0
           "%s: unable to read 16-bit from bit stream.",
908
0
           function );
909
910
0
          goto on_error;
911
0
        }
912
2.08M
      }
913
6.69M
    }
914
#if defined( HAVE_DEBUG_OUTPUT )
915
    if( libcnotify_verbose != 0 )
916
    {
917
      libcnotify_printf(
918
       "\n" );
919
    }
920
#endif
921
19.6M
  }
922
6.12k
  if( libfwnt_huffman_tree_free(
923
6.12k
       &huffman_tree,
924
6.12k
       error ) != 1 )
925
0
  {
926
0
    libcerror_error_set(
927
0
     error,
928
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
929
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
930
0
     "%s: unable to free Huffman tree.",
931
0
     function );
932
933
0
    goto on_error;
934
0
  }
935
6.12k
  *uncompressed_data_offset = safe_uncompressed_data_offset;
936
937
6.12k
  return( 1 );
938
939
554
on_error:
940
554
  if( huffman_tree != NULL )
941
554
  {
942
554
    libfwnt_huffman_tree_free(
943
554
     &huffman_tree,
944
554
     NULL );
945
554
  }
946
554
  return( -1 );
947
6.12k
}
948
949
/* Decompresses data using LZXPRESS Huffman compression
950
 * Return 1 on success or -1 on error
951
 */
952
int libfwnt_lzxpress_huffman_decompress(
953
     const uint8_t *compressed_data,
954
     size_t compressed_data_size,
955
     uint8_t *uncompressed_data,
956
     size_t *uncompressed_data_size,
957
     libcerror_error_t **error )
958
1.59k
{
959
1.59k
  libfwnt_bit_stream_t *bit_stream   = NULL;
960
1.59k
  static char *function              = "libfwnt_lzxpress_huffman_decompress";
961
1.59k
  size_t safe_uncompressed_data_size = 0;
962
1.59k
  size_t uncompressed_data_offset    = 0;
963
964
1.59k
  if( uncompressed_data_size == NULL )
965
0
  {
966
0
    libcerror_error_set(
967
0
     error,
968
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
969
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
970
0
     "%s: invalid uncompressed data size.",
971
0
     function );
972
973
0
    return( -1 );
974
0
  }
975
1.59k
  if( libfwnt_bit_stream_initialize(
976
1.59k
       &bit_stream,
977
1.59k
       compressed_data,
978
1.59k
       compressed_data_size,
979
1.59k
       error ) != 1 )
980
0
  {
981
0
    libcerror_error_set(
982
0
     error,
983
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
984
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
985
0
     "%s: unable to create bit stream.",
986
0
     function );
987
988
0
    goto on_error;
989
0
  }
990
1.59k
  safe_uncompressed_data_size = *uncompressed_data_size;
991
992
7.72k
  while( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
993
7.34k
  {
994
7.34k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
995
423
    {
996
423
      break;
997
423
    }
998
6.92k
    if( libfwnt_lzxpress_huffman_decompress_chunk(
999
6.92k
         bit_stream,
1000
6.92k
         uncompressed_data,
1001
6.92k
         safe_uncompressed_data_size,
1002
6.92k
         &uncompressed_data_offset,
1003
6.92k
         error ) != 1 )
1004
798
    {
1005
798
      libcerror_error_set(
1006
798
       error,
1007
798
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
1008
798
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
1009
798
       "%s: unable to decompress chunk.",
1010
798
       function );
1011
1012
798
      goto on_error;
1013
798
    }
1014
6.92k
  }
1015
797
  if( libfwnt_bit_stream_free(
1016
797
       &bit_stream,
1017
797
       error ) != 1 )
1018
0
  {
1019
0
    libcerror_error_set(
1020
0
     error,
1021
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1022
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1023
0
     "%s: unable to free bit stream.",
1024
0
     function );
1025
1026
0
    goto on_error;
1027
0
  }
1028
797
  *uncompressed_data_size = uncompressed_data_offset;
1029
1030
797
  return( 1 );
1031
1032
798
on_error:
1033
798
  if( bit_stream != NULL )
1034
798
  {
1035
798
    libfwnt_bit_stream_free(
1036
798
     &bit_stream,
1037
798
     NULL );
1038
798
  }
1039
798
  return( -1 );
1040
797
}
1041