Coverage Report

Created: 2024-02-25 07:19

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