Coverage Report

Created: 2025-06-24 07:14

/src/libfsapfs/libfsapfs/libfsapfs_compressed_data_handle.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The compressed data handle functions
3
 *
4
 * Copyright (C) 2018-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 "libfsapfs_compressed_data_handle.h"
28
#include "libfsapfs_compression.h"
29
#include "libfsapfs_definitions.h"
30
#include "libfsapfs_libbfio.h"
31
#include "libfsapfs_libcerror.h"
32
#include "libfsapfs_libcnotify.h"
33
#include "libfsapfs_unused.h"
34
35
0
#define LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE 65536
36
37
/* Creates compressed data handle
38
 * Make sure the value data_handle is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libfsapfs_compressed_data_handle_initialize(
42
     libfsapfs_compressed_data_handle_t **data_handle,
43
     libfdata_stream_t *compressed_data_stream,
44
     size64_t uncompressed_data_size,
45
     int compression_method,
46
     libcerror_error_t **error )
47
0
{
48
0
  static char *function = "libfsapfs_compressed_data_handle_initialize";
49
50
0
  if( data_handle == NULL )
51
0
  {
52
0
    libcerror_error_set(
53
0
     error,
54
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56
0
     "%s: invalid data handle.",
57
0
     function );
58
59
0
    return( -1 );
60
0
  }
61
0
  if( *data_handle != NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
66
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67
0
     "%s: invalid data handle value already set.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
0
  if( compressed_data_stream == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
77
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
78
0
     "%s: invalid compressed data stream.",
79
0
     function );
80
81
0
    return( -1 );
82
0
  }
83
0
  if( ( compression_method != LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
84
0
   && ( compression_method != LIBFSAPFS_COMPRESSION_METHOD_LZVN )
85
0
   && ( compression_method != LIBFSAPFS_COMPRESSION_METHOD_UNKNOWN5 ) )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
90
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
91
0
     "%s: unsupported compression method.",
92
0
     function );
93
94
0
    return( -1 );
95
0
  }
96
0
  *data_handle = memory_allocate_structure(
97
0
                  libfsapfs_compressed_data_handle_t );
98
99
0
  if( *data_handle == NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
104
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
105
0
     "%s: unable to create data handle.",
106
0
     function );
107
108
0
    goto on_error;
109
0
  }
110
0
  if( memory_set(
111
0
       *data_handle,
112
0
       0,
113
0
       sizeof( libfsapfs_compressed_data_handle_t ) ) == NULL )
114
0
  {
115
0
    libcerror_error_set(
116
0
     error,
117
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
118
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
119
0
     "%s: unable to clear data handle.",
120
0
     function );
121
122
0
    memory_free(
123
0
     *data_handle );
124
125
0
    *data_handle = NULL;
126
127
0
    return( -1 );
128
0
  }
129
0
  ( *data_handle )->compressed_segment_data = (uint8_t *) memory_allocate(
130
0
                                                           sizeof( uint8_t ) * ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) );
131
132
0
  if( ( *data_handle )->compressed_segment_data == NULL )
133
0
  {
134
0
    libcerror_error_set(
135
0
     error,
136
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
137
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
138
0
     "%s: unable to create compressed segment data.",
139
0
     function );
140
141
0
    goto on_error;
142
0
  }
143
0
  if( compression_method != LIBFSAPFS_COMPRESSION_METHOD_UNKNOWN5 )
144
0
  {
145
0
    ( *data_handle )->segment_data = (uint8_t *) memory_allocate(
146
0
                                                  sizeof( uint8_t ) * LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE );
147
148
0
    if( ( *data_handle )->segment_data == NULL )
149
0
    {
150
0
      libcerror_error_set(
151
0
       error,
152
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
153
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
154
0
       "%s: unable to create segment data.",
155
0
       function );
156
157
0
      goto on_error;
158
0
    }
159
0
  }
160
0
  ( *data_handle )->compressed_data_stream         = compressed_data_stream;
161
0
  ( *data_handle )->current_compressed_block_index = (uint32_t) -1;
162
0
  ( *data_handle )->uncompressed_data_size         = uncompressed_data_size;
163
0
  ( *data_handle )->compression_method             = compression_method;
164
165
0
  return( 1 );
166
167
0
on_error:
168
0
  if( *data_handle != NULL )
169
0
  {
170
0
    if( ( *data_handle )->segment_data != NULL )
171
0
    {
172
0
      memory_free(
173
0
       ( *data_handle )->segment_data );
174
0
    }
175
0
    if( ( *data_handle )->compressed_segment_data != NULL )
176
0
    {
177
0
      memory_free(
178
0
       ( *data_handle )->compressed_segment_data );
179
0
    }
180
0
    memory_free(
181
0
     *data_handle );
182
183
0
    *data_handle = NULL;
184
0
  }
185
0
  return( -1 );
186
0
}
187
188
/* Frees data handle
189
 * Returns 1 if successful or -1 on error
190
 */
