Coverage Report

Created: 2025-12-05 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libscca/libscca/libscca_compressed_block.c
Line
Count
Source
1
/*
2
 * Compressed block functions
3
 *
4
 * Copyright (C) 2011-2025, 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 "libscca_compressed_block.h"
28
#include "libscca_definitions.h"
29
#include "libscca_file.h"
30
#include "libscca_io_handle.h"
31
#include "libscca_libcerror.h"
32
#include "libscca_libcnotify.h"
33
#include "libscca_libfdata.h"
34
#include "libscca_libfwnt.h"
35
#include "libscca_unused.h"
36
37
/* Creates compressed block
38
 * Make sure the value compressed_block is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libscca_compressed_block_initialize(
42
     libscca_compressed_block_t **compressed_block,
43
     size_t data_size,
44
     libcerror_error_t **error )
45
372
{
46
372
  static char *function = "libscca_compressed_block_initialize";
47
48
372
  if( compressed_block == NULL )
49
0
  {
50
0
    libcerror_error_set(
51
0
     error,
52
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54
0
     "%s: invalid compressed block.",
55
0
     function );
56
57
0
    return( -1 );
58
0
  }
59
372
  if( *compressed_block != NULL )
60
0
  {
61
0
    libcerror_error_set(
62
0
     error,
63
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
64
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65
0
     "%s: invalid compressed block value already set.",
66
0
     function );
67
68
0
    return( -1 );
69
0
  }
70
372
  if( ( data_size == 0 )
71
370
   || ( data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
72
11
  {
73
11
    libcerror_error_set(
74
11
     error,
75
11
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76
11
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
77
11
     "%s: invalid data size value out of bounds.",
78
11
     function );
79
80
11
    return( -1 );
81
11
  }
82
361
  *compressed_block = memory_allocate_structure(
83
361
                       libscca_compressed_block_t );
84
85
361
  if( *compressed_block == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91
0
     "%s: unable to create compressed block.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
361
  if( memory_set(
97
361
       *compressed_block,
98
361
       0,
99
361
       sizeof( libscca_compressed_block_t ) ) == NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
104
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
105
0
     "%s: unable to clear compressed block.",
106
0
     function );
107
108
0
    memory_free(
109
0
     *compressed_block );
110
111
0
    *compressed_block = NULL;
112
113
0
    return( -1 );
114
0
  }
115
361
  ( *compressed_block )->data = (uint8_t *) memory_allocate(
116
361
                                             sizeof( uint8_t ) * data_size );
117
118
361
  if( ( *compressed_block )->data == NULL )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
123
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
124
0
     "%s: unable to create data.",
125
0
     function );
126
127
0
    goto on_error;
128
0
  }
129
361
  if( memory_set(
130
361
       ( *compressed_block )->data,
131
361
       0,
132
361
       sizeof( uint8_t ) * data_size ) == NULL )
133
0
  {
134
0
    libcerror_error_set(
135
0
     error,
136
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
137
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
138
0
     "%s: unable to clear compressed block.",
139
0
     function );
140
141
0
    goto on_error;
142
0
  }
143
361
  ( *compressed_block )->data_size = data_size;
144
145
361
  return( 1 );
146
147
0
on_error:
148
0
  if( *compressed_block != NULL )
149
0
  {
150
0
    if( ( *compressed_block )->data != NULL )
151
0
    {
152
0
      memory_free(
153
0
       ( *compressed_block )->data );
154
0
    }
155
0
    memory_free(
156
0
     *compressed_block );
157
158
0
    *compressed_block = NULL;
159
0
  }
160
0
  return( -1 );
161
361
}
162
163
/* Frees compressed block
164
 * Returns 1 if successful or -1 on error
165
 */
166
int libscca_compressed_block_free(
167
     libscca_compressed_block_t **compressed_block,
168
     libcerror_error_t **error )
169
361
{
170
361
  static char *function = "libscca_compressed_block_free";
171
172
361
  if( compressed_block == NULL )
173
0
  {
174
0
    libcerror_error_set(
175
0
     error,
176
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
177
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
178
0
     "%s: invalid compressed block.",
179
0
     function );
180
181
0
    return( -1 );
182
0
  }
183
361
  if( *compressed_block != NULL )
184
361
  {
185
361
    if( ( *compressed_block )->data != NULL )
186
361
    {
187
361
      memory_free(
188
361
       ( *compressed_block )->data );
189
361
    }
190
361
    memory_free(
191
361
     *compressed_block );
192
193
361
    *compressed_block = NULL;
194
361
  }
195
361
  return( 1 );
196
361
}
197
198
/* Reads a compressed block
199
 * Returns the number of bytes of read on success or -1 on error
200
 */
