Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsapfs/libfsapfs/libfsapfs_compression.c
Line
Count
Source
1
/*
2
 * Compression functions
3
 *
4
 * Copyright (C) 2018-2026, 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
0
  uint8_t uncompressed_data_marker   = 0;
55
56
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
57
  uLongf zlib_uncompressed_data_size = 0;
58
#endif
59
60
0
  if( compressed_data == NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
65
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
66
0
     "%s: invalid compressed data buffer.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
0
  if( uncompressed_data == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
77
0
     "%s: invalid uncompressed data buffer.",
78
0
     function );
79
80
0
    return( -1 );
81
0
  }
82
0
  if( uncompressed_data == compressed_data )
83
0
  {
84
0
    libcerror_error_set(
85
0
     error,
86
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
87
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
88
0
     "%s: invalid compressed data buffer equals uncompressed data buffer.",
89
0
     function );
90
91
0
    return( -1 );
92
0
  }
93
0
  if( uncompressed_data_size == NULL )
94
0
  {
95
0
    libcerror_error_set(
96
0
     error,
97
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
98
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
99
0
     "%s: invalid uncompressed data size.",
100
0
     function );
101
102
0
    return( -1 );
103
0
  }
104
0
  if( ( compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
105
0
   || ( compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZFSE ) )
106
0
  {
107
0
    uncompressed_data_marker = 0xff;
108
0
  }
109
0
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZVN )
110
0
  {
111
0
    uncompressed_data_marker = 0x06;
112
0
  }
113
0
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_RAW )
114
0
  {
115
0
    uncompressed_data_marker = 0xcc;
116
0
  }
117
0
  if( ( uncompressed_data_marker != 0 )
118
0
   && ( compressed_data_size >= 1 )
119
0
   && ( compressed_data[ 0 ] == uncompressed_data_marker ) )
120
0
  {
121
0
    if( compressed_data_size > (size_t) SSIZE_MAX )
122
0
    {
123
0
      libcerror_error_set(
124
0
       error,
125
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
126
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
127
0
       "%s: invalid compressed data size value exceeds maximum.",
128
0
       function );
129
130
0
      return( -1 );
131
0
    }
132
0
    if( *uncompressed_data_size > (size_t) SSIZE_MAX )
133
0
    {
134
0
      libcerror_error_set(
135
0
       error,
136
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
137
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
138
0
       "%s: invalid uncompressed data size value exceeds maximum.",
139
0
       function );
140
141
0
      return( -1 );
142
0
    }
143
0
    if( ( compressed_data_size - 1 ) > *uncompressed_data_size )
144
0
    {
145
0
      libcerror_error_set(
146
0
       error,
147
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
148
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
149
0
       "%s: compressed data size value exceeds uncompressed data size.",
150
0
       function );
151
152
0
      return( -1 );
153
0
    }
154
0
    *uncompressed_data_size = compressed_data_size - 1;
155
156
0
    if( memory_copy(
157
0
         uncompressed_data,
158
0
         &( compressed_data[ 1 ] ),
159
0
         *uncompressed_data_size ) == NULL )
160
0
    {
161
0
      libcerror_error_set(
162
0
       error,
163
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
164
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
165
0
       "%s: unable to copy compressed to uncompressed data.",
166
0
       function );
167
168
0
      return( -1 );
169
0
    }
170
0
    return( 1 );
171
0
  }
172
0
  if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_DEFLATE )
173
0
  {
174
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL )
175
    if( compressed_data_size > (size_t) ULONG_MAX )
176
    {
177
      libcerror_error_set(
178
       error,
179
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
180
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
181
       "%s: invalid compressed data size value exceeds maximum.",
182
       function );
183
184
      return( -1 );
185
    }
186
    if( *uncompressed_data_size > (size_t) ULONG_MAX )
187
    {
188
      libcerror_error_set(
189
       error,
190
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
191
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
192
       "%s: invalid uncompressed data size value exceeds maximum.",
193
       function );
194
195
      return( -1 );
196
    }
197
    zlib_uncompressed_data_size = (uLongf) *uncompressed_data_size;
198
199
    result = uncompress(
200
        (Bytef *) uncompressed_data,
201
        &zlib_uncompressed_data_size,
202
        (Bytef *) compressed_data,
203
        (uLong) compressed_data_size );
204
205
    if( result == Z_OK )
206
    {
207
      *uncompressed_data_size = (size_t) zlib_uncompressed_data_size;
208
209
      result = 1;
210
    }
211
    else if( result == Z_DATA_ERROR )
212
    {
213
#if defined( HAVE_DEBUG_OUTPUT )
214
      if( libcnotify_verbose != 0 )
215
      {
216
        libcnotify_printf(
217
         "%s: unable to read compressed data: data error.\n",
218
         function );
219
      }
220
#endif
221
      *uncompressed_data_size = 0;
222
223
      result = -1;
224
    }
225
    else if( result == Z_BUF_ERROR )
226
    {
227
#if defined( HAVE_DEBUG_OUTPUT )
228
      if( libcnotify_verbose != 0 )
229
      {
230
        libcnotify_printf(
231
        "%s: unable to read compressed data: target buffer too small.\n",
232
         function );
233
      }
234
#endif
235
      /* Estimate that a factor 2 enlargement should suffice
236
       */