191
int libfsapfs_compressed_data_handle_free(
192
     libfsapfs_compressed_data_handle_t **data_handle,
193
     libcerror_error_t **error )
194
0
{
195
0
  static char *function = "libfsapfs_compressed_data_handle_free";
196
197
0
  if( data_handle == NULL )
198
0
  {
199
0
    libcerror_error_set(
200
0
     error,
201
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
202
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
203
0
     "%s: invalid data handle.",
204
0
     function );
205
206
0
    return( -1 );
207
0
  }
208
0
  if( *data_handle != NULL )
209
0
  {
210
0
    if( ( *data_handle )->segment_data != NULL )
211
0
    {
212
0
      memory_free(
213
0
       ( *data_handle )->segment_data );
214
0
    }
215
0
    if( ( *data_handle )->compressed_segment_data != NULL )
216
0
    {
217
0
      memory_free(
218
0
       ( *data_handle )->compressed_segment_data );
219
0
    }
220
0
    if( ( *data_handle )->compressed_block_offsets != NULL )
221
0
    {
222
0
      memory_free(
223
0
       ( *data_handle )->compressed_block_offsets );
224
0
    }
225
0
    memory_free(
226
0
     *data_handle );
227
228
0
    *data_handle = NULL;
229
0
  }
230
0
  return( 1 );
231
0
}
232
233
/* Determines the compressed block offsets
234
 * Returns 1 if successful or -1 on error
235
 */
236
int libfsapfs_compressed_data_handle_get_compressed_block_offsets(
237
     libfsapfs_compressed_data_handle_t *data_handle,
238
     libbfio_handle_t *file_io_handle,
239
     libcerror_error_t **error )
240
0
{
241
0
  static char *function                     = "libfsapfs_compressed_data_handle_get_compressed_block_offsets";
242
0
  size64_t compressed_data_size             = 0;
243
0
  size_t compressed_block_descriptor_size   = 0;
244
0
  size_t read_size                          = 0;
245
0
  size_t segment_data_offset                = 0;
246
0
  ssize_t read_count                        = 0;
247
0
  uint32_t compressed_block_index           = 0;
248
0
  uint32_t compressed_block_offset          = 0;
249
0
  uint32_t compressed_descriptors_offset    = 0;
250
0
  uint32_t compressed_footer_offset         = 0;
251
0
  uint32_t compressed_footer_size           = 0;
252
0
  uint32_t previous_compressed_block_offset = 0;
253
0
  int compare_result                        = 0;
254
255
#if defined( HAVE_DEBUG_OUTPUT )
256
  uint32_t value_32bit                      = 0;
257
#endif
258
259
0
  if( data_handle == NULL )
260
0
  {
261
0
    libcerror_error_set(
262
0
     error,
263
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
264
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
265
0
     "%s: invalid data handle.",
266
0
     function );
267
268
0
    return( -1 );
269
0
  }
270
0
  if( data_handle->compressed_block_offsets != NULL )
271
0
  {
272
0
    libcerror_error_set(
273
0
     error,
274
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
275
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
276
0
     "%s: invalid data handle - compressed block offsets value already set.",
277
0
     function );
278
279
0
    return( -1 );
280
0
  }
281
0
  if( libfdata_stream_get_size(
282
0
       data_handle->compressed_data_stream,
283
0
       &compressed_data_size,
284
0
       error ) != 1 )
285
0
  {
286
0
    libcerror_error_set(
287
0
     error,
288
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
289
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
290
0
     "%s: unable to retrieve compressed data size.",
291
0
     function );
292
293
0
    goto on_error;
294
0
  }
295
0
  read_count = libfdata_stream_read_buffer_at_offset(
296
0
                data_handle->compressed_data_stream,
297
0
                (intptr_t *) file_io_handle,
298
0
                data_handle->compressed_segment_data,
299
0
                4,
300
0
                0,
301
0
                0,
302
0
                error );
303
304
0
  if( read_count != 4 )
305
0
  {
306
0
    libcerror_error_set(
307
0
     error,
308
0
     LIBCERROR_ERROR_DOMAIN_IO,
309
0
     LIBCERROR_IO_ERROR_READ_FAILED,
310
0
     "%s: unable to read buffer at offset: 0 (0x00000000) from data stream.",
311
0
     function );
312
313
0
    goto on_error;
314
0
  }
315
0
  compare_result = memory_compare(
316
0
                    data_handle->compressed_segment_data,
317
0
                    "fpmc",
318
0
                    4 );
319
320
0
  if( compare_result == 0 )
321
0
  {
322
0
    if( compressed_data_size > (size64_t) ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) )
323
0
    {
324
0
      libcerror_error_set(
325
0
       error,
326
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
327
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
328
0
       "%s: invalid segment data size value out of bounds.",
329
0
       function );
330
331
0
      goto on_error;
332
0
    }
333
0
    data_handle->number_of_compressed_blocks = 1;
334
0
  }
