1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file block_decoder.c
4 /// \brief Decodes .lzma Blocks
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 "block_decoder.h"
21 #include "block_private.h"
22 #include "raw_decoder.h"
30 SEQ_UNCOMPRESSED_SIZE,
36 /// The filters in the chain; initialized with lzma_raw_decoder_init().
39 /// Decoding options; we also write Total Size, Compressed Size, and
40 /// Uncompressed Size back to this structure when the encoding has
42 lzma_options_block *options;
44 /// Position in variable-length integers (and in some other places).
47 /// Check of the uncompressed data
50 /// Total Size calculated while encoding
53 /// Compressed Size calculated while encoding
54 lzma_vli compressed_size;
56 /// Uncompressed Size calculated while encoding
57 lzma_vli uncompressed_size;
59 /// Maximum allowed total_size
62 /// Maximum allowed uncompressed_size
63 lzma_vli uncompressed_limit;
65 /// Temporary location for the Uncompressed Size and Backward Size
66 /// fields in Block Footer.
69 /// Size of the Backward Size field - This is needed so that we
70 /// can verify the Backward Size and still keep updating total_size.
71 size_t size_of_backward_size;
76 update_sequence(lzma_coder *coder)
78 switch (coder->sequence) {
80 if (coder->options->check != LZMA_CHECK_NONE) {
81 lzma_check_finish(&coder->check,
82 coder->options->check);
83 coder->sequence = SEQ_CHECK;
90 if (coder->options->has_uncompressed_size_in_footer) {
91 coder->sequence = SEQ_UNCOMPRESSED_SIZE;
97 case SEQ_UNCOMPRESSED_SIZE:
98 if (coder->options->has_backward_size) {
99 coder->sequence = SEQ_BACKWARD_SIZE;
105 case SEQ_BACKWARD_SIZE:
106 if (coder->options->handle_padding) {
107 coder->sequence = SEQ_PADDING;
112 if (!is_size_valid(coder->total_size,
113 coder->options->total_size)
114 || !is_size_valid(coder->compressed_size,
115 coder->options->compressed_size)
116 || !is_size_valid(coder->uncompressed_size,
117 coder->options->uncompressed_size))
118 return LZMA_DATA_ERROR;
120 // Copy the values into coder->options. The caller
121 // may use this information to construct Index.
122 coder->options->total_size = coder->total_size;
123 coder->options->compressed_size = coder->compressed_size;
124 coder->options->uncompressed_size = coder->uncompressed_size;
126 return LZMA_STREAM_END;
130 return LZMA_PROG_ERROR;
138 block_decode(lzma_coder *coder, lzma_allocator *allocator,
139 const uint8_t *restrict in, size_t *restrict in_pos,
140 size_t in_size, uint8_t *restrict out,
141 size_t *restrict out_pos, size_t out_size, lzma_action action)
143 // Special case when the Block has only Block Header.
144 if (coder->sequence == SEQ_END)
145 return LZMA_STREAM_END;
147 // FIXME: Termination condition should work but could be cleaner.
148 while (*out_pos < out_size && (*in_pos < in_size
149 || coder->sequence == SEQ_CODE))
150 switch (coder->sequence) {
152 const size_t in_start = *in_pos;
153 const size_t out_start = *out_pos;
155 lzma_ret ret = coder->next.code(coder->next.coder,
156 allocator, in, in_pos, in_size,
157 out, out_pos, out_size, action);
159 const size_t in_used = *in_pos - in_start;
160 const size_t out_used = *out_pos - out_start;
162 if (update_size(&coder->total_size, in_used,
164 || update_size(&coder->compressed_size,
166 coder->options->compressed_size)
167 || update_size(&coder->uncompressed_size,
168 out_used, coder->uncompressed_limit))
169 return LZMA_DATA_ERROR;
171 lzma_check_update(&coder->check, coder->options->check,
172 out + out_start, out_used);
174 if (ret != LZMA_STREAM_END)
177 ret = update_sequence(coder);
185 switch (coder->options->check) {
186 case LZMA_CHECK_CRC32:
187 if (((coder->check.crc32 >> (coder->pos * 8))
188 & 0xFF) != in[*in_pos])
189 return LZMA_DATA_ERROR;
192 case LZMA_CHECK_CRC64:
193 if (((coder->check.crc64 >> (coder->pos * 8))
194 & 0xFF) != in[*in_pos])
195 return LZMA_DATA_ERROR;
198 case LZMA_CHECK_SHA256:
199 if (coder->check.sha256.buffer[coder->pos]
201 return LZMA_DATA_ERROR;
205 assert(coder->options->check != LZMA_CHECK_NONE);
206 assert(coder->options->check <= LZMA_CHECK_ID_MAX);
210 if (update_size(&coder->total_size, 1, coder->total_limit))
211 return LZMA_DATA_ERROR;
215 if (++coder->pos == lzma_check_sizes[coder->options->check]) {
216 const lzma_ret ret = update_sequence(coder);
225 case SEQ_UNCOMPRESSED_SIZE: {
226 const size_t in_start = *in_pos;
228 lzma_ret ret = lzma_vli_decode(&coder->tmp,
229 &coder->pos, in, in_pos, in_size);
231 if (update_size(&coder->total_size, *in_pos - in_start,
233 return LZMA_DATA_ERROR;
235 if (ret != LZMA_STREAM_END)
238 if (coder->tmp != coder->uncompressed_size)
239 return LZMA_DATA_ERROR;
244 ret = update_sequence(coder);
251 case SEQ_BACKWARD_SIZE: {
252 const size_t in_start = *in_pos;
254 lzma_ret ret = lzma_vli_decode(&coder->tmp,
255 &coder->pos, in, in_pos, in_size);
257 const size_t in_used = *in_pos - in_start;
259 if (update_size(&coder->total_size, in_used,
261 return LZMA_DATA_ERROR;
263 coder->size_of_backward_size += in_used;
265 if (ret != LZMA_STREAM_END)
268 if (coder->tmp != coder->total_size
269 - coder->size_of_backward_size)
270 return LZMA_DATA_ERROR;
272 ret = update_sequence(coder);
280 if (in[*in_pos] == 0x00) {
281 if (update_size(&coder->total_size, 1,
283 return LZMA_DATA_ERROR;
289 return update_sequence(coder);
292 return LZMA_PROG_ERROR;
300 block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
302 lzma_next_coder_end(&coder->next, allocator);
303 lzma_free(coder, allocator);
309 lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
310 lzma_options_block *options)
312 // This is pretty similar to lzma_block_encoder_init().
313 // See comments there.
315 if (next->coder == NULL) {
316 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
317 if (next->coder == NULL)
318 return LZMA_MEM_ERROR;
320 next->code = &block_decode;
321 next->end = &block_decoder_end;
322 next->coder->next = LZMA_NEXT_CODER_INIT;
325 if (!lzma_vli_is_valid(options->total_size)
326 || !lzma_vli_is_valid(options->compressed_size)
327 || !lzma_vli_is_valid(options->uncompressed_size)
328 || !lzma_vli_is_valid(options->total_size)
329 || !lzma_vli_is_valid(options->total_limit)
330 || !lzma_vli_is_valid(options->uncompressed_limit)
331 || (options->uncompressed_size
332 != LZMA_VLI_VALUE_UNKNOWN
333 && options->uncompressed_size
334 > options->uncompressed_limit)
335 || (options->total_size != LZMA_VLI_VALUE_UNKNOWN
336 && options->total_size
337 > options->total_limit)
338 || (!options->has_eopm && options->uncompressed_size
339 == LZMA_VLI_VALUE_UNKNOWN)
340 || options->header_size > options->total_size
341 || (options->handle_padding
342 && (options->has_uncompressed_size_in_footer
343 || options->has_backward_size)))
344 return LZMA_PROG_ERROR;
347 const lzma_ret ret = lzma_check_init(
348 &next->coder->check, options->check);
353 if (!options->has_eopm && options->uncompressed_size == 0) {
354 if (!is_size_valid(0, options->compressed_size))
355 return LZMA_PROG_ERROR;
357 if (options->check != LZMA_CHECK_NONE) {
358 lzma_check_finish(&next->coder->check, options->check);
359 next->coder->sequence = SEQ_CHECK;
360 } else if (options->handle_padding) {
361 next->coder->sequence = SEQ_PADDING;
363 next->coder->sequence = SEQ_END;
366 next->coder->sequence = SEQ_CODE;
370 const lzma_ret ret = lzma_raw_decoder_init(
371 &next->coder->next, allocator,
372 options->filters, options->has_eopm
373 ? LZMA_VLI_VALUE_UNKNOWN
374 : options->uncompressed_size,
380 next->coder->options = options;
381 next->coder->pos = 0;
382 next->coder->total_size = options->header_size;
383 next->coder->compressed_size = 0;
384 next->coder->uncompressed_size = 0;
385 next->coder->total_limit
386 = MIN(options->total_size, options->total_limit);
387 next->coder->uncompressed_limit = MIN(options->uncompressed_size,
388 options->uncompressed_limit);
389 next->coder->tmp = 0;
390 next->coder->size_of_backward_size = 0;
396 extern LZMA_API lzma_ret
397 lzma_block_decoder(lzma_stream *strm, lzma_options_block *options)
399 lzma_next_strm_init(strm, lzma_block_decoder_init, options);
401 strm->internal->supported_actions[LZMA_RUN] = true;
402 strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;