1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file stream_decoder.c
4 /// \brief Decodes .lzma Streams
6 // Copyright (C) 2007 Lasse Collin
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.
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.
18 ///////////////////////////////////////////////////////////////////////////////
20 #include "stream_common.h"
22 #include "stream_flags_decoder.h"
23 #include "block_decoder.h"
24 #include "metadata_decoder.h"
29 SEQ_STREAM_HEADER_CODE,
30 SEQ_BLOCK_HEADER_INIT,
31 SEQ_BLOCK_HEADER_CODE,
38 /// Position in variable-length integers and in some other things.
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;
46 /// Block Header decoder; this is separate
47 lzma_next_coder block_header_decoder;
49 lzma_options_block block_options;
51 /// Information about the sizes of the Blocks
54 /// Current Block in *info
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.
62 /// Like uncompressed_left above but for uncompressed data from
64 lzma_vli uncompressed_left;
66 /// Stream Flags from Stream Header
67 lzma_stream_flags header_flags;
69 /// Stream Flags from Stream tail
70 lzma_stream_flags tail_flags;
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;
78 /// Temporary destination for the decoded Metadata.
79 lzma_metadata metadata;
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;
85 /// Same as above but Footer Metadata Block
86 lzma_extra **footer_extra;
91 metadata_init(lzma_coder *coder, lzma_allocator *allocator)
93 assert(coder->metadata.index == NULL);
94 assert(coder->metadata.extra == NULL);
96 // Single-Block Streams don't have Metadata Blocks.
97 if (!coder->header_flags.is_multi)
98 return LZMA_DATA_ERROR;
100 coder->block_options.total_limit = LZMA_VLI_VALUE_UNKNOWN;
102 // Limit the Uncompressed Size of a Metadata Block. This is to
103 // prevent security issues where input file would have very huge
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;
110 lzma_info_size size_type;
113 // If we haven't decoded any Data Blocks yet, this is Header
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;
121 if (lzma_info_index_finish(coder->info))
122 return LZMA_DATA_ERROR;
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;
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);
134 coder->sequence = SEQ_METADATA_CODE;
136 return lzma_metadata_decoder_init(&coder->block_decoder, allocator,
137 &coder->block_options, &coder->metadata, want_extra);
142 data_init(lzma_coder *coder, lzma_allocator *allocator)
144 return_if_error(lzma_info_iter_next(&coder->iter, allocator));
146 return_if_error(lzma_info_iter_set(
147 &coder->iter, LZMA_VLI_VALUE_UNKNOWN,
148 coder->block_options.uncompressed_size));
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;
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;
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;
167 coder->sequence = SEQ_DATA_CODE;
169 return lzma_block_decoder_init(&coder->block_decoder, allocator,
170 &coder->block_options);
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)
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)
191 coder->sequence = SEQ_BLOCK_HEADER_INIT;
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
197 if (lzma_check_init(&tmp, coder->header_flags.check))
198 return LZMA_UNSUPPORTED_CHECK;
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;
208 i < ARRAY_SIZE(coder->block_options.filters);
210 lzma_free(coder->block_options.filters[i].options,
212 coder->block_options.filters[i].options = NULL;
215 return_if_error(lzma_block_header_decoder_init(
216 &coder->block_header_decoder, allocator,
217 &coder->block_options));
219 coder->sequence = SEQ_BLOCK_HEADER_CODE;
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);
230 if (ret != LZMA_STREAM_END)
233 if (coder->block_options.is_metadata)
234 ret = metadata_init(coder, allocator);
236 ret = data_init(coder, allocator);
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)
251 const bool is_header_metadata = lzma_info_index_count_get(
254 if (is_header_metadata) {
255 if (coder->header_extra != NULL) {
256 *coder->header_extra = coder->metadata.extra;
257 coder->metadata.extra = NULL;
260 if (lzma_info_size_set(coder->info,
261 LZMA_INFO_HEADER_METADATA,
262 coder->block_options.total_size)
264 return LZMA_PROG_ERROR;
266 coder->sequence = SEQ_BLOCK_HEADER_INIT;
268 if (coder->footer_extra != NULL) {
269 *coder->footer_extra = coder->metadata.extra;
270 coder->metadata.extra = NULL;
273 coder->sequence = SEQ_STREAM_TAIL_INIT;
276 assert(coder->metadata.extra == NULL);
278 ret = lzma_info_metadata_set(coder->info, allocator,
279 &coder->metadata, is_header_metadata, true);
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);
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,
301 if (ret != LZMA_STREAM_END)
304 ret = lzma_info_iter_set(&coder->iter,
305 coder->block_options.total_size,
306 coder->block_options.uncompressed_size);
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
317 if (!coder->header_flags.is_multi) {
318 ret = lzma_info_index_finish(coder->info);
322 coder->sequence = SEQ_STREAM_TAIL_INIT;
326 coder->sequence = SEQ_BLOCK_HEADER_INIT;
330 case SEQ_STREAM_TAIL_INIT: {
331 lzma_ret ret = lzma_info_index_finish(coder->info);
335 ret = lzma_stream_tail_decoder_init(&coder->flags_decoder,
336 allocator, &coder->tail_flags);
340 coder->sequence = SEQ_STREAM_TAIL_CODE;
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)
352 if (!lzma_stream_flags_is_equal(
353 coder->header_flags, coder->tail_flags))
354 return LZMA_DATA_ERROR;
356 return LZMA_STREAM_END;
360 return LZMA_PROG_ERROR;
368 stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
370 for (size_t i = 0; i < ARRAY_SIZE(coder->block_options.filters); ++i)
371 lzma_free(coder->block_options.filters[i].options, allocator);
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);
385 stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
386 lzma_extra **header, lzma_extra **footer)
388 if (next->coder == NULL) {
389 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
390 if (next->coder == NULL)
391 return LZMA_MEM_ERROR;
393 next->code = &stream_decode;
394 next->end = &stream_decoder_end;
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;
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);
408 lzma_index_free(next->coder->metadata.index, allocator);
409 next->coder->metadata.index = NULL;
411 lzma_extra_free(next->coder->metadata.extra, allocator);
412 next->coder->metadata.extra = NULL;
415 for (size_t i = 0; i < ARRAY_SIZE(next->coder->block_options.filters);
417 next->coder->block_options.filters[i].options = NULL;
419 next->coder->info = lzma_info_init(next->coder->info, allocator);
420 if (next->coder->info == NULL)
421 return LZMA_MEM_ERROR;
423 lzma_info_iter_begin(next->coder->info, &next->coder->iter);
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));
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.)
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;
451 lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
452 lzma_extra **header, lzma_extra **footer)
454 lzma_next_coder_init(
455 stream_decoder_init, next, allocator, header, footer);
459 extern LZMA_API lzma_ret
460 lzma_stream_decoder(lzma_stream *strm,
461 lzma_extra **header, lzma_extra **footer)
463 lzma_next_strm_init(strm, stream_decoder_init, header, footer);
465 strm->internal->supported_actions[LZMA_RUN] = true;
466 strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;