335
0
  else if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
336
0
  {
337
0
    byte_stream_copy_to_uint32_big_endian(
338
0
     data_handle->compressed_segment_data,
339
0
     compressed_descriptors_offset );
340
341
0
    if( compressed_descriptors_offset != 0x00000100UL )
342
0
    {
343
0
      libcerror_error_set(
344
0
       error,
345
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
346
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
347
0
       "%s: invalid compressed descriptors offset value out of bounds.",
348
0
       function );
349
350
0
      goto on_error;
351
0
    }
352
0
    read_size = (size_t) compressed_descriptors_offset + 16 - 4;
353
354
0
    read_count = libfdata_stream_read_buffer_at_offset(
355
0
                  data_handle->compressed_data_stream,
356
0
                  (intptr_t *) file_io_handle,
357
0
                  &( data_handle->compressed_segment_data[ 4 ] ),
358
0
                  read_size,
359
0
                  4,
360
0
                  0,
361
0
                  error );
362
363
0
    if( read_count != (ssize_t) read_size )
364
0
    {
365
0
      libcerror_error_set(
366
0
       error,
367
0
       LIBCERROR_ERROR_DOMAIN_IO,
368
0
       LIBCERROR_IO_ERROR_READ_FAILED,
369
0
       "%s: unable to read compressed header data at offset: 4 (0x00000004) from data stream.",
370
0
       function );
371
372
0
      goto on_error;
373
0
    }
374
#if defined( HAVE_DEBUG_OUTPUT )
375
    if( libcnotify_verbose != 0 )
376
    {
377
      libcnotify_printf(
378
       "%s: compressed header data:\n",
379
       function );
380
      libcnotify_print_data(
381
       data_handle->compressed_segment_data,
382
       read_size - 4,
383
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
384
    }
385
#endif
386
#if defined( HAVE_DEBUG_OUTPUT )
387
    if( libcnotify_verbose != 0 )
388
    {
389
      libcnotify_printf(
390
       "%s: compressed descriptors offset\t: 0x%08" PRIx32 "\n",
391
       function,
392
       compressed_descriptors_offset );
393
394
      byte_stream_copy_to_uint32_big_endian(
395
       &( data_handle->compressed_segment_data[ 4 ] ),
396
       compressed_footer_offset );
397
      libcnotify_printf(
398
       "%s: compressed footer offset\t\t: 0x%08" PRIx32 "\n",
399
       function,
400
       compressed_footer_offset );
401
402
      byte_stream_copy_to_uint32_big_endian(
403
       &( data_handle->compressed_segment_data[ 8 ] ),
404
       value_32bit );
405
      libcnotify_printf(
406
       "%s: compressed data size\t\t: %" PRIu32 "\n",
407
       function,
408
       value_32bit );
409
410
      byte_stream_copy_to_uint32_big_endian(
411
       &( data_handle->compressed_segment_data[ 12 ] ),
412
       compressed_footer_size );
413
      libcnotify_printf(
414
       "%s: compressed footer size\t\t: %" PRIu32 "\n",
415
       function,
416
       compressed_footer_size );
417
418
      libcnotify_printf(
419
       "%s: unknown1:\n",
420
       function );
421
      libcnotify_print_data(
422
       &( data_handle->compressed_segment_data[ 16 ] ),
423
       240,
424
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
425
426
      byte_stream_copy_to_uint32_little_endian(
427
       &( data_handle->compressed_segment_data[ 256 ] ),
428
       value_32bit );
429
      libcnotify_printf(
430
       "%s: compressed data size\t\t: %" PRIu32 "\n",
431
       function,
432
       value_32bit );
433
    }
434
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
435
436
0
    byte_stream_copy_to_uint32_little_endian(
437
0
     &( data_handle->compressed_segment_data[ 260 ] ),
438
0
     data_handle->number_of_compressed_blocks );
439
440
0
    if( data_handle->number_of_compressed_blocks > ( (uint32_t) UINT32_MAX / 8 ) )
441
0
    {
442
0
      libcerror_error_set(
443
0
       error,
444
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
445
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
446
0
       "%s: invalid number of compressed blocks value out of bounds.",
447
0
       function );
448
449
0
      goto on_error;
450
0
    }
451
0
    segment_data_offset = 264;
452
453
0
    byte_stream_copy_to_uint32_little_endian(
454
0
     &( data_handle->compressed_segment_data[ segment_data_offset ] ),
455
0
     compressed_block_offset );
456
457
0
    segment_data_offset += 4;
458
459
0
    compressed_descriptors_offset   += 4;
460
0
    compressed_block_descriptor_size = 8;
461
0
  }
462
0
  else if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZVN )
463
0
  {
464
0
    segment_data_offset = 0;
465
466
0
    byte_stream_copy_to_uint32_little_endian(
467
0
     &( data_handle->compressed_segment_data[ segment_data_offset ] ),
468
0
     compressed_block_offset );
469
470
0
    segment_data_offset += 4;
471
472
0
    compressed_block_descriptor_size = 4;
473
474
0
    if( ( compressed_block_offset <= 0x00000004UL )
475
0
     || ( compressed_block_offset >= ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) ) )
476
0
    {
477
0
      libcerror_error_set(
478
0
       error,
479
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
480
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
481
0
       "%s: invalid number of compressed blocks value out of bounds.",
482
0
       function );
483
484
0
      goto on_error;
485
0
    }
486
0
    data_handle->number_of_compressed_blocks = compressed_block_offset / 4;
487
0
  }
