Coverage Report

Created: 2025-06-22 07:35

/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
346
{
103
346
  static char *function                  = "libfwnt_lzxpress_decompress";
104
346
  size_t compressed_data_offset          = 0;
105
346
  size_t compression_index               = 0;
106
346
  size_t compression_shared_byte_index   = 0;
107
346
  size_t safe_uncompressed_data_size     = 0;
108
346
  size_t uncompressed_data_offset        = 0;
109
346
  uint32_t compression_indicator         = 0;
110
346
  uint32_t compression_indicator_bitmask = 0;
111
346
  uint16_t compression_tuple             = 0;
112
346
  uint16_t compression_tuple_size        = 0;
113
346
  int16_t compression_tuple_offset       = 0;
114
115
346
  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
346
  if( ( compressed_data_size < 2 )
127
346
   || ( 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
345
  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
345
  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
345
  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
345
  safe_uncompressed_data_size = *uncompressed_data_size;
172
173
46.2k
  while( compressed_data_offset < compressed_data_size )
174
46.0k
  {
175
46.0k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
176
10
    {
177
10
      break;
178
10
    }
179
46.0k
    if( ( compressed_data_size < 4 )
180
46.0k
     || ( 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
46.0k
    byte_stream_copy_to_uint32_little_endian(
192
46.0k
     &( compressed_data[ compressed_data_offset ] ),
193
46.0k
     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
46.0k
    compressed_data_offset += 4;
214
215
46.0k
    for( compression_indicator_bitmask = 0x80000000UL;
216
1.51M
         compression_indicator_bitmask > 0;
217
1.46M
         compression_indicator_bitmask >>= 1 )
218
1.46M
    {
219
1.46M
      if( uncompressed_data_offset >= safe_uncompressed_data_size )
220
11
      {
221
11
        break;
222
11
      }
223
1.46M
      if( compressed_data_offset >= compressed_data_size )
224
100
      {
225
100
        break;
226
100
      }
227
      /* If the indicator bit is 0 the data is uncompressed
228
       * or 1 if the data is compressed
229
       */
230
1.46M
      if( ( compression_indicator & compression_indicator_bitmask ) != 0 )
231
643k
      {
232
643k
        if( compressed_data_offset > ( compressed_data_size - 2 ) )
233
23
        {
234
23
          libcerror_error_set(
235
23
           error,
236
23
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
237
23
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
238
23
           "%s: compressed data too small.",
239
23
           function );
240
241
23
          return( -1 );
242
23
        }
243
643k
                    byte_stream_copy_to_uint16_little_endian(
244
643k
                     &( compressed_data[ compressed_data_offset ] ),
245
643k
                     compression_tuple );
246
247
643k
        compressed_data_offset += 2;
248
249
        /* The compression tuple contains:
250
         * 0 - 2  the size
251
         * 3 - 15 the offset - 1
252
         */
253
643k
        compression_tuple_size   = ( compression_tuple & 0x0007 );
254
643k
        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
643k
        if( compression_tuple_size == 0x07 )
261
630k
        {
262
630k
          if( compression_shared_byte_index == 0 )
263
315k
          {
264
315k
            if( compressed_data_offset >= compressed_data_size )
265
2
            {
266
2
              libcerror_error_set(
267
2
               error,
268
2
               LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
269
2
               LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
270
2
               "%s: compressed data too small.",
271
2
               function );
272
273
2
              return( -1 );
274
2
            }
275
315k
            compression_tuple_size += compressed_data[ compressed_data_offset ] & 0x0f;
276
277
315k
            compression_shared_byte_index = compressed_data_offset++;
278
315k
          }
279
315k
          else
280
315k
          {
281
315k
            compression_tuple_size += compressed_data[ compression_shared_byte_index ] >> 4;
282
283
315k
            compression_shared_byte_index = 0;
284
315k
          }
285
630k
        }
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
643k
        if( compression_tuple_size == ( 0x07 + 0x0f ) )
291
624k
        {
292
624k
          if( compressed_data_offset >= compressed_data_size )
293
11
          {
294
11
            libcerror_error_set(
295
11
             error,
296
11
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
297
11
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
298
11
             "%s: compressed data too small.",
299
11
             function );
300
301
11
            return( -1 );
302
11
          }
303
624k
          compression_tuple_size += compressed_data[ compressed_data_offset++ ];
304
624k
        }
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
643k
        if( compression_tuple_size == ( 0x07 + 0x0f + 0xff ) )
310
623k
        {
311
623k
          if( compressed_data_offset > ( compressed_data_size - 2 ) )
312
30
          {
313
30
            libcerror_error_set(
314
30
             error,
315
30
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
316
30
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
317
30
             "%s: compressed data too small.",
318
30
             function );
319
320
30
            return( -1 );
321
30
          }
322
623k
                      byte_stream_copy_to_uint16_little_endian(
323
623k
                       &( compressed_data[ compressed_data_offset ] ),
324
623k
                       compression_tuple_size );
325
    
326
623k
          compressed_data_offset += 2;
327
623k
        }
328
        /* The size value is stored as
329
         * size - 3
330
         */
331
643k
        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
643k
        if( compression_tuple_size > 32771 )
364
17
        {
365
17
          libcerror_error_set(
366
17
           error,
367
17
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
368
17
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
369
17
           "%s: compression tuple size value out of bounds.",
370
17
           function );
371
372
17
          return( -1 );
373
17
        }
374
643k
        compression_index = uncompressed_data_offset - compression_tuple_offset;
375
376
6.20M
        while( compression_tuple_size > 0 )
377
5.56M
        {
378
5.56M
          if( compression_index >= uncompressed_data_offset )
379
94
          {
380
94
            libcerror_error_set(
381
94
             error,
382
94
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
383
94
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
384
94
             "%s: invalid compressed data at offset: %" PRIzd " - compression index: %" PRIzd " out of range: %" PRIzd ".",
385
94
             function,
386
94
             compressed_data_offset,
387
94
             compression_index,
388
94
             uncompressed_data_offset );
389
390
94
            return( -1 );
391
94
          }
392
5.56M
          if( uncompressed_data_offset >= safe_uncompressed_data_size )
393
12
          {
394
12
            libcerror_error_set(
395
12
             error,
396
12
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
397
12
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
398
12
             "%s: uncompressed data too small.",
399
12
             function );
400
401
12
            return( -1 );
402
12
          }
403
5.56M
          uncompressed_data[ uncompressed_data_offset++ ] = uncompressed_data[ compression_index++ ];
404
405
5.56M
          compression_tuple_size--;
406
5.56M
        }
407
643k
      }
408
822k
      else
409
822k
      {
410
822k
        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
822k
        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
822k
        uncompressed_data[ uncompressed_data_offset++ ] = compressed_data[ compressed_data_offset++ ];
433
822k
      }
434
1.46M
    }
435
46.0k
  }
436
124
  *uncompressed_data_size = uncompressed_data_offset;
437
438
124
  return( 1 );
439
345
}
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.84k
{
451
6.84k
  uint8_t code_size_array[ 512 ];
452
453
6.84k
  libfwnt_huffman_tree_t *huffman_tree       = NULL;
454
6.84k
  static char *function                      = "libfwnt_lzxpress_huffman_decompress_chunk";
455
6.84k
  size_t next_chunk_uncompressed_data_offset = 0;
456
6.84k
  size_t safe_uncompressed_data_offset       = 0;
457
6.84k
  uint32_t compression_offset                = 0;
458
6.84k
  uint32_t compression_size                  = 0;
459
6.84k
  uint32_t symbol                            = 0;
460
6.84k
  uint8_t byte_value                         = 0;
461
462
6.84k
  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.84k
  if( ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) < 260 )
474
240
  {
475
240
    libcerror_error_set(
476
240
     error,
477
240
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
478
240
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
479
240
     "%s: invalid bit stream - byte stream value too small.",
480
240
     function );
481
482
240
    return( -1 );
483
240
  }
484
6.60k
  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.60k
  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.60k
  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.60k
  safe_uncompressed_data_offset = *uncompressed_data_offset;
518
519
6.60k
  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.69M
  while( symbol < 512 )
533
1.69M
  {
534
1.69M
    byte_value = bit_stream->byte_stream[ bit_stream->byte_stream_offset ];
535
536
1.69M
    code_size_array[ symbol++ ] = byte_value & 0x0f;
537
538
1.69M
    byte_value >>= 4;
539
540
1.69M
    code_size_array[ symbol++ ] = byte_value & 0x0f;
541
542
1.69M
    bit_stream->byte_stream_offset += 1;
543
1.69M
  }
544
6.60k
  if( libfwnt_huffman_tree_initialize(
545
6.60k
       &huffman_tree,
546
6.60k
       512,
547
6.60k
       15,
548
6.60k
       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.60k
  if( libfwnt_huffman_tree_build(
560
6.60k
       huffman_tree,
561
6.60k
       code_size_array,
562
6.60k
       512,
563
6.60k
       error ) != 1 )
564
93
  {
565
93
    libcerror_error_set(
566
93
     error,
567
93
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
568
93
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
569
93
     "%s: unable to build Huffman tree.",
570
93
     function );
571
572
93
    goto on_error;
573
93
  }
574
6.51k
  if( libfwnt_bit_stream_read(
575
6.51k
       bit_stream,
576
6.51k
       32,
577
6.51k
       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.51k
  next_chunk_uncompressed_data_offset = safe_uncompressed_data_offset + 65536;
589
590
6.51k
  if( next_chunk_uncompressed_data_offset > uncompressed_data_size )
591
158
  {
592
158
    next_chunk_uncompressed_data_offset = uncompressed_data_size;
593
158
  }
594
19.7M
        while( ( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
595
19.7M
            || ( bit_stream->bit_buffer_size > 0 ) )
596
19.7M
  {
597
19.7M
    if( safe_uncompressed_data_offset >= next_chunk_uncompressed_data_offset )
598
5.88k
    {
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.88k
      bit_stream->bit_buffer_size = 0;
615
616
5.88k
      break;
617
5.88k
    }
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.7M
    if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
629
19.7M
         huffman_tree,
630
19.7M
         bit_stream,
631
19.7M
         &symbol,
632
19.7M
         error ) != 1 )
633
76
    {
634
76
      libcerror_error_set(
635
76
       error,
636
76
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
637
76
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
638
76
       "%s: unable to read symbol.",
639
76
       function );
640
641
76
      goto on_error;
642
76
    }
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.7M
    if( symbol < 256 )
653
13.1M
    {
654
13.1M
      uncompressed_data[ safe_uncompressed_data_offset++ ] = (uint8_t) symbol;
655
13.1M
    }
656
    /* Make sure the bit buffer contains at least 16-bit to ensure end-of-block marker is read correctly
657
     */
658
19.7M
    if( bit_stream->bit_buffer_size < 16 )
659
6.42M
    {
660
6.42M
      if( libfwnt_bit_stream_read(
661
6.42M
           bit_stream,
662
6.42M
           16,
663
6.42M
           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.42M
    }
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.7M
    if( ( bit_stream->bit_buffer == 0 )
688
19.7M
     && ( safe_uncompressed_data_offset >= uncompressed_data_size ) )
689
172
    {
690
172
      break;
691
172
    }
692
19.7M
    if( symbol >= 256 )
693
6.63M
    {
694
6.63M
      symbol            -= 256;
695
6.63M
      compression_offset = 0;
696
6.63M
      compression_size   = symbol & 0x000f;
697
6.63M
      symbol           >>= 4;
698
699
6.63M
      if( symbol != 0 )
700
6.22M
      {
701
6.22M
        if( libfwnt_bit_stream_get_value(
702
6.22M
             bit_stream,
703
6.22M
             (uint8_t) symbol,
704
6.22M
             &compression_offset,
705
6.22M
             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.22M
      }
726
6.63M
      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.63M
      if( compression_size == 15 )
740
275k
      {
741
275k
        if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 1 ) )
742
116
        {
743
116
          libcerror_error_set(
744
116
           error,
745
116
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
746
116
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
747
116
           "%s: compressed data size value too small.",
748
116
           function );
749
750
116
          goto on_error;
751
116
        }
752
275k
        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
275k
        bit_stream->byte_stream_offset += 1;
770
771
275k
        if( compression_size == 270 )
772
8.33k
        {
773
8.33k
          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.30k
          byte_stream_copy_to_uint16_little_endian(
785
8.30k
           &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
786
8.30k
           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.30k
          bit_stream->byte_stream_offset += 2;
804
805
8.30k
          if( compression_size == 0 )
806
2.15k
          {
807
2.15k
            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.12k
            byte_stream_copy_to_uint32_little_endian(
819
2.12k
             &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
820
2.12k
             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.12k
            bit_stream->byte_stream_offset += 4;
838
839
2.12k
          }
840
8.30k
        }
841
275k
      }
842
6.63M
      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.63M
      if( compression_offset > safe_uncompressed_data_offset )
865
97
      {
866
97
        libcerror_error_set(
867
97
         error,
868
97
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
869
97
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
870
97
         "%s: compression offset value out of bounds.",
871
97
         function );
872
873
97
        goto on_error;
874
97
      }
875
6.63M
      if( compression_size > ( uncompressed_data_size - safe_uncompressed_data_offset ) )
876
114
      {
877
114
        libcerror_error_set(
878
114
         error,
879
114
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
880
114
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
881
114
         "%s: compression size value out of bounds.",
882
114
         function );
883
884
114
        goto on_error;
885
114
      }
886
6.63M
      compression_offset = safe_uncompressed_data_offset - compression_offset;
887
888
1.37G
      while( compression_size > 0 )
889
1.37G
      {
890
1.37G
        uncompressed_data[ safe_uncompressed_data_offset++ ] = uncompressed_data[ compression_offset++ ];
891
892
1.37G
        compression_size--;
893
1.37G
      }
894
      /* Make sure the bit buffer contains at least 16-bit to ensure successive chunks in a stream are read correctly
895
       */
896
6.63M
      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.63M
    }
914
#if defined( HAVE_DEBUG_OUTPUT )
915
    if( libcnotify_verbose != 0 )
916
    {
917
      libcnotify_printf(
918
       "\n" );
919
    }
920
#endif
921
19.7M
  }
922
6.05k
  if( libfwnt_huffman_tree_free(
923
6.05k
       &huffman_tree,
924
6.05k
       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.05k
  *uncompressed_data_offset = safe_uncompressed_data_offset;
936
937
6.05k
  return( 1 );
938
939
550
on_error:
940
550
  if( huffman_tree != NULL )
941
550
  {
942
550
    libfwnt_huffman_tree_free(
943
550
     &huffman_tree,
944
550
     NULL );
945
550
  }
946
550
  return( -1 );
947
6.05k
}
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.58k
{
959
1.58k
  libfwnt_bit_stream_t *bit_stream   = NULL;
960
1.58k
  static char *function              = "libfwnt_lzxpress_huffman_decompress";
961
1.58k
  size_t safe_uncompressed_data_size = 0;
962
1.58k
  size_t uncompressed_data_offset    = 0;
963
964
1.58k
  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.58k
  if( libfwnt_bit_stream_initialize(
976
1.58k
       &bit_stream,
977
1.58k
       compressed_data,
978
1.58k
       compressed_data_size,
979
1.58k
       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.58k
  safe_uncompressed_data_size = *uncompressed_data_size;
991
992
7.64k
  while( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
993
7.26k
  {
994
7.26k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
995
421
    {
996
421
      break;
997
421
    }
998
6.84k
    if( libfwnt_lzxpress_huffman_decompress_chunk(
999
6.84k
         bit_stream,
1000
6.84k
         uncompressed_data,
1001
6.84k
         safe_uncompressed_data_size,
1002
6.84k
         &uncompressed_data_offset,
1003
6.84k
         error ) != 1 )
1004
790
    {
1005
790
      libcerror_error_set(
1006
790
       error,
1007
790
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
1008
790
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
1009
790
       "%s: unable to decompress chunk.",
1010
790
       function );
1011
1012
790
      goto on_error;
1013
790
    }
1014
6.84k
  }
1015
796
  if( libfwnt_bit_stream_free(
1016
796
       &bit_stream,
1017
796
       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
796
  *uncompressed_data_size = uncompressed_data_offset;
1029
1030
796
  return( 1 );
1031
1032
790
on_error:
1033
790
  if( bit_stream != NULL )
1034
790
  {
1035
790
    libfwnt_bit_stream_free(
1036
790
     &bit_stream,
1037
790
     NULL );
1038
790
  }
1039
790
  return( -1 );
1040
796
}
1041