Coverage Report

Created: 2025-06-13 07:22

/src/libfsapfs/libfsapfs/libfsapfs_compression.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Compression 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 <memory.h>
24
#include <types.h>
25
26
#if defined( HAVE_STDLIB_H ) || defined( WINAPI )
27
#include <stdlib.h>
28
#endif
29
30
#if defined( HAVE_ZLIB ) || defined( ZLIB_DLL )
31
#include <zlib.h>
32
#endif
33
34
#include "libfsapfs_compression.h"
35
#include "libfsapfs_definitions.h"
36
#include "libfsapfs_deflate.h"
37
#include "libfsapfs_libcerror.h"
38
#include "libfsapfs_libcnotify.h"
39
#include "libfsapfs_libfmos.h"
40
41
/* Decompresses data using the compression method
42
 * Returns 1 on success, 0 on failure or -1 on error
43
 */
44
int libfsapfs_decompress_data(
45
     const uint8_t *compressed_data,
46
     size_t compressed_data_size,
47
     int compression_method,
48
     uint8_t *uncompressed_data,
49
     size_t *uncompressed_data_size,
50
     libcerror_error_t **error )
51
0
{
52
0
  static char *function              = "libfsapfs_decompress_data";
53
0
  int result                         = 0;
54
55
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
56
  uLongf zlib_uncompressed_data_size = 0;
57
#endif
58
59
0
  if( compressed_data == NULL )
60
0
  {
61
0
    libcerror_error_set(
62
0
     error,
63
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
64
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
65
0
     "%s: invalid compressed data buffer.",
66
0
     function );
67
68
0
    return( -1 );
69
0
  }
70
0
  if( uncompressed_data == NULL )
71
0
  {
72
0
    libcerror_error_set(
73
0
     error,
74
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
75
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
76
0
     "%s: invalid uncompressed data buffer.",
77
0
     function );
78
79
0
    return( -1 );
80
0
  }
81
0
  if( uncompressed_data == compressed_data )
82
0
  {
83
0
    libcerror_error_set(
84
0
     error,
85
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
86
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
87
0
     "%s: invalid compressed data buffer equals uncompressed data buffer.",
88
0
     function );
89
90
0
    return( -1 );
91
0
  }
92
0
  if( uncompressed_data_size == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
97
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
98
0
     "%s: invalid uncompressed data size.",
99
0
     function );
100
101
0
    return( -1 );
102
0
  }
103
0
  if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
104
0
  {
105
0
    if( ( compressed_data_size >= 1 )
106
0
     && ( compressed_data[ 0 ] == 0xff ) )
107
0
    {
108
0
      if( compressed_data_size > (size_t) SSIZE_MAX )
109
0
      {
110
0
        libcerror_error_set(
111
0
         error,
112
0
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
113
0
         LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
114
0
         "%s: invalid compressed data size value exceeds maximum.",
115
0
         function );
116
117
0
        return( -1 );
118
0
      }
119
0
      if( *uncompressed_data_size > (size_t) SSIZE_MAX )
120
0
      {
121
0
        libcerror_error_set(
122
0
         error,
123
0
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
124
0
         LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
125
0
         "%s: invalid uncompressed data size value exceeds maximum.",
126
0
         function );
127
128
0
        return( -1 );
129
0
      }
130
0
      if( ( compressed_data_size - 1 ) > *uncompressed_data_size )
131
0
      {
132
0
        libcerror_error_set(
133
0
         error,
134
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
135
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
136
0
         "%s: compressed data size value exceeds uncompressed data size.",
137
0
         function );
138
139
0
        return( -1 );
140
0
      }
141
0
      *uncompressed_data_size = compressed_data_size - 1;
142
143
0
      if( memory_copy(
144
0
           uncompressed_data,
145
0
           &( compressed_data[ 1 ] ),
146
0
           *uncompressed_data_size ) == NULL )
147
0
      {
148
0
        libcerror_error_set(
149
0
         error,
150
0
         LIBCERROR_ERROR_DOMAIN_MEMORY,
151
0
         LIBCERROR_MEMORY_ERROR_COPY_FAILED,
152
0
         "%s: unable to compressed to uncompressed data.",
153
0
         function );
154
155
0
        return( -1 );
156
0
      }
157
0
      result = 1;
158
0
    }
159
0
    else
160
0
    {
161
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
162
      if( compressed_data_size > (size_t) ULONG_MAX )
163
      {
164
        libcerror_error_set(
165
         error,
166
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
167
         LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
168
         "%s: invalid compressed data size value exceeds maximum.",
169
         function );
170
171
        return( -1 );
172
      }
173
      if( *uncompressed_data_size > (size_t) ULONG_MAX )
174
      {
175
        libcerror_error_set(
176
         error,
177
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
178
         LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
179
         "%s: invalid uncompressed data size value exceeds maximum.",
180
         function );
181
182
        return( -1 );
183
      }
184
      zlib_uncompressed_data_size = (uLongf) *uncompressed_data_size;
185
186
      result = uncompress(
187
          (Bytef *) uncompressed_data,
188
          &zlib_uncompressed_data_size,
189
          (Bytef *) compressed_data,
190
          (uLong) compressed_data_size );
191
192
      if( result == Z_OK )
193
      {
194
        *uncompressed_data_size = (size_t) zlib_uncompressed_data_size;
195
196
        result = 1;
197
      }
198
      else if( result == Z_DATA_ERROR )
199
      {
200
#if defined( HAVE_DEBUG_OUTPUT )
201
        if( libcnotify_verbose != 0 )
202
        {
203
          libcnotify_printf(
204
           "%s: unable to read compressed data: data error.\n",
205
           function );
206
        }
207
#endif
208
        *uncompressed_data_size = 0;
209
210
        result = -1;
211
      }
212
      else if( result == Z_BUF_ERROR )
213
      {
214
#if defined( HAVE_DEBUG_OUTPUT )
215
        if( libcnotify_verbose != 0 )
216
        {
217
          libcnotify_printf(
218
          "%s: unable to read compressed data: target buffer too small.\n",
219
           function );
220
        }
221
#endif
222
        /* Estimate that a factor 2 enlargement should suffice
223
         */
224
        *uncompressed_data_size *= 2;
225
226
        result = 0;
227
      }
228
      else if( result == Z_MEM_ERROR )
229
      {
230
        libcerror_error_set(
231
         error,
232
         LIBCERROR_ERROR_DOMAIN_MEMORY,
233
         LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
234
         "%s: unable to read compressed data: insufficient memory.",
235
         function );
236
237
        *uncompressed_data_size = 0;
238
239
        result = -1;
240
      }
241
      else
242
      {
243
        libcerror_error_set(
244
         error,
245
         LIBCERROR_ERROR_DOMAIN_COMPRESSION,
246
         LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
247
         "%s: zlib returned undefined error: %d.",
248
         function,
249
         result );
250
251
        *uncompressed_data_size = 0;
252
253
        result = -1;
254
      }
255
#else
256
0
      result = libfsapfs_deflate_decompress_zlib(
257
0
                compressed_data,
258
0
                compressed_data_size,
259
0
                uncompressed_data,
260
0
                uncompressed_data_size,
261
0
                error );
262
263
0
      if( result != 1 )
264
0
      {
265
0
        libcerror_error_set(
266
0
         error,
267
0
         LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
268
0
         LIBCERROR_ENCRYPTION_ERROR_GENERIC,
269
0
         "%s: unable to decompress DEFLATE compressed data.",
270
0
         function );
271
272
0
        return( -1 );
273
0
      }
274
0
#endif /* ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL ) */
275
0
    }
276
0
  }