488
#if defined( HAVE_DEBUG_OUTPUT )
489
  if( libcnotify_verbose != 0 )
490
  {
491
    libcnotify_printf(
492
     "%s: number of compressed blocks\t: %" PRIu32 "\n",
493
     function,
494
     data_handle->number_of_compressed_blocks );
495
  }
496
#endif
497
0
  if( (size_t) data_handle->number_of_compressed_blocks > ( (size_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE / 4 ) - 1 ) )
498
0
  {
499
0
    libcerror_error_set(
500
0
     error,
501
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
502
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
503
0
     "%s: invalid number of compressed blocks value exceeds maximum allocation size.",
504
0
     function );
505
506
0
    goto on_error;
507
0
  }
508
0
  data_handle->compressed_block_offsets = (uint32_t *) memory_allocate(
509
0
                                                        sizeof( uint32_t ) * ( data_handle->number_of_compressed_blocks + 1 ) );
510
511
0
  if( data_handle->compressed_block_offsets == NULL )
512
0
  {
513
0
    libcerror_error_set(
514
0
     error,
515
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
516
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
517
0
     "%s: unable to create compressed block offsets.",
518
0
     function );
519
520
0
    goto on_error;
521
0
  }
522
0
  if( compare_result == 0 )
523
0
  {
524
0
    data_handle->compressed_block_offsets[ compressed_block_index++ ] = 16;
525
0
    previous_compressed_block_offset                                  = 16;
526
0
  }
527
0
  else