201
ssize_t libscca_compressed_block_read_file_io_handle(
202
         libscca_compressed_block_t *compressed_block,
203
         libbfio_handle_t *file_io_handle,
204
         off64_t compressed_block_offset,
205
         size_t compressed_block_size,
206
         libcerror_error_t **error )
207
361
{
208
361
  uint8_t *compressed_data      = NULL;
209
361
  static char *function         = "libscca_compressed_block_read_file_io_handle";
210
361
  size_t uncompressed_data_size = 0;
211
361
  ssize_t read_count            = 0;
212
213
361
  if( compressed_block == NULL )
214
0
  {
215
0
    libcerror_error_set(
216
0
     error,
217
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
218
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
219
0
     "%s: invalid compressed block.",
220
0
     function );
221
222
0
    return( -1 );
223
0
  }
224
361
  if( ( compressed_block_size == 0 )
225
361
   || ( compressed_block_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
226
0
  {
227
0
    libcerror_error_set(
228
0
     error,
229
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
230
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
231
0
     "%s: invalid compressed block size value out of bounds.",
232
0
     function );
233
234
0
    return( -1 );
235
0
  }
236
361
  compressed_data = (uint8_t *) memory_allocate(
237
361
                                 sizeof( uint8_t ) * compressed_block_size );
238
239
361
  if( compressed_data == NULL )
240
0
  {
241
0
    libcerror_error_set(
242
0
     error,
243
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
244
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
245
0
     "%s: unable to create compressed data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
246
0
     function,
247
0
     compressed_block_offset,
248
0
     compressed_block_offset );
249
250
0
    goto on_error;
251
0
  }
252
361
  read_count = libbfio_handle_read_buffer_at_offset(
253
361
          file_io_handle,
254
361
          compressed_data,
255
361
          compressed_block_size,
256
361
          compressed_block_offset,
257
361
          error );
258
259
361
  if( read_count == -1 )
260
0
  {
261
0
    libcerror_error_set(
262
0
     error,
263
0
     LIBCERROR_ERROR_DOMAIN_IO,
264
0
     LIBCERROR_IO_ERROR_READ_FAILED,
265
0
     "%s: unable to read compressed block.",
266
0
     function );
267
268
0
    goto on_error;
269
0
  }
270
361
  uncompressed_data_size = compressed_block->data_size;
271
272
361
  if( libfwnt_lzxpress_huffman_decompress(
273
361
       compressed_data,
274
361
       (size_t) read_count,
275
361
       compressed_block->data,
276
361
       &uncompressed_data_size,
277
361
       error ) != 1 )
278
225
  {
279
225
    libcerror_error_set(
280
225
     error,
281
225
     LIBCERROR_ERROR_DOMAIN_COMPRESSION,
282
225
     LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
283
225
     "%s: unable to decompress compressed data.",
284
225
     function );
285
286
225
    goto on_error;
287
225
  }
288
#if defined( HAVE_DEBUG_OUTPUT )
289
  if( libcnotify_verbose != 0 )
290
  {
291
    libcnotify_printf(
292
     "%s: uncompressed data:\n",
293
     function );
294
    libcnotify_print_data(
295
     compressed_block->data,
296
     compressed_block->data_size,
297
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
298
  }
299
#endif
300
136
  memory_free(
301
136
   compressed_data );
302
303
136
  compressed_data = NULL;
304
305
136
  return( read_count );
306
307
225
on_error:
308
225
  if( compressed_data != NULL )
309
225
  {
310
225
    memory_free(
311
225
     compressed_data );
312
225
  }
313
225
  return( -1 );
314
361
}
315
316
/* Reads a compressed block
317
 * Callback function for the compressed blocks list
318
 * Returns 1 if successful or -1 on error
319
 */
320
int libscca_compressed_block_read_element_data(
321
     libscca_io_handle_t *io_handle,
322
     libbfio_handle_t *file_io_handle,
323
     libfdata_list_element_t *element,
324
     libfdata_cache_t *cache,
325
     int element_file_index LIBSCCA_ATTRIBUTE_UNUSED,
326
     off64_t compressed_block_offset,
327
     size64_t compressed_block_size,
328
     uint32_t compressed_block_flags,
329
     uint8_t read_flags LIBSCCA_ATTRIBUTE_UNUSED,
330
     libcerror_error_t **error )
331
0
{
332
0
  libscca_compressed_block_t *compressed_block = NULL;
333
0
  static char *function                        = "libscca_compressed_block_read_element_data";
334
0
  size64_t uncompressed_size                   = 0;
335
0
  ssize_t read_count                           = 0;
336
337
0
  LIBSCCA_UNREFERENCED_PARAMETER( element_file_index )
338
0
  LIBSCCA_UNREFERENCED_PARAMETER( read_flags )
339
340
0
  if( io_handle == NULL )
341
0
  {
342
0
    libcerror_error_set(
343
0
     error,
344
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
345
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
346
0
     "%s: invalid IO handle.",
347
0
     function );
348
349
0
    return( -1 );
350
0
  }
351
0
  if( io_handle->file_type != LIBSCCA_FILE_TYPE_COMPRESSED_WINDOWS10 )
352
0
  {
353
0
    libcerror_error_set(
354
0
     error,
355
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
356
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
357
0
     "%s: invalid IO handle - unsupported file type.",
358
0
     function );
359
360
0
    return( -1 );
361
0
  }
362
0
  if( compressed_block_size > (size64_t) SSIZE_MAX )
363
0
  {
364
0
    libcerror_error_set(
365
0
     error,
366
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
367
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
368
0
     "%s: invalid compressed block size value out of bounds.",
369
0
     function );
370
371
0
    return( -1 );
372
0
  }
373
0
  if( ( compressed_block_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) == 0 )
374
0
  {
375
0
    libcerror_error_set(
376
0
     error,
377
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
378
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
379
0
     "%s: compressed range flags not set.",
380
0
     function );
381
382
0
    return( -1 );
383
0
  }
384
0
  if( libfdata_list_element_get_mapped_size(
385
0
       element,
386
0
       &uncompressed_size,
387
0
       error ) != 1 )
388
0
  {
389
0
    libcerror_error_set(
390
0
     error,
391
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
392
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
393
0
     "%s: unable to retrieve list element mapped size.",
394
0
     function );
395
396
0
    goto on_error;
397
0
  }
398
0
  if( libscca_compressed_block_initialize(
399
0
       &compressed_block,
400
0
       (size_t) uncompressed_size,
401
0
       error ) != 1 )
402
0
  {
403
0
    libcerror_error_set(
404
0
     error,
405
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
406
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
407
0
     "%s: unable to create compressed block.",
408
0
     function );
409
410
0
    goto on_error;
411
0
  }
412
0
  read_count = libscca_compressed_block_read_file_io_handle(
413
0
                compressed_block,
414
0
                file_io_handle,
415
0
                compressed_block_offset,
416
0
                (size_t) compressed_block_size,
417
0
                error );
418
419
0
  if( read_count != (ssize_t) compressed_block_size )
420
0
  {
421
0
    libcerror_error_set(
422
0
     error,
423
0
     LIBCERROR_ERROR_DOMAIN_IO,
424
0
     LIBCERROR_IO_ERROR_READ_FAILED,
425
0
     "%s: unable to read compressed block.",
426
0
     function );
427
428
0
    goto on_error;
429
0
  }
430
#if defined( HAVE_DEBUG_OUTPUT )
431
  if( libcnotify_verbose != 0 )
432
  {
433
    libcnotify_printf(
434
     "%s: uncompressed data:\n",
435
     function );
436
    libcnotify_print_data(
437
     compressed_block->data,
438
     compressed_block->data_size,
439
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
440
  }
441
#endif
442
0
  if( libfdata_list_element_set_element_value(
443
0
       element,
444
0
       (intptr_t *) file_io_handle,
445
0
       cache,
446
0
       (intptr_t *) compressed_block,
447
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libscca_compressed_block_free,
448
0
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
449
0
       error ) != 1 )
450
0
  {
451
0
    libcerror_error_set(
452
0
     error,
453
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
454
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
455
0
     "%s: unable to set compressed block as element value.",
456
0
     function );
457
458
0
    goto on_error;
459
0
  }
460
0
  return( 1 );
461
462
0
on_error:
463
0
  if( compressed_block != NULL )
464
0
  {
465
0
    libscca_compressed_block_free(
466
0
     &compressed_block,
467
     NULL );
468
0
  }
469
0
  return( -1 );
470
0
}
471