237
      *uncompressed_data_size *= 2;
238
239
      result = 0;
240
    }
241
    else if( result == Z_MEM_ERROR )
242
    {
243
      libcerror_error_set(
244
       error,
245
       LIBCERROR_ERROR_DOMAIN_MEMORY,
246
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
247
       "%s: unable to read compressed data: insufficient memory.",
248
       function );
249
250
      *uncompressed_data_size = 0;
251
252
      result = -1;
253
    }
254
    else
255
    {
256
      libcerror_error_set(
257
       error,
258
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
259
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
260
       "%s: zlib returned undefined error: %d.",
261
       function,
262
       result );
263
264
      *uncompressed_data_size = 0;
265
266
      result = -1;
267
    }
268
#else
269
0
    result = libfsapfs_deflate_decompress_zlib(
270
0
        compressed_data,
271
0
        compressed_data_size,
272
0
        uncompressed_data,
273
0
        uncompressed_data_size,
274
0
        error );
275
276
0
    if( result != 1 )
277
0
    {
278
0
      libcerror_error_set(
279
0
       error,
280
0
       LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
281
0
       LIBCERROR_ENCRYPTION_ERROR_GENERIC,
282
0
       "%s: unable to decompress DEFLATE compressed data.",
283
0
       function );
284
285
0
      return( -1 );
286
0
    }
287
0
#endif /* ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_UNCOMPRESS ) ) || defined( ZLIB_DLL ) */
288
0
  }
289
0
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZFSE )
290
0
  {
291
0
    result = libfmos_lzfse_decompress(
292
0
              compressed_data,
293
0
              compressed_data_size,
294
0
              uncompressed_data,
295
0
              uncompressed_data_size,
296
0
              error );
297
298
0
    if( result != 1 )
299
0
    {
300
0
      libcerror_error_set(
301
0
       error,
302
0
       LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
303
0
       LIBCERROR_ENCRYPTION_ERROR_GENERIC,
304
0
       "%s: unable to decompress LZFSE compressed data.",
305
0
       function );
306
307
0
      return( -1 );
308
0
    }
309
0
  }
310
0
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_LZVN )
311
0
  {
312
0
    result = libfmos_lzvn_decompress(
313
0
        compressed_data,
314
0
        compressed_data_size,
315
0
        uncompressed_data,
316
0
        uncompressed_data_size,
317
0
        error );
318
319
0
    if( result != 1 )
320
0
    {
321
0
      libcerror_error_set(
322
0
       error,
323
0
       LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
324
0
       LIBCERROR_ENCRYPTION_ERROR_GENERIC,
325
0
       "%s: unable to decompress LZVN compressed data.",
326
0
       function );
327
328
0
      return( -1 );
329
0
    }
330
0
  }
331
0
  else if( compression_method == LIBFSAPFS_COMPRESSION_METHOD_RAW )
332
0
  {
333
0
    libcerror_error_set(
334
0
     error,
335
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
337
0
     "%s: invalid raw compressed data - unsupported marker byte.",
338
0
     function );
339
340
0
    return( -1 );
341
0
  }
342
0
  else
343
0
  {
344
0
    libcerror_error_set(
345
0
     error,
346
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
347
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
348
0
     "%s: unsupported compression method.",
349
0
     function );
350
351
0
    return( -1 );
352
0
  }
353
0
  return( result );
354
0
}
355