528
0
  {
529
0
    read_size = ( (size_t) data_handle->number_of_compressed_blocks - 1 ) * compressed_block_descriptor_size;
530
531
0
    read_count = libfdata_stream_read_buffer_at_offset(
532
0
                  data_handle->compressed_data_stream,
533
0
                  (intptr_t *) file_io_handle,
534
0
                  &( data_handle->compressed_segment_data[ segment_data_offset ] ),
535
0
                  read_size,
536
0
                  segment_data_offset,
537
0
                  0,
538
0
                  error );
539
540
0
    if( read_count != (ssize_t) read_size )
541
0
    {
542
0
      libcerror_error_set(
543
0
       error,
544
0
       LIBCERROR_ERROR_DOMAIN_IO,
545
0
       LIBCERROR_IO_ERROR_READ_FAILED,
546
0
       "%s: unable to read compressed block descriptors data at offset: %" PRIzd " (0x%08" PRIzx ") from data stream.",
547
0
       function,
548
0
       segment_data_offset,
549
0
       segment_data_offset );
550
551
0
      goto on_error;
552
0
    }
553
#if defined( HAVE_DEBUG_OUTPUT )
554
    if( libcnotify_verbose != 0 )
555
    {
556
      libcnotify_printf(
557
       "%s: compressed block descriptors data:\n",
558
       function );
559
      libcnotify_print_data(
560
       &( data_handle->compressed_segment_data[ segment_data_offset - compressed_block_descriptor_size ] ),
561
       read_size + compressed_block_descriptor_size,
562
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
563
    }
564
#endif
565
#if defined( HAVE_DEBUG_OUTPUT )
566
    if( libcnotify_verbose != 0 )
567
    {
568
      libcnotify_printf(
569
       "%s: compressed block: % 2" PRIu32 " offset\t: 0x%08" PRIx32 " (0x%08" PRIx32 ")\n",
570
       function,
571
       compressed_block_index,
572
       compressed_block_offset,
573
       compressed_block_offset + compressed_descriptors_offset );
574
    }
575
#endif
576
0
    if( ( compressed_block_offset <= compressed_block_descriptor_size )
577
0
     || ( compressed_block_offset >= ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) ) )
578
0
    {
579
0
      libcerror_error_set(
580
0
       error,
581
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
582
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
583
0
       "%s: invalid compressed block offset: %" PRIu32 " (0x%08" PRIx32 ") value out of bounds.",
584
0
       function,
585
0
       compressed_block_offset,
586
0
       compressed_block_offset );
587
588
0
      goto on_error;
589
0
    }
590
0
    compressed_block_offset += compressed_descriptors_offset;
591
592
0
    data_handle->compressed_block_offsets[ 0 ] = compressed_block_offset;
593
0
    previous_compressed_block_offset           = compressed_block_offset;
594
595
0
    if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
596
0
    {
597
#if defined( HAVE_DEBUG_OUTPUT )
598
      if( libcnotify_verbose != 0 )
599
      {
600
        byte_stream_copy_to_uint32_little_endian(
601
         &( data_handle->compressed_segment_data[ segment_data_offset ] ),
602
         value_32bit );
603
        libcnotify_printf(
604
         "%s: compressed block: % 2" PRIu32 " size\t: %" PRIu32 "\n",
605
         function,
606
         compressed_block_index,
607
         value_32bit );
608
      }
609
#endif
610
0
      segment_data_offset += 4;
611
0
    }
612
0
    for( compressed_block_index = 1;
613
0
         compressed_block_index < data_handle->number_of_compressed_blocks;
614
0
         compressed_block_index++ )
615
0
    {
616
0
      byte_stream_copy_to_uint32_little_endian(
617
0
       &( data_handle->compressed_segment_data[ segment_data_offset ] ),
618
0
       compressed_block_offset );
619
620
#if defined( HAVE_DEBUG_OUTPUT )
621
      if( libcnotify_verbose != 0 )
622
      {
623
        libcnotify_printf(
624
         "%s: compressed block: % 2" PRIu32 " offset\t: 0x%08" PRIx32 " (0x%08" PRIx32 ")\n",
625
         function,
626
         compressed_block_index,
627
         compressed_block_offset,
628
         compressed_block_offset + compressed_descriptors_offset );
629
      }
630
#endif
631
0
      segment_data_offset += 4;
632
633
0
      compressed_block_offset += compressed_descriptors_offset;
634
635
0
      if( ( previous_compressed_block_offset > compressed_block_offset )
636
0
       || ( ( compressed_block_offset - previous_compressed_block_offset ) > (uint32_t) ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) ) )
637
0
      {
638
0
        libcerror_error_set(
639
0
         error,
640
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
641
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
642
0
         "%s: invalid compressed block offset: %" PRIu32 " (0x%08" PRIx32 ") value out of bounds.",
643
0
         function,
644
0
         compressed_block_offset,
645
0
         compressed_block_offset );
646
647
0
        goto on_error;
648
0
      }
649
0
      data_handle->compressed_block_offsets[ compressed_block_index ] = compressed_block_offset;
650
0
      previous_compressed_block_offset                                = compressed_block_offset;
651
652
0
      if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
653
0
      {
654
#if defined( HAVE_DEBUG_OUTPUT )
655
        if( libcnotify_verbose != 0 )
656
        {
657
          byte_stream_copy_to_uint32_little_endian(
658
           &( data_handle->compressed_segment_data[ segment_data_offset ] ),
659
           value_32bit );
660
          libcnotify_printf(
661
           "%s: compressed block: % 2" PRIu32 " size\t: %" PRIu32 "\n",
662
           function,
663
           compressed_block_index,
664
           value_32bit );
665
        }
666
#endif
667
0
        segment_data_offset += 4;
668
0
      }
669
0
    }
670
0
  }
671
0
  if( ( previous_compressed_block_offset > compressed_data_size )
672
0
   || ( ( compressed_data_size - previous_compressed_block_offset ) > (uint32_t) ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) ) )
673
0
  {
674
0
    libcerror_error_set(
675
0
     error,
676
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
677
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
678
0
     "%s: invalid compressed block offset: %" PRIu32 " (0x%08" PRIx32 ") value out of bounds.",
679
0
     function,
680
0
     previous_compressed_block_offset,
681
0
     previous_compressed_block_offset );
682
683
0
    goto on_error;
684
0
  }
685
0
  data_handle->compressed_block_offsets[ compressed_block_index ] = (uint32_t) compressed_data_size;
686
687
#if defined( HAVE_DEBUG_OUTPUT )
688
  if( libcnotify_verbose != 0 )
689
  {
690
    libcnotify_printf(
691
     "\n" );
692
  }
693
#endif
694
0
  if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
