Coverage Report

Created: 2024-02-25 07:20

/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.8k
  while( compressed_data_offset < compressed_data_size )
174
46.7k
  {
175
46.7k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
176
16
    {
177
16
      break;
178
16
    }
179
46.7k
    if( ( compressed_data_size < 4 )
180
46.7k
     || ( 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.7k
    byte_stream_copy_to_uint32_little_endian(
192
46.7k
     &( compressed_data[ compressed_data_offset ] ),
193
46.7k
     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.7k
    compressed_data_offset += 4;
214
215
46.7k
    for( compression_indicator_bitmask = 0x80000000UL;
216
1.53M
         compression_indicator_bitmask > 0;
217
1.48M
         compression_indicator_bitmask >>= 1 )
218
1.48M
    {
219
1.48M
      if( uncompressed_data_offset >= safe_uncompressed_data_size )
220
17
      {
221
17
        break;
222
17
      }
223
1.48M
      if( compressed_data_offset >= compressed_data_size )
224
92
      {
225
92
        break;
226
92
      }
227
      /* If the indicator bit is 0 the data is uncompressed
228
       * or 1 if the data is compressed
229
       */
230
1.48M
      if( ( compression_indicator & compression_indicator_bitmask ) != 0 )
231
666k
      {
232
666k
        if( compressed_data_offset > ( compressed_data_size - 2 ) )
233
30
        {
234
30
          libcerror_error_set(
235
30
           error,
236
30
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
237
30
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
238
30
           "%s: compressed data too small.",
239
30
           function );
240
241
30
          return( -1 );
242
30
        }
243
666k
                    byte_stream_copy_to_uint16_little_endian(
244
666k
                     &( compressed_data[ compressed_data_offset ] ),
245
666k
                     compression_tuple );
246
247
666k
        compressed_data_offset += 2;
248
249
        /* The compression tuple contains:
250
         * 0 - 2  the size
251
         * 3 - 15 the offset - 1
252
         */
253
666k
        compression_tuple_size   = ( compression_tuple & 0x0007 );
254
666k
        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
666k
        if( compression_tuple_size == 0x07 )
261
650k
        {
262
650k
          if( compression_shared_byte_index == 0 )
263
325k
          {
264
325k
            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
325k
            compression_tuple_size += compressed_data[ compressed_data_offset ] & 0x0f;
276
277
325k
            compression_shared_byte_index = compressed_data_offset++;
278
325k
          }
279
325k
          else
280
325k
          {
281
325k
            compression_tuple_size += compressed_data[ compression_shared_byte_index ] >> 4;
282
283
325k
            compression_shared_byte_index = 0;
284
325k
          }
285
650k
        }
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
666k
        if( compression_tuple_size == ( 0x07 + 0x0f ) )
291
646k
        {
292
646k
          if( compressed_data_offset >= compressed_data_size )
293
18
          {
294
18
            libcerror_error_set(
295
18
             error,
296
18
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
297
18
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
298
18
             "%s: compressed data too small.",
299
18
             function );
300
301
18
            return( -1 );
302
18
          }
303
646k
          compression_tuple_size += compressed_data[ compressed_data_offset++ ];
304
646k
        }
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
666k
        if( compression_tuple_size == ( 0x07 + 0x0f + 0xff ) )
310
645k
        {
311
645k
          if( compressed_data_offset > ( compressed_data_size - 2 ) )
312
28
          {
313
28
            libcerror_error_set(
314
28
             error,
315
28
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
316
28
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
317
28
             "%s: compressed data too small.",
318
28
             function );
319
320
28
            return( -1 );
321
28
          }
322
645k
                      byte_stream_copy_to_uint16_little_endian(
323
645k
                       &( compressed_data[ compressed_data_offset ] ),
324
645k
                       compression_tuple_size );
325
    
326
645k
          compressed_data_offset += 2;
327
645k
        }
328
        /* The size value is stored as
329
         * size - 3
330
         */
331
666k
        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
666k
        if( compression_tuple_size > 32771 )
364
16
        {
365
16
          libcerror_error_set(
366
16
           error,
367
16
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
368
16
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
369
16
           "%s: compression tuple size value out of bounds.",
370
16
           function );
371
372
16
          return( -1 );
373
16
        }
374
666k
        compression_index = uncompressed_data_offset - compression_tuple_offset;
375
376
6.56M
        while( compression_tuple_size > 0 )
377
5.89M
        {
378
5.89M
          if( compression_index >= uncompressed_data_offset )
379
89
          {
380
89
            libcerror_error_set(
381
89
             error,
382
89
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
383
89
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
384
89
             "%s: invalid compressed data at offset: %" PRIzd " - compression index: %" PRIzd " out of range: %" PRIzd ".",
385
89
             function,
386
89
             compressed_data_offset,
387
89
             compression_index,
388
89
             uncompressed_data_offset );
389
390
89
            return( -1 );
391
89
          }
392
5.89M
          if( uncompressed_data_offset >= safe_uncompressed_data_size )
393
8
          {
394
8
            libcerror_error_set(
395
8
             error,
396
8
             LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
397
8
             LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
398
8
             "%s: uncompressed data too small.",
399
8
             function );
400
401
8
            return( -1 );
402
8
          }
403
5.89M
          uncompressed_data[ uncompressed_data_offset++ ] = uncompressed_data[ compression_index++ ];
404
405
5.89M
          compression_tuple_size--;
406
5.89M
        }
407
666k
      }
408
821k
      else
409
821k
      {
410
821k
        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
821k
        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
821k
        uncompressed_data[ uncompressed_data_offset++ ] = compressed_data[ compressed_data_offset++ ];
433
821k
      }
434
1.48M
    }
435
46.7k
  }
436
122
  *uncompressed_data_size = uncompressed_data_offset;
437
438
122
  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
5.89k
{
451
5.89k
  uint8_t code_size_array[ 512 ];
452
453
5.89k
  libfwnt_huffman_tree_t *huffman_tree       = NULL;
454
5.89k
  static char *function                      = "libfwnt_lzxpress_huffman_decompress_chunk";
455
5.89k
  size_t next_chunk_uncompressed_data_offset = 0;
456
5.89k
  size_t safe_uncompressed_data_offset       = 0;
457
5.89k
  uint32_t compression_offset                = 0;
458
5.89k
  uint32_t compression_size                  = 0;
459
5.89k
  uint32_t symbol                            = 0;
460
5.89k
  uint8_t byte_value                         = 0;
461
462
5.89k
  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
5.89k
  if( ( bit_stream->byte_stream_size - bit_stream->byte_stream_offset ) < 260 )
474
248
  {
475
248
    libcerror_error_set(
476
248
     error,
477
248
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
478
248
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
479
248
     "%s: invalid bit stream - byte stream value too small.",
480
248
     function );
481
482
248
    return( -1 );
483
248
  }
484
5.64k
  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
5.64k
  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
5.64k
  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
5.64k
  safe_uncompressed_data_offset = *uncompressed_data_offset;
518
519
5.64k
  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.45M
  while( symbol < 512 )
533
1.44M
  {
534
1.44M
    byte_value = bit_stream->byte_stream[ bit_stream->byte_stream_offset ];
535
536
1.44M
    code_size_array[ symbol++ ] = byte_value & 0x0f;
537
538
1.44M
    byte_value >>= 4;
539
540
1.44M
    code_size_array[ symbol++ ] = byte_value & 0x0f;
541
542
1.44M
    bit_stream->byte_stream_offset += 1;
543
1.44M
  }
544
5.64k
  if( libfwnt_huffman_tree_initialize(
545
5.64k
       &huffman_tree,
546
5.64k
       512,
547
5.64k
       15,
548
5.64k
       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
5.64k
  if( libfwnt_huffman_tree_build(
560
5.64k
       huffman_tree,
561
5.64k
       code_size_array,
562
5.64k
       512,
563
5.64k
       error ) != 1 )
564
69
  {
565
69
    libcerror_error_set(
566
69
     error,
567
69
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
568
69
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
569
69
     "%s: unable to build Huffman tree.",
570
69
     function );
571
572
69
    goto on_error;
573
69
  }
574
5.57k
  if( libfwnt_bit_stream_read(
575
5.57k
       bit_stream,
576
5.57k
       32,
577
5.57k
       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
5.57k
  next_chunk_uncompressed_data_offset = safe_uncompressed_data_offset + 65536;
589
590
5.57k
  if( next_chunk_uncompressed_data_offset > uncompressed_data_size )
591
153
  {
592
153
    next_chunk_uncompressed_data_offset = uncompressed_data_size;
593
153
  }
594
20.2M
        while( ( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
595
20.2M
            || ( bit_stream->bit_buffer_size > 0 ) )
596
20.2M
  {
597
20.2M
    if( safe_uncompressed_data_offset >= next_chunk_uncompressed_data_offset )
598
4.91k
    {
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
4.91k
      bit_stream->bit_buffer_size = 0;
615
616
4.91k
      break;
617
4.91k
    }
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
20.2M
    if( libfwnt_huffman_tree_get_symbol_from_bit_stream(
629
20.2M
         huffman_tree,
630
20.2M
         bit_stream,
631
20.2M
         &symbol,
632
20.2M
         error ) != 1 )
633
84
    {
634
84
      libcerror_error_set(
635
84
       error,
636
84
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
637
84
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
638
84
       "%s: unable to read symbol.",
639
84
       function );
640
641
84
      goto on_error;
642
84
    }
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
20.2M
    if( symbol < 256 )
653
13.2M
    {
654
13.2M
      uncompressed_data[ safe_uncompressed_data_offset++ ] = (uint8_t) symbol;
655
13.2M
    }
656
    /* Make sure the bit buffer contains at least 16-bit to ensure end-of-block marker is read correctly
657
     */
658
20.2M
    if( bit_stream->bit_buffer_size < 16 )
659
6.78M
    {
660
6.78M
      if( libfwnt_bit_stream_read(
661
6.78M
           bit_stream,
662
6.78M
           16,
663
6.78M
           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.78M
    }
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
20.2M
    if( ( bit_stream->bit_buffer == 0 )
688
20.2M
     && ( safe_uncompressed_data_offset >= uncompressed_data_size ) )
689
182
    {
690
182
      break;
691
182
    }
692
20.2M
    if( symbol >= 256 )
693
7.00M
    {
694
7.00M
      symbol            -= 256;
695
7.00M
      compression_offset = 0;
696
7.00M
      compression_size   = symbol & 0x000f;
697
7.00M
      symbol           >>= 4;
698
699
7.00M
      if( symbol != 0 )
700
6.54M
      {
701
6.54M
        if( libfwnt_bit_stream_get_value(
702
6.54M
             bit_stream,
703
6.54M
             (uint8_t) symbol,
704
6.54M
             &compression_offset,
705
6.54M
             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.54M
      }
726
7.00M
      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
7.00M
      if( compression_size == 15 )
740
286k
      {
741
286k
        if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 1 ) )
742
107
        {
743
107
          libcerror_error_set(
744
107
           error,
745
107
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
746
107
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
747
107
           "%s: compressed data size value too small.",
748
107
           function );
749
750
107
          goto on_error;
751
107
        }
752
286k
        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
286k
        bit_stream->byte_stream_offset += 1;
770
771
286k
        if( compression_size == 270 )
772
8.16k
        {
773
8.16k
          if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 2 ) )
774
25
          {
775
25
            libcerror_error_set(
776
25
             error,
777
25
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
778
25
             LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
779
25
             "%s: compressed data size value too small.",
780
25
             function );
781
782
25
            goto on_error;
783
25
          }
784
8.14k
          byte_stream_copy_to_uint16_little_endian(
785
8.14k
           &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
786
8.14k
           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.14k
          bit_stream->byte_stream_offset += 2;
804
805
8.14k
          if( compression_size == 0 )
806
2.93k
          {
807
2.93k
            if( bit_stream->byte_stream_offset > ( bit_stream->byte_stream_size - 4 ) )
808
24
            {
809
24
              libcerror_error_set(
810
24
               error,
811
24
               LIBCERROR_ERROR_DOMAIN_RUNTIME,
812
24
               LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
813
24
               "%s: compressed data size value too small.",
814
24
               function );
815
816
24
              goto on_error;
817
24
            }
818
2.90k
            byte_stream_copy_to_uint32_little_endian(
819
2.90k
             &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
820
2.90k
             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.90k
            bit_stream->byte_stream_offset += 4;
838
839
2.90k
          }
840
8.14k
        }
841
286k
      }
842
7.00M
      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
7.00M
      if( compression_offset > safe_uncompressed_data_offset )
865
102
      {
866
102
        libcerror_error_set(
867
102
         error,
868
102
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
869
102
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
870
102
         "%s: compression offset value out of bounds.",
871
102
         function );
872
873
102
        goto on_error;
874
102
      }
875
7.00M
      if( compression_size > ( uncompressed_data_size - safe_uncompressed_data_offset ) )
876
144
      {
877
144
        libcerror_error_set(
878
144
         error,
879
144
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
880
144
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
881
144
         "%s: compression size value out of bounds.",
882
144
         function );
883
884
144
        goto on_error;
885
144
      }
886
7.00M
      compression_offset = safe_uncompressed_data_offset - compression_offset;
887
888
1.08G
      while( compression_size > 0 )
889
1.08G
      {
890
1.08G
        uncompressed_data[ safe_uncompressed_data_offset++ ] = uncompressed_data[ compression_offset++ ];
891
892
1.08G
        compression_size--;
893
1.08G
      }
894
      /* Make sure the bit buffer contains at least 16-bit to ensure successive chunks in a stream are read correctly
895
       */
896
7.00M
      if( bit_stream->bit_buffer_size < 16 )
897
2.23M
      {
898
2.23M
        if( libfwnt_bit_stream_read(
899
2.23M
             bit_stream,
900
2.23M
             16,
901
2.23M
             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.23M
      }
913
7.00M
    }
914
#if defined( HAVE_DEBUG_OUTPUT )
915
    if( libcnotify_verbose != 0 )
916
    {
917
      libcnotify_printf(
918
       "\n" );
919
    }
920
#endif
921
20.2M
  }
922
5.09k
  if( libfwnt_huffman_tree_free(
923
5.09k
       &huffman_tree,
924
5.09k
       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
5.09k
  *uncompressed_data_offset = safe_uncompressed_data_offset;
936
937
5.09k
  return( 1 );
938
939
555
on_error:
940
555
  if( huffman_tree != NULL )
941
555
  {
942
555
    libfwnt_huffman_tree_free(
943
555
     &huffman_tree,
944
555
     NULL );
945
555
  }
946
555
  return( -1 );
947
5.09k
}
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.63k
{
959
1.63k
  libfwnt_bit_stream_t *bit_stream   = NULL;
960
1.63k
  static char *function              = "libfwnt_lzxpress_huffman_decompress";
961
1.63k
  size_t safe_uncompressed_data_size = 0;
962
1.63k
  size_t uncompressed_data_offset    = 0;
963
964
1.63k
  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.63k
  if( libfwnt_bit_stream_initialize(
976
1.63k
       &bit_stream,
977
1.63k
       compressed_data,
978
1.63k
       compressed_data_size,
979
1.63k
       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.63k
  safe_uncompressed_data_size = *uncompressed_data_size;
991
992
6.72k
  while( bit_stream->byte_stream_offset < bit_stream->byte_stream_size )
993
6.32k
  {
994
6.32k
    if( uncompressed_data_offset >= safe_uncompressed_data_size )
995
426
    {
996
426
      break;
997
426
    }
998
5.89k
    if( libfwnt_lzxpress_huffman_decompress_chunk(
999
5.89k
         bit_stream,
1000
5.89k
         uncompressed_data,
1001
5.89k
         safe_uncompressed_data_size,
1002
5.89k
         &uncompressed_data_offset,
1003
5.89k
         error ) != 1 )
1004
803
    {
1005
803
      libcerror_error_set(
1006
803
       error,
1007
803
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
1008
803
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
1009
803
       "%s: unable to decompress chunk.",
1010
803
       function );
1011
1012
803
      goto on_error;
1013
803
    }
1014
5.89k
  }
1015
828
  if( libfwnt_bit_stream_free(
1016
828
       &bit_stream,
1017
828
       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
828
  *uncompressed_data_size = uncompressed_data_offset;
1029
1030
828
  return( 1 );
1031
1032
803
on_error:
1033
803
  if( bit_stream != NULL )
1034
803
  {
1035
803
    libfwnt_bit_stream_free(
1036
803
     &bit_stream,
1037
803
     NULL );
1038
803
  }
1039
803
  return( -1 );
1040
828
}
1041