277
#ifdef TODO
278
/* TODO need sample data */
279
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZFSE )
280
  {
281
    result = libfmos_lzfse_decompress(
282
              compressed_data,
283
              compressed_data_size,
284
              uncompressed_data,
285
              uncompressed_data_size,
286
              error );
287
288
    if( result != 1 )
289
    {
290
      libcerror_error_set(
291
       error,
292
       LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
293
       LIBCERROR_ENCRYPTION_ERROR_GENERIC,
294
       "%s: unable to decompress LZFSE compressed data.",
295
       function );
296
297
      return( -1 );
298
    }
299
  }
300
#endif /* TODO */
301
0
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZVN )
302
0
  {
303
0
    if( ( compressed_data_size >= 1 )
304
0
     && ( compressed_data[ 0 ] == 0x06 ) )
305
0
    {
306
0
      if( compressed_data_size > (size_t) SSIZE_MAX )
307
0
      {
308
0
        libcerror_error_set(
309
0
         error,
310
0
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
311
0
         LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
312
0
         "%s: invalid compressed data size value exceeds maximum.",
313
0
         function );
314
315
0
        return( -1 );
316
0
      }
317
0
      if( *uncompressed_data_size > (size_t) SSIZE_MAX )
318
0
      {
319
0
        libcerror_error_set(
320
0
         error,
321
0
         LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
322
0
         LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
323
0
         "%s: invalid uncompressed data size value exceeds maximum.",
324
0
         function );
325
326
0
        return( -1 );
327
0
      }
328
0
      if( ( compressed_data_size - 1 ) > *uncompressed_data_size )
329
0
      {
330
0
        libcerror_error_set(
331
0
         error,
332
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
333
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
334
0
         "%s: compressed data size value exceeds uncompressed data size.",
335
0
         function );
336
337
0
        return( -1 );
338
0
      }
339
0
      *uncompressed_data_size = compressed_data_size - 1;
340
341
0
      if( memory_copy(
342
0
           uncompressed_data,
343
0
           &( compressed_data[ 1 ] ),
344
0
           *uncompressed_data_size ) == NULL )
345
0
      {
346
0
        libcerror_error_set(
347
0
         error,
348
0
         LIBCERROR_ERROR_DOMAIN_MEMORY,
349
0
         LIBCERROR_MEMORY_ERROR_COPY_FAILED,
350
0
         "%s: unable to compressed to uncompressed data.",
351
0
         function );
352
353
0
        return( -1 );
354
0
      }
355
0
      result = 1;
356
0
    }
357
0
    else
358
0
    {
359
0
      result = libfmos_lzvn_decompress(
360
0
                compressed_data,
361
0
                compressed_data_size,
362
0
                uncompressed_data,
363
0
                uncompressed_data_size,
364
0
                error );
365
366
0
      if( result != 1 )
367
0
      {
368
0
        libcerror_error_set(
369
0
         error,
370
0
         LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
371
0
         LIBCERROR_ENCRYPTION_ERROR_GENERIC,
372
0
         "%s: unable to decompress LZVN compressed data.",
373
0
         function );
374
375
0
        return( -1 );
376
0
      }
377
0
    }
378
0
  }
379
0
  else
380
0
  {
381
0
    libcerror_error_set(
382
0
     error,
383
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
384
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
385
0
     "%s: unsupported compression method.",
386
0
     function );
387
388
0
    return( -1 );
389
0
  }
390
0
  return( result );
391
0
}
392