695
0
  {
696
0
    if( compressed_footer_size > (uint32_t) ( LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE + 1 ) )
697
0
    {
698
0
      libcerror_error_set(
699
0
       error,
700
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
701
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
702
0
       "%s: invalid compressed footer size value out of bounds.",
703
0
       function );
704
705
0
      goto on_error;
706
0
    }
707
0
    read_count = libfdata_stream_read_buffer_at_offset(
708
0
                  data_handle->compressed_data_stream,
709
0
                  (intptr_t *) file_io_handle,
710
0
                  data_handle->compressed_segment_data,
711
0
                  (size_t) compressed_footer_size,
712
0
                  (off64_t) compressed_footer_offset,
713
0
                  0,
714
0
                  error );
715
716
0
    if( read_count != (ssize_t) compressed_footer_size )
717
0
    {
718
0
      libcerror_error_set(
719
0
       error,
720
0
       LIBCERROR_ERROR_DOMAIN_IO,
721
0
       LIBCERROR_IO_ERROR_READ_FAILED,
722
0
       "%s: unable to read compressed footer data at offset: %" PRIu32 " (0x08%" PRIx32 ") from data stream.",
723
0
       function,
724
0
       compressed_footer_offset,
725
0
       compressed_footer_offset );
726
727
0
      goto on_error;
728
0
    }
729
#if defined( HAVE_DEBUG_OUTPUT )
730
    if( libcnotify_verbose != 0 )
731
    {
732
      libcnotify_printf(
733
       "%s: compressed footer data:\n",
734
       function );
735
      libcnotify_print_data(
736
       data_handle->compressed_segment_data,
737
       (size_t) compressed_footer_size,
738
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
739
    }
740
#endif
741
0
  }
742
0
  else if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_UNKNOWN5 )
743
0
  {
744
0
    if( compressed_data_size > (size64_t) SSIZE_MAX )
745
0
    {
746
0
      libcerror_error_set(
747
0
       error,
748
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
749
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
750
0
       "%s: invalid compressed data size value out of bounds.",
751
0
       function );
752
753
0
      goto on_error;
754
0
    }
755
0
    read_size = (size_t) compressed_data_size - 16;
756
757
0
    read_count = libfdata_stream_read_buffer_at_offset(
758
0
                  data_handle->compressed_data_stream,
759
0
                  (intptr_t *) file_io_handle,
760
0
                  data_handle->compressed_segment_data,
761
0
                  read_size,
762
0
                  16,
763
0
                  0,
764
0
                  error );
765
766
0
    if( read_count != (ssize_t) read_size )
767
0
    {
768
0
      libcerror_error_set(
769
0
       error,
770
0
       LIBCERROR_ERROR_DOMAIN_IO,
771
0
       LIBCERROR_IO_ERROR_READ_FAILED,
772
0
       "%s: unable to read unknown data at offset: 16 (0x00000010) from data stream.",
773
0
       function );
774
775
0
      goto on_error;
776
0
    }
777
#if defined( HAVE_DEBUG_OUTPUT )
778
    if( libcnotify_verbose != 0 )
779
    {
780
      libcnotify_printf(
781
       "%s: unknown data:\n",
782
       function );
783
      libcnotify_print_data(
784
       data_handle->compressed_segment_data,
785
       read_size,
786
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
787
    }
788
#endif
789
0
  }
790
0
  return( 1 );
791
792
0
on_error:
793
0
  if( data_handle->compressed_block_offsets != NULL )
794
0
  {
795
0
    memory_free(
796
0
     data_handle->compressed_block_offsets );
797
798
0
    data_handle->compressed_block_offsets = NULL;
799
0
  }
800
0
  return( -1 );
801
0
}
802
803
/* Reads data from the current offset into a compressed
804
 * Callback for the data stream
805
 * Returns the number of bytes read or -1 on error
806
 */
807
ssize_t libfsapfs_compressed_data_handle_read_segment_data(
808
         libfsapfs_compressed_data_handle_t *data_handle,
809
         intptr_t *file_io_handle,
810
         int segment_index,
811
         int segment_file_index LIBFSAPFS_ATTRIBUTE_UNUSED,
812
         uint8_t *segment_data,
813
         size_t segment_data_size,
814
         uint32_t segment_flags LIBFSAPFS_ATTRIBUTE_UNUSED,
815
         uint8_t read_flags LIBFSAPFS_ATTRIBUTE_UNUSED,
816
         libcerror_error_t **error )
817
0
{
818
0
  static char *function             = "libfsapfs_compressed_data_handle_read_segment_data";
819
0
  size_t data_offset                = 0;
820
0
  size_t read_size                  = 0;
821
0
  size_t segment_data_offset        = 0;
822
0
  ssize_t read_count                = 0;
823
0
  off64_t data_stream_offset        = 0;
824
0
  off64_t uncompressed_block_offset = 0;
825
0
  uint32_t compressed_block_index   = 0;
826
827
0
  LIBFSAPFS_UNREFERENCED_PARAMETER( file_io_handle )
828
0
  LIBFSAPFS_UNREFERENCED_PARAMETER( segment_file_index )
829
0
  LIBFSAPFS_UNREFERENCED_PARAMETER( segment_flags )
830
0
  LIBFSAPFS_UNREFERENCED_PARAMETER( read_flags )
831
832
0
  if( data_handle == NULL )
833
0
  {
834
0
    libcerror_error_set(
835
0
     error,
836
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
837
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
838
0
     "%s: invalid data handle.",
839
0
     function );
840
841
0
    return( -1 );
842
0
  }
843
0
  if( segment_index != 0 )
844
0
  {
845
0
    libcerror_error_set(
846
0
     error,
847
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
848
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
849
0
     "%s: invalid segment index value out of bounds.",
850
0
     function );
851
852
0
    return( -1 );
853
0
  }
854
0
  if( segment_data == NULL )
855
0
  {
856
0
    libcerror_error_set(
857
0
     error,
858
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
859
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
860
0
     "%s: invalid segment data.",
861
0
     function );
862
863
0
    return( -1 );
864
0
  }
865
0
  if( segment_data_size > (size_t) SSIZE_MAX )
866
0
  {
867
0
    libcerror_error_set(
868
0
     error,
869
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
870
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
871
0
     "%s: invalid segment data size value exceeds maximum.",
872
0
     function );
873
874
0
    return( -1 );
875
0
  }
876
0
  if( data_handle->compressed_block_offsets == NULL )
877
0
  {
878
0
    if( libfsapfs_compressed_data_handle_get_compressed_block_offsets(
879
0
         data_handle,
880
0
         (libbfio_handle_t *) file_io_handle,
881
0
         error ) != 1 )
882
0
    {
883
0
      libcerror_error_set(
884
0
       error,
885
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
886
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
887
0
       "%s: unable to determine compressed block offsets.",
888
0
       function );
889
890
0
      return( -1 );
891
0
    }
892
0
  }
893
0
  if( (size64_t) data_handle->current_segment_offset >= data_handle->uncompressed_data_size )
894
0
  {
895
0
    return( 0 );
896
0
  }
897
0
  if( data_handle->compression_method == LIBFSAPFS_COMPRESSION_METHOD_UNKNOWN5 )
898
0
  {
899
0
    if( (size64_t) segment_data_size > ( data_handle->uncompressed_data_size - data_handle->current_segment_offset ) )
900
0
    {
901
0
      read_size = (size_t) ( data_handle->uncompressed_data_size - data_handle->current_segment_offset );
902
0
    }
903
0
    else
904
0
    {
905
0
      read_size = segment_data_size;
906
0
    }
907
0
    if( memory_set(
908
0
         segment_data,
909
0
         0,
910
0
         read_size ) == NULL )
911
0
    {
912
0
      libcerror_error_set(
913
0
       error,
914
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
915
0
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
916
0
       "%s: unable to clear segment data.",
917
0
       function );
918
919
0
      return( -1 );
920
0
    }
921
0
    data_handle->current_segment_offset += read_size;
922
923
0
    return( (ssize_t) read_size );
924
0
  }
925
0
  compressed_block_index = (uint32_t) ( data_handle->current_segment_offset / LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE );
926
0
  segment_data_offset    = 0;
927
0
  data_offset            = (size_t) ( data_handle->current_segment_offset % LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE );
928
929
0
  while( segment_data_size > 0 )
930
0
  {
931
0
    if( compressed_block_index >= data_handle->number_of_compressed_blocks )
932
0
    {
933
0
      libcerror_error_set(
934
0
       error,
935
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
936
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
937
0
       "%s: invalid compressed block index value out of bounds.",
938
0
       function );
939
940
0
      return( -1 );
941
0
    }
942
0
    if( data_handle->current_compressed_block_index != compressed_block_index )
943
0
    {
944
0
      data_stream_offset = data_handle->compressed_block_offsets[ compressed_block_index ];
945
0
      read_size          = (size_t) ( data_handle->compressed_block_offsets[ compressed_block_index + 1 ] - data_stream_offset );
946
947
0
      read_count = libfdata_stream_read_buffer_at_offset(
948
0
                    data_handle->compressed_data_stream,
949
0
                    (intptr_t *) file_io_handle,
950
0
                    (uint8_t *) data_handle->compressed_segment_data,
951
0
                    read_size,
952
0
                    data_stream_offset,
953
0
                    0,
954
0
                    error );
955
956
0
      if( read_count != (ssize_t) read_size )
957
0
      {
958
0
        libcerror_error_set(
959
0
         error,
960
0
         LIBCERROR_ERROR_DOMAIN_IO,
961
0
         LIBCERROR_IO_ERROR_READ_FAILED,
962
0
         "%s: unable to read buffer at offset: %" PRIi64 " (0x08%" PRIx64 ") from data stream.",
963
0
         function,
964
0
         data_stream_offset,
965
0
         data_stream_offset );
966
967
0
        return( -1 );
968
0
      }
969
#if defined( HAVE_DEBUG_OUTPUT )
970
      if( libcnotify_verbose != 0 )
971
      {
972
        libcnotify_printf(
973
         "%s: compressed block data:\n",
974
         function );
975
        libcnotify_print_data(
976
         data_handle->compressed_segment_data,
977
         read_size,
978
         LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
979
      }
980
#endif
981
0
      data_handle->segment_data_size = LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE;
982
983
0
      if( libfsapfs_decompress_data(
984
0
           data_handle->compressed_segment_data,
985
0
           (size_t) read_count,
986
0
           data_handle->compression_method,
987
0
           data_handle->segment_data,
988
0
           &( data_handle->segment_data_size ),
989
0
           error ) != 1 )
990
0
      {
991
0
        libcerror_error_set(
992
0
         error,
993
0
         LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
994
0
         LIBCERROR_ENCRYPTION_ERROR_GENERIC,
995
0
         "%s: unable to decompress data.",
996
0
         function );
997
998
0
        return( -1 );
999
0
      }
1000
#if defined( HAVE_DEBUG_OUTPUT )
1001
      if( libcnotify_verbose != 0 )
1002
      {
1003
        libcnotify_printf(
1004
         "%s: uncompressed block data:\n",
1005
         function );
1006
        libcnotify_print_data(
1007
         data_handle->segment_data,
1008
         data_handle->segment_data_size,
1009
         LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1010
      }
1011
#endif
1012
0
      uncompressed_block_offset = ( compressed_block_index + 1 ) * LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE;
1013
1014
0
      if( ( (size64_t) uncompressed_block_offset < data_handle->uncompressed_data_size )
1015
0
       && ( data_handle->segment_data_size != LIBFSAPFS_COMPRESSED_DATA_HANDLE_BLOCK_SIZE ) )
1016
0
      {
1017
0
        libcerror_error_set(
1018
0
         error,
1019
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1020
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1021
0
         "%s: invalid uncompressed segment data size value out of bounds.",
1022
0
         function );
1023
1024
0
        return( -1 );
1025
0
      }
1026
0
      data_handle->current_compressed_block_index = compressed_block_index;
1027
0
    }
1028
0
    if( data_offset >= data_handle->segment_data_size )
1029
0
    {
1030
0
      libcerror_error_set(
1031
0
       error,
1032
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1033
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1034
0
       "%s: invalid data offset value out of bounds.",
1035
0
       function );
1036
1037
0
      return( -1 );
1038
0
    }
1039
0
    read_size = data_handle->segment_data_size - data_offset;
1040
1041
0
    if( read_size > segment_data_size )
1042
0
    {
1043
0
      read_size = segment_data_size;
1044
0
    }
1045
0
    if( memory_copy(
1046
0
         &( segment_data[ segment_data_offset ] ),
1047
0
         &( data_handle->segment_data[ data_offset ] ),
1048
0
         read_size ) == NULL )
1049
0
    {
1050
0
      libcerror_error_set(
1051
0
       error,
1052
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
1053
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
1054
0
       "%s: unable to copy data.",
1055
0
       function );
1056
1057
0
      return( -1 );
1058
0
    }
1059
0
    data_offset          = 0;
1060
0
    segment_data_size   -= read_size;
1061
0
    segment_data_offset += read_size;
1062
1063
0
    compressed_block_index++;
1064
0
  }
1065
0
  data_handle->current_segment_offset += segment_data_offset;
1066
1067
0
  return( (ssize_t) segment_data_offset );
1068
0
}
1069
1070
/* Seeks a certain offset of the data
1071
 * Callback for the data stream
1072
 * Returns the offset if seek is successful or -1 on error
1073
 */
1074
off64_t libfsapfs_compressed_data_handle_seek_segment_offset(
1075
         libfsapfs_compressed_data_handle_t *data_handle,
1076
         intptr_t *file_io_handle LIBFSAPFS_ATTRIBUTE_UNUSED,
1077
         int segment_index,
1078
         int segment_file_index LIBFSAPFS_ATTRIBUTE_UNUSED,
1079
         off64_t segment_offset,
1080
         libcerror_error_t **error )
1081
0
{
1082
0
  static char *function = "libfsapfs_compressed_data_handle_seek_segment_offset";
1083
1084
0
  LIBFSAPFS_UNREFERENCED_PARAMETER( file_io_handle )
1085
0
  LIBFSAPFS_UNREFERENCED_PARAMETER( segment_file_index )
1086
1087
0
  if( data_handle == NULL )
1088
0
  {
1089
0
    libcerror_error_set(
1090
0
     error,
1091
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1092
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1093
0
     "%s: invalid data handle.",
1094
0
     function );
1095
1096
0
    return( -1 );
1097
0
  }
1098
0
  if( segment_index != 0 )
1099
0
  {
1100
0
    libcerror_error_set(
1101
0
     error,
1102
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1103
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1104
0
     "%s: invalid segment index value out of bounds.",
1105
0
     function );
1106
1107
0
    return( -1 );
1108
0
  }
1109
0
  if( segment_offset < 0 )
1110
0
  {
1111
0
    libcerror_error_set(
1112
0
     error,
1113
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1114
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1115
0
     "%s: invalid segment offset value out of bounds.",
1116
0
     function );
1117
1118
0
    return( -1 );
1119
0
  }
1120
0
  data_handle->current_segment_offset = segment_offset;
1121
1122
0
  return( segment_offset );
1123
0
}
1124