]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/stream_decoder.c
Plugged a memory leak in stream_decoder.c.
[icculus/xz.git] / src / liblzma / common / stream_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       stream_decoder.c
4 /// \brief      Decodes .lzma Streams
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This library 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 GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "stream_common.h"
21 #include "check.h"
22 #include "stream_flags_decoder.h"
23 #include "block_decoder.h"
24 #include "metadata_decoder.h"
25
26
27 struct lzma_coder_s {
28         enum {
29                 SEQ_STREAM_HEADER_CODE,
30                 SEQ_BLOCK_HEADER_INIT,
31                 SEQ_BLOCK_HEADER_CODE,
32                 SEQ_METADATA_CODE,
33                 SEQ_DATA_CODE,
34                 SEQ_STREAM_TAIL_INIT,
35                 SEQ_STREAM_TAIL_CODE,
36         } sequence;
37
38         /// Position in variable-length integers and in some other things.
39         size_t pos;
40
41         /// Block or Metadata decoder. This takes little memory and the same
42         /// data structure can be used to decode every Block Header, so it's
43         /// a good idea to have a separate lzma_next_coder structure for it.
44         lzma_next_coder block_decoder;
45
46         /// Block Header decoder; this is separate
47         lzma_next_coder block_header_decoder;
48
49         lzma_options_block block_options;
50
51         /// Information about the sizes of the Blocks
52         lzma_info *info;
53
54         /// Current Block in *info
55         lzma_info_iter iter;
56
57         /// Number of bytes not yet processed from Data Blocks in the Stream.
58         /// This can be LZMA_VLI_VALUE_UNKNOWN. If it is known, it is
59         /// decremented while decoding and verified to match the reality.
60         lzma_vli total_left;
61
62         /// Like uncompressed_left above but for uncompressed data from
63         /// Data Blocks.
64         lzma_vli uncompressed_left;
65
66         /// Stream Flags from Stream Header
67         lzma_stream_flags header_flags;
68
69         /// Stream Flags from Stream tail
70         lzma_stream_flags tail_flags;
71
72         /// Decoder for Stream Header and Stream tail. This takes very
73         /// little memory and the same data structure can be used for
74         /// both Header and tail, so it's a good idea to have a separate
75         /// lzma_next_coder structure for it.
76         lzma_next_coder flags_decoder;
77
78         /// Temporary destination for the decoded Metadata.
79         lzma_metadata metadata;
80
81         /// Pointer to application-supplied pointer where to store the list
82         /// of Extra Records from the Header Metadata Block.
83         lzma_extra **header_extra;
84
85         /// Same as above but Footer Metadata Block
86         lzma_extra **footer_extra;
87 };
88
89
90 static lzma_ret
91 metadata_init(lzma_coder *coder, lzma_allocator *allocator)
92 {
93         assert(coder->metadata.index == NULL);
94         assert(coder->metadata.extra == NULL);
95
96         // Single-Block Streams don't have Metadata Blocks.
97         if (!coder->header_flags.is_multi)
98                 return LZMA_DATA_ERROR;
99
100         coder->block_options.total_limit = LZMA_VLI_VALUE_UNKNOWN;
101
102         // Limit the Uncompressed Size of a Metadata Block. This is to
103         // prevent security issues where input file would have very huge
104         // Metadata.
105         //
106         // FIXME: Hardcoded constant is ugly. Maybe we should provide
107         // some way to specify this from the application.
108         coder->block_options.uncompressed_limit = LZMA_VLI_C(1) << 23;
109
110         lzma_info_size size_type;
111         bool want_extra;
112
113         // If we haven't decoded any Data Blocks yet, this is Header
114         // Metadata Block.
115         if (lzma_info_index_count_get(coder->info) == 0) {
116                 coder->block_options.has_backward_size = false;
117                 coder->block_options.handle_padding = true;
118                 size_type = LZMA_INFO_HEADER_METADATA;
119                 want_extra = coder->header_extra != NULL;
120         } else {
121                 if (lzma_info_index_finish(coder->info))
122                         return LZMA_DATA_ERROR;
123
124                 coder->block_options.has_backward_size = true;
125                 coder->block_options.handle_padding = false;
126                 size_type = LZMA_INFO_FOOTER_METADATA;
127                 want_extra = coder->footer_extra != NULL;
128         }
129
130         coder->block_options.has_uncompressed_size_in_footer = false;
131         coder->block_options.total_size = lzma_info_size_get(
132                         coder->info, size_type);
133
134         coder->sequence = SEQ_METADATA_CODE;
135
136         return lzma_metadata_decoder_init(&coder->block_decoder, allocator,
137                         &coder->block_options, &coder->metadata, want_extra);
138 }
139
140
141 static lzma_ret
142 data_init(lzma_coder *coder, lzma_allocator *allocator)
143 {
144         return_if_error(lzma_info_iter_next(&coder->iter, allocator));
145
146         return_if_error(lzma_info_iter_set(
147                         &coder->iter, LZMA_VLI_VALUE_UNKNOWN,
148                         coder->block_options.uncompressed_size));
149
150         coder->block_options.total_size = coder->iter.total_size;
151         coder->block_options.uncompressed_size = coder->iter.uncompressed_size;
152         coder->block_options.total_limit = coder->total_left;
153         coder->block_options.uncompressed_limit = coder->uncompressed_left;
154
155         if (coder->header_flags.is_multi) {
156                 coder->block_options.has_uncompressed_size_in_footer = false;
157                 coder->block_options.has_backward_size = false;
158                 coder->block_options.handle_padding = true;
159         } else {
160                 coder->block_options.has_uncompressed_size_in_footer
161                                 = coder->iter.uncompressed_size
162                                         == LZMA_VLI_VALUE_UNKNOWN;
163                 coder->block_options.has_backward_size = true;
164                 coder->block_options.handle_padding = false;
165         }
166
167         coder->sequence = SEQ_DATA_CODE;
168
169         return lzma_block_decoder_init(&coder->block_decoder, allocator,
170                         &coder->block_options);
171 }
172
173
174 static lzma_ret
175 stream_decode(lzma_coder *coder, lzma_allocator *allocator,
176                 const uint8_t *restrict in, size_t *restrict in_pos,
177                 size_t in_size, uint8_t *restrict out,
178                 size_t *restrict out_pos, size_t out_size, lzma_action action)
179 {
180         while (*out_pos < out_size && (*in_pos < in_size
181                         || coder->sequence == SEQ_DATA_CODE))
182         switch (coder->sequence) {
183         case SEQ_STREAM_HEADER_CODE: {
184                 const lzma_ret ret = coder->flags_decoder.code(
185                                 coder->flags_decoder.coder,
186                                 allocator, in, in_pos, in_size,
187                                 NULL, NULL, 0, LZMA_RUN);
188                 if (ret != LZMA_STREAM_END)
189                         return ret;
190
191                 coder->sequence = SEQ_BLOCK_HEADER_INIT;
192
193                 // Detect if the Check type is supported and give appropriate
194                 // warning if it isn't. We don't warn every time a new Block
195                 // is started.
196                 lzma_check tmp;
197                 if (lzma_check_init(&tmp, coder->header_flags.check))
198                         return LZMA_UNSUPPORTED_CHECK;
199
200                 break;
201         }
202
203         case SEQ_BLOCK_HEADER_INIT: {
204                 coder->block_options.check = coder->header_flags.check;
205                 coder->block_options.has_crc32 = coder->header_flags.has_crc32;
206
207                 for (size_t i = 0;
208                                 i < ARRAY_SIZE(coder->block_options.filters);
209                                 ++i) {
210                         lzma_free(coder->block_options.filters[i].options,
211                                         allocator);
212                         coder->block_options.filters[i].options = NULL;
213                 }
214
215                 return_if_error(lzma_block_header_decoder_init(
216                                 &coder->block_header_decoder, allocator,
217                                 &coder->block_options));
218
219                 coder->sequence = SEQ_BLOCK_HEADER_CODE;
220         }
221
222         // Fall through
223
224         case SEQ_BLOCK_HEADER_CODE: {
225                 lzma_ret ret = coder->block_header_decoder.code(
226                                 coder->block_header_decoder.coder,
227                                 allocator, in, in_pos, in_size,
228                                 NULL, NULL, 0, LZMA_RUN);
229
230                 if (ret != LZMA_STREAM_END)
231                         return ret;
232
233                 if (coder->block_options.is_metadata)
234                         ret = metadata_init(coder, allocator);
235                 else
236                         ret = data_init(coder, allocator);
237
238                 if (ret != LZMA_OK)
239                         return ret;
240
241                 break;
242         }
243
244         case SEQ_METADATA_CODE: {
245                 lzma_ret ret = coder->block_decoder.code(
246                                 coder->block_decoder.coder, allocator,
247                                 in, in_pos, in_size, NULL, NULL, 0, LZMA_RUN);
248                 if (ret != LZMA_STREAM_END)
249                         return ret;
250
251                 const bool is_header_metadata = lzma_info_index_count_get(
252                                 coder->info) == 0;
253
254                 if (is_header_metadata) {
255                         if (coder->header_extra != NULL) {
256                                 *coder->header_extra = coder->metadata.extra;
257                                 coder->metadata.extra = NULL;
258                         }
259
260                         if (lzma_info_size_set(coder->info,
261                                         LZMA_INFO_HEADER_METADATA,
262                                         coder->block_options.total_size)
263                                         != LZMA_OK)
264                                 return LZMA_PROG_ERROR;
265
266                         coder->sequence = SEQ_BLOCK_HEADER_INIT;
267                 } else {
268                         if (coder->footer_extra != NULL) {
269                                 *coder->footer_extra = coder->metadata.extra;
270                                 coder->metadata.extra = NULL;
271                         }
272
273                         coder->sequence = SEQ_STREAM_TAIL_INIT;
274                 }
275
276                 assert(coder->metadata.extra == NULL);
277
278                 ret = lzma_info_metadata_set(coder->info, allocator,
279                                 &coder->metadata, is_header_metadata, true);
280                 if (ret != LZMA_OK)
281                         return ret;
282
283                 // Intialize coder->total_size and coder->uncompressed_size
284                 // from Header Metadata.
285                 if (is_header_metadata) {
286                         coder->total_left = lzma_info_size_get(
287                                         coder->info, LZMA_INFO_TOTAL);
288                         coder->uncompressed_left = lzma_info_size_get(
289                                         coder->info, LZMA_INFO_UNCOMPRESSED);
290                 }
291
292                 break;
293         }
294
295         case SEQ_DATA_CODE: {
296                 lzma_ret ret = coder->block_decoder.code(
297                                 coder->block_decoder.coder, allocator,
298                                 in, in_pos, in_size, out, out_pos, out_size,
299                                 action);
300
301                 if (ret != LZMA_STREAM_END)
302                         return ret;
303
304                 ret = lzma_info_iter_set(&coder->iter,
305                                 coder->block_options.total_size,
306                                 coder->block_options.uncompressed_size);
307                 if (ret != LZMA_OK)
308                         return ret;
309
310                 // These won't overflow since lzma_info_iter_set() succeeded.
311                 if (coder->total_left != LZMA_VLI_VALUE_UNKNOWN)
312                         coder->total_left -= coder->block_options.total_size;
313                 if (coder->uncompressed_left != LZMA_VLI_VALUE_UNKNOWN)
314                         coder->uncompressed_left -= coder->block_options
315                                         .uncompressed_size;
316
317                 if (!coder->header_flags.is_multi) {
318                         ret = lzma_info_index_finish(coder->info);
319                         if (ret != LZMA_OK)
320                                 return ret;
321
322                         coder->sequence = SEQ_STREAM_TAIL_INIT;
323                         break;
324                 }
325
326                 coder->sequence = SEQ_BLOCK_HEADER_INIT;
327                 break;
328         }
329
330         case SEQ_STREAM_TAIL_INIT: {
331                 lzma_ret ret = lzma_info_index_finish(coder->info);
332                 if (ret != LZMA_OK)
333                         return ret;
334
335                 ret = lzma_stream_tail_decoder_init(&coder->flags_decoder,
336                                 allocator, &coder->tail_flags);
337                 if (ret != LZMA_OK)
338                         return ret;
339
340                 coder->sequence = SEQ_STREAM_TAIL_CODE;
341         }
342
343         // Fall through
344
345         case SEQ_STREAM_TAIL_CODE: {
346                 const lzma_ret ret = coder->flags_decoder.code(
347                                 coder->flags_decoder.coder, allocator,
348                                 in, in_pos, in_size, NULL, NULL, 0, LZMA_RUN);
349                 if (ret != LZMA_STREAM_END)
350                         return ret;
351
352                 if (!lzma_stream_flags_is_equal(
353                                 coder->header_flags, coder->tail_flags))
354                         return LZMA_DATA_ERROR;
355
356                 return LZMA_STREAM_END;
357         }
358
359         default:
360                 return LZMA_PROG_ERROR;
361         }
362
363         return LZMA_OK;
364 }
365
366
367 static void
368 stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
369 {
370         for (size_t i = 0; i < ARRAY_SIZE(coder->block_options.filters); ++i)
371                 lzma_free(coder->block_options.filters[i].options, allocator);
372
373         lzma_next_coder_end(&coder->block_decoder, allocator);
374         lzma_next_coder_end(&coder->block_header_decoder, allocator);
375         lzma_next_coder_end(&coder->flags_decoder, allocator);
376         lzma_info_free(coder->info, allocator);
377         lzma_index_free(coder->metadata.index, allocator);
378         lzma_extra_free(coder->metadata.extra, allocator);
379         lzma_free(coder, allocator);
380         return;
381 }
382
383
384 static lzma_ret
385 stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
386                 lzma_extra **header, lzma_extra **footer)
387 {
388         if (next->coder == NULL) {
389                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
390                 if (next->coder == NULL)
391                         return LZMA_MEM_ERROR;
392
393                 next->code = &stream_decode;
394                 next->end = &stream_decoder_end;
395
396                 next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
397                 next->coder->block_header_decoder = LZMA_NEXT_CODER_INIT;
398                 next->coder->info = NULL;
399                 next->coder->flags_decoder = LZMA_NEXT_CODER_INIT;
400                 next->coder->metadata.index = NULL;
401                 next->coder->metadata.extra = NULL;
402         } else {
403                 for (size_t i = 0; i < ARRAY_SIZE(
404                                 next->coder->block_options.filters); ++i)
405                         lzma_free(next->coder->block_options
406                                         .filters[i].options, allocator);
407
408                 lzma_index_free(next->coder->metadata.index, allocator);
409                 next->coder->metadata.index = NULL;
410
411                 lzma_extra_free(next->coder->metadata.extra, allocator);
412                 next->coder->metadata.extra = NULL;
413         }
414
415         for (size_t i = 0; i < ARRAY_SIZE(next->coder->block_options.filters);
416                         ++i)
417                 next->coder->block_options.filters[i].options = NULL;
418
419         next->coder->info = lzma_info_init(next->coder->info, allocator);
420         if (next->coder->info == NULL)
421                 return LZMA_MEM_ERROR;
422
423         lzma_info_iter_begin(next->coder->info, &next->coder->iter);
424
425         // Initialize Stream Header decoder.
426         return_if_error(lzma_stream_header_decoder_init(
427                                 &next->coder->flags_decoder, allocator,
428                                 &next->coder->header_flags));
429
430         // Reset the *foo_extra pointers to NULL. This way the caller knows
431         // if there were no Extra Records. (We don't support appending
432         // Records to Extra list.)
433         if (header != NULL)
434                 *header = NULL;
435         if (footer != NULL)
436                 *footer = NULL;
437
438         // Reset some variables.
439         next->coder->sequence = SEQ_STREAM_HEADER_CODE;
440         next->coder->pos = 0;
441         next->coder->uncompressed_left = LZMA_VLI_VALUE_UNKNOWN;
442         next->coder->total_left = LZMA_VLI_VALUE_UNKNOWN;
443         next->coder->header_extra = header;
444         next->coder->footer_extra = footer;
445
446         return LZMA_OK;
447 }
448
449
450 extern lzma_ret
451 lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
452                 lzma_extra **header, lzma_extra **footer)
453 {
454         lzma_next_coder_init(
455                         stream_decoder_init, next, allocator, header, footer);
456 }
457
458
459 extern LZMA_API lzma_ret
460 lzma_stream_decoder(lzma_stream *strm,
461                 lzma_extra **header, lzma_extra **footer)
462 {
463         lzma_next_strm_init(strm, stream_decoder_init, header, footer);
464
465         strm->internal->supported_actions[LZMA_RUN] = true;
466         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
467
468         return LZMA_OK;
469 }