Coverage Report

Created: 2024-02-25 07:19

/src/libqcow/libqcow/libqcow_compression.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Compression functions
3
 *
4
 * Copyright (c) 2010, 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 <file_stream.h>
25
#include <memory.h>
26
#include <types.h>
27
28
#if defined( HAVE_STDLIB_H ) || defined( WINAPI )
29
#include <stdlib.h>
30
#endif
31
32
#if defined( HAVE_ZLIB ) || defined( ZLIB_DLL )
33
#include <zlib.h>
34
#endif
35
36
#include "libqcow_compression.h"
37
#include "libqcow_definitions.h"
38
#include "libqcow_deflate.h"
39
#include "libqcow_libcerror.h"
40
#include "libqcow_libcnotify.h"
41
42
/* Decompresses data using the compression method
43
 * Returns 1 on success, 0 on failure or -1 on error
44
 */
45
int libqcow_decompress_data(
46
     const uint8_t *compressed_data,
47
     size_t compressed_data_size,
48
     uint16_t compression_method,
49
     uint8_t *uncompressed_data,
50
     size_t *uncompressed_data_size,
51
     libcerror_error_t **error )
52
0
{
53
0
  static char *function = "libqcow_decompress_data";
54
0
  int result            = 0;
55
56
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_INFLATE ) ) || defined( ZLIB_DLL )
57
  z_stream zlib_stream;
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 == LIBQCOW_COMPRESSION_METHOD_DEFLATE )
105
0
  {
106
#if ( defined( HAVE_ZLIB ) && defined( HAVE_ZLIB_INFLATE ) ) || defined( ZLIB_DLL )
107
    if( compressed_data_size > (size_t) ULONG_MAX )
108
    {
109
      libcerror_error_set(
110
       error,
111
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
112
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
113
       "%s: invalid compressed data size value exceeds maximum.",
114
       function );
115
116
      return( -1 );
117
    }
118
    if( *uncompressed_data_size > (size_t) ULONG_MAX )
119
    {
120
      libcerror_error_set(
121
       error,
122
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
123
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
124
       "%s: invalid uncompressed data size value exceeds maximum.",
125
       function );
126
127
      return( -1 );
128
    }
129
    if( memory_set(
130
         &zlib_stream,
131
         0,
132
         sizeof( z_stream ) ) == NULL )
133
    {
134
      libcerror_error_set(
135
       error,
136
       LIBCERROR_ERROR_DOMAIN_MEMORY,
137
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
138
       "%s: unable to clear zlib stream.",
139
       function );
140
141
      return( -1 );
142
    }
143
    zlib_stream.next_in   = (Bytef *) compressed_data;
144
    zlib_stream.avail_in  = (uInt) compressed_data_size;
145
    zlib_stream.next_out  = (Bytef *) uncompressed_data;
146
    zlib_stream.avail_out = (uInt) *uncompressed_data_size;
147
148
#if defined( HAVE_ZLIB_INFLATE_INIT2 ) || defined( ZLIB_DLL )
149
    result = inflateInit2(
150
              &zlib_stream,
151
              -12 );
152
#else
153
    result = _inflateInit2(
154
              &zlib_stream,
155
              -12 );
156
#endif
157
    if( result != Z_OK )
158
    {
159
      libcerror_error_set(
160
       error,
161
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
162
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
163
       "%s: unable to initialize zlib stream.",
164
       function );
165
166
      return( -1 );
167
    }
168
    result = inflate(
169
              &zlib_stream,
170
              Z_FINISH );
171
172
    if( result == Z_STREAM_END )
173
    {
174
      *uncompressed_data_size = (size_t) zlib_stream.total_out;
175
176
      result = 1;
177
    }
178
    else if( result == Z_DATA_ERROR )
179
    {
180
#if defined( HAVE_DEBUG_OUTPUT )
181
      if( libcnotify_verbose != 0 )
182
      {
183
        libcnotify_printf(
184
         "%s: unable to read compressed data: data error.\n",
185
         function );
186
      }
187
#endif
188
      *uncompressed_data_size = 0;
189
190
      result = -1;
191
    }
192
    else if( result == Z_BUF_ERROR )
193
    {
194
#if defined( HAVE_DEBUG_OUTPUT )
195
      if( libcnotify_verbose != 0 )
196
      {
197
        libcnotify_printf(
198
        "%s: unable to read compressed data: target buffer too small.\n",
199
         function );
200
      }
201
#endif
202
      /* Estimate that a factor 2 enlargement should suffice
203
       */
204
      *uncompressed_data_size *= 2;
205
206
      result = 0;
207
    }
208
    else if( result == Z_MEM_ERROR )
209
    {
210
      libcerror_error_set(
211
       error,
212
       LIBCERROR_ERROR_DOMAIN_MEMORY,
213
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
214
       "%s: unable to read compressed data: insufficient memory.",
215
       function );
216
217
      *uncompressed_data_size = 0;
218
219
      result = -1;
220
    }
221
    else
222
    {
223
      libcerror_error_set(
224
       error,
225
       LIBCERROR_ERROR_DOMAIN_COMPRESSION,
226
       LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
227
       "%s: zlib returned undefined error: %d.",
228
       function,
229
       result );
230
231
      *uncompressed_data_size = 0;
232
233
      result = -1;
234
    }
235
    if( result == -1 )
236
    {
237
      inflateEnd(
238
       &zlib_stream );
239
    }
240
    else
241
    {
242
      if( inflateEnd(
243
           &zlib_stream ) != Z_OK )
244
      {
245
        libcerror_error_set(
246
         error,
247
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
248
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
249
         "%s: unable to finalize zlib stream.",
250
         function );
251
252
        return( -1 );
253
      }
254
    }
255
#else
256
0
    result = libqcow_deflate_decompress(
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_INFLATE ) ) || defined( ZLIB_DLL ) */
275
0
  }
276
0
  else
277
0
  {
278
0
    libcerror_error_set(
279
0
     error,
280
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
281
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
282
0
     "%s: unsupported compression method.",
283
0
     function );
284
285
0
    return( -1 );
286
0
  }
287
0
  return( result );
288
0
}
289