xref: /freebsd/contrib/xz/src/liblzma/common/stream_decoder.c (revision 532000256b898d5d3b0067ffa328715d18f4776d)
181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
281ad8388SMartin Matuska //
381ad8388SMartin Matuska /// \file       stream_decoder.c
481ad8388SMartin Matuska /// \brief      Decodes .xz Streams
581ad8388SMartin Matuska //
681ad8388SMartin Matuska //  Author:     Lasse Collin
781ad8388SMartin Matuska //
881ad8388SMartin Matuska //  This file has been put into the public domain.
981ad8388SMartin Matuska //  You can do whatever you want with this file.
1081ad8388SMartin Matuska //
1181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
1281ad8388SMartin Matuska 
1381ad8388SMartin Matuska #include "stream_decoder.h"
1481ad8388SMartin Matuska #include "block_decoder.h"
1581ad8388SMartin Matuska 
1681ad8388SMartin Matuska 
1781ad8388SMartin Matuska struct lzma_coder_s {
1881ad8388SMartin Matuska 	enum {
1981ad8388SMartin Matuska 		SEQ_STREAM_HEADER,
2081ad8388SMartin Matuska 		SEQ_BLOCK_HEADER,
2181ad8388SMartin Matuska 		SEQ_BLOCK,
2281ad8388SMartin Matuska 		SEQ_INDEX,
2381ad8388SMartin Matuska 		SEQ_STREAM_FOOTER,
2481ad8388SMartin Matuska 		SEQ_STREAM_PADDING,
2581ad8388SMartin Matuska 	} sequence;
2681ad8388SMartin Matuska 
2781ad8388SMartin Matuska 	/// Block or Metadata decoder. This takes little memory and the same
2881ad8388SMartin Matuska 	/// data structure can be used to decode every Block Header, so it's
2981ad8388SMartin Matuska 	/// a good idea to have a separate lzma_next_coder structure for it.
3081ad8388SMartin Matuska 	lzma_next_coder block_decoder;
3181ad8388SMartin Matuska 
3281ad8388SMartin Matuska 	/// Block options decoded by the Block Header decoder and used by
3381ad8388SMartin Matuska 	/// the Block decoder.
3481ad8388SMartin Matuska 	lzma_block block_options;
3581ad8388SMartin Matuska 
3681ad8388SMartin Matuska 	/// Stream Flags from Stream Header
3781ad8388SMartin Matuska 	lzma_stream_flags stream_flags;
3881ad8388SMartin Matuska 
3981ad8388SMartin Matuska 	/// Index is hashed so that it can be compared to the sizes of Blocks
4081ad8388SMartin Matuska 	/// with O(1) memory usage.
4181ad8388SMartin Matuska 	lzma_index_hash *index_hash;
4281ad8388SMartin Matuska 
4381ad8388SMartin Matuska 	/// Memory usage limit
4481ad8388SMartin Matuska 	uint64_t memlimit;
4581ad8388SMartin Matuska 
4681ad8388SMartin Matuska 	/// Amount of memory actually needed (only an estimate)
4781ad8388SMartin Matuska 	uint64_t memusage;
4881ad8388SMartin Matuska 
4981ad8388SMartin Matuska 	/// If true, LZMA_NO_CHECK is returned if the Stream has
5081ad8388SMartin Matuska 	/// no integrity check.
5181ad8388SMartin Matuska 	bool tell_no_check;
5281ad8388SMartin Matuska 
5381ad8388SMartin Matuska 	/// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has
5481ad8388SMartin Matuska 	/// an integrity check that isn't supported by this liblzma build.
5581ad8388SMartin Matuska 	bool tell_unsupported_check;
5681ad8388SMartin Matuska 
5781ad8388SMartin Matuska 	/// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
5881ad8388SMartin Matuska 	bool tell_any_check;
5981ad8388SMartin Matuska 
60*53200025SRui Paulo 	/// If true, we will tell the Block decoder to skip calculating
61*53200025SRui Paulo 	/// and verifying the integrity check.
62*53200025SRui Paulo 	bool ignore_check;
63*53200025SRui Paulo 
6481ad8388SMartin Matuska 	/// If true, we will decode concatenated Streams that possibly have
6581ad8388SMartin Matuska 	/// Stream Padding between or after them. LZMA_STREAM_END is returned
6681ad8388SMartin Matuska 	/// once the application isn't giving us any new input, and we aren't
6781ad8388SMartin Matuska 	/// in the middle of a Stream, and possible Stream Padding is a
6881ad8388SMartin Matuska 	/// multiple of four bytes.
6981ad8388SMartin Matuska 	bool concatenated;
7081ad8388SMartin Matuska 
7181ad8388SMartin Matuska 	/// When decoding concatenated Streams, this is true as long as we
7281ad8388SMartin Matuska 	/// are decoding the first Stream. This is needed to avoid misleading
7381ad8388SMartin Matuska 	/// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic
7481ad8388SMartin Matuska 	/// bytes.
7581ad8388SMartin Matuska 	bool first_stream;
7681ad8388SMartin Matuska 
7781ad8388SMartin Matuska 	/// Write position in buffer[] and position in Stream Padding
7881ad8388SMartin Matuska 	size_t pos;
7981ad8388SMartin Matuska 
8081ad8388SMartin Matuska 	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
8181ad8388SMartin Matuska 	/// Block Header has biggest maximum size.
8281ad8388SMartin Matuska 	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
8381ad8388SMartin Matuska };
8481ad8388SMartin Matuska 
8581ad8388SMartin Matuska 
8681ad8388SMartin Matuska static lzma_ret
87*53200025SRui Paulo stream_decoder_reset(lzma_coder *coder, const lzma_allocator *allocator)
8881ad8388SMartin Matuska {
8981ad8388SMartin Matuska 	// Initialize the Index hash used to verify the Index.
9081ad8388SMartin Matuska 	coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
9181ad8388SMartin Matuska 	if (coder->index_hash == NULL)
9281ad8388SMartin Matuska 		return LZMA_MEM_ERROR;
9381ad8388SMartin Matuska 
9481ad8388SMartin Matuska 	// Reset the rest of the variables.
9581ad8388SMartin Matuska 	coder->sequence = SEQ_STREAM_HEADER;
9681ad8388SMartin Matuska 	coder->pos = 0;
9781ad8388SMartin Matuska 
9881ad8388SMartin Matuska 	return LZMA_OK;
9981ad8388SMartin Matuska }
10081ad8388SMartin Matuska 
10181ad8388SMartin Matuska 
10281ad8388SMartin Matuska static lzma_ret
103*53200025SRui Paulo stream_decode(lzma_coder *coder, const lzma_allocator *allocator,
10481ad8388SMartin Matuska 		const uint8_t *restrict in, size_t *restrict in_pos,
10581ad8388SMartin Matuska 		size_t in_size, uint8_t *restrict out,
10681ad8388SMartin Matuska 		size_t *restrict out_pos, size_t out_size, lzma_action action)
10781ad8388SMartin Matuska {
10881ad8388SMartin Matuska 	// When decoding the actual Block, it may be able to produce more
10981ad8388SMartin Matuska 	// output even if we don't give it any new input.
11081ad8388SMartin Matuska 	while (true)
11181ad8388SMartin Matuska 	switch (coder->sequence) {
11281ad8388SMartin Matuska 	case SEQ_STREAM_HEADER: {
11381ad8388SMartin Matuska 		// Copy the Stream Header to the internal buffer.
11481ad8388SMartin Matuska 		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
11581ad8388SMartin Matuska 				LZMA_STREAM_HEADER_SIZE);
11681ad8388SMartin Matuska 
11781ad8388SMartin Matuska 		// Return if we didn't get the whole Stream Header yet.
11881ad8388SMartin Matuska 		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
11981ad8388SMartin Matuska 			return LZMA_OK;
12081ad8388SMartin Matuska 
12181ad8388SMartin Matuska 		coder->pos = 0;
12281ad8388SMartin Matuska 
12381ad8388SMartin Matuska 		// Decode the Stream Header.
12481ad8388SMartin Matuska 		const lzma_ret ret = lzma_stream_header_decode(
12581ad8388SMartin Matuska 				&coder->stream_flags, coder->buffer);
12681ad8388SMartin Matuska 		if (ret != LZMA_OK)
12781ad8388SMartin Matuska 			return ret == LZMA_FORMAT_ERROR && !coder->first_stream
12881ad8388SMartin Matuska 					? LZMA_DATA_ERROR : ret;
12981ad8388SMartin Matuska 
13081ad8388SMartin Matuska 		// If we are decoding concatenated Streams, and the later
13181ad8388SMartin Matuska 		// Streams have invalid Header Magic Bytes, we give
13281ad8388SMartin Matuska 		// LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR.
13381ad8388SMartin Matuska 		coder->first_stream = false;
13481ad8388SMartin Matuska 
13581ad8388SMartin Matuska 		// Copy the type of the Check so that Block Header and Block
13681ad8388SMartin Matuska 		// decoders see it.
13781ad8388SMartin Matuska 		coder->block_options.check = coder->stream_flags.check;
13881ad8388SMartin Matuska 
13981ad8388SMartin Matuska 		// Even if we return LZMA_*_CHECK below, we want
14081ad8388SMartin Matuska 		// to continue from Block Header decoding.
14181ad8388SMartin Matuska 		coder->sequence = SEQ_BLOCK_HEADER;
14281ad8388SMartin Matuska 
14381ad8388SMartin Matuska 		// Detect if there's no integrity check or if it is
14481ad8388SMartin Matuska 		// unsupported if those were requested by the application.
14581ad8388SMartin Matuska 		if (coder->tell_no_check && coder->stream_flags.check
14681ad8388SMartin Matuska 				== LZMA_CHECK_NONE)
14781ad8388SMartin Matuska 			return LZMA_NO_CHECK;
14881ad8388SMartin Matuska 
14981ad8388SMartin Matuska 		if (coder->tell_unsupported_check
15081ad8388SMartin Matuska 				&& !lzma_check_is_supported(
15181ad8388SMartin Matuska 					coder->stream_flags.check))
15281ad8388SMartin Matuska 			return LZMA_UNSUPPORTED_CHECK;
15381ad8388SMartin Matuska 
15481ad8388SMartin Matuska 		if (coder->tell_any_check)
15581ad8388SMartin Matuska 			return LZMA_GET_CHECK;
15681ad8388SMartin Matuska 	}
15781ad8388SMartin Matuska 
15881ad8388SMartin Matuska 	// Fall through
15981ad8388SMartin Matuska 
16081ad8388SMartin Matuska 	case SEQ_BLOCK_HEADER: {
16181ad8388SMartin Matuska 		if (*in_pos >= in_size)
16281ad8388SMartin Matuska 			return LZMA_OK;
16381ad8388SMartin Matuska 
16481ad8388SMartin Matuska 		if (coder->pos == 0) {
16581ad8388SMartin Matuska 			// Detect if it's Index.
16681ad8388SMartin Matuska 			if (in[*in_pos] == 0x00) {
16781ad8388SMartin Matuska 				coder->sequence = SEQ_INDEX;
16881ad8388SMartin Matuska 				break;
16981ad8388SMartin Matuska 			}
17081ad8388SMartin Matuska 
17181ad8388SMartin Matuska 			// Calculate the size of the Block Header. Note that
17281ad8388SMartin Matuska 			// Block Header decoder wants to see this byte too
17381ad8388SMartin Matuska 			// so don't advance *in_pos.
17481ad8388SMartin Matuska 			coder->block_options.header_size
17581ad8388SMartin Matuska 					= lzma_block_header_size_decode(
17681ad8388SMartin Matuska 						in[*in_pos]);
17781ad8388SMartin Matuska 		}
17881ad8388SMartin Matuska 
17981ad8388SMartin Matuska 		// Copy the Block Header to the internal buffer.
18081ad8388SMartin Matuska 		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
18181ad8388SMartin Matuska 				coder->block_options.header_size);
18281ad8388SMartin Matuska 
18381ad8388SMartin Matuska 		// Return if we didn't get the whole Block Header yet.
18481ad8388SMartin Matuska 		if (coder->pos < coder->block_options.header_size)
18581ad8388SMartin Matuska 			return LZMA_OK;
18681ad8388SMartin Matuska 
18781ad8388SMartin Matuska 		coder->pos = 0;
18881ad8388SMartin Matuska 
189*53200025SRui Paulo 		// Version 1 is needed to support the .ignore_check option.
190*53200025SRui Paulo 		coder->block_options.version = 1;
19181ad8388SMartin Matuska 
19281ad8388SMartin Matuska 		// Set up a buffer to hold the filter chain. Block Header
19381ad8388SMartin Matuska 		// decoder will initialize all members of this array so
19481ad8388SMartin Matuska 		// we don't need to do it here.
19581ad8388SMartin Matuska 		lzma_filter filters[LZMA_FILTERS_MAX + 1];
19681ad8388SMartin Matuska 		coder->block_options.filters = filters;
19781ad8388SMartin Matuska 
19881ad8388SMartin Matuska 		// Decode the Block Header.
19981ad8388SMartin Matuska 		return_if_error(lzma_block_header_decode(&coder->block_options,
20081ad8388SMartin Matuska 				allocator, coder->buffer));
20181ad8388SMartin Matuska 
202*53200025SRui Paulo 		// If LZMA_IGNORE_CHECK was used, this flag needs to be set.
203*53200025SRui Paulo 		// It has to be set after lzma_block_header_decode() because
204*53200025SRui Paulo 		// it always resets this to false.
205*53200025SRui Paulo 		coder->block_options.ignore_check = coder->ignore_check;
206*53200025SRui Paulo 
20781ad8388SMartin Matuska 		// Check the memory usage limit.
20881ad8388SMartin Matuska 		const uint64_t memusage = lzma_raw_decoder_memusage(filters);
20981ad8388SMartin Matuska 		lzma_ret ret;
21081ad8388SMartin Matuska 
21181ad8388SMartin Matuska 		if (memusage == UINT64_MAX) {
21281ad8388SMartin Matuska 			// One or more unknown Filter IDs.
21381ad8388SMartin Matuska 			ret = LZMA_OPTIONS_ERROR;
21481ad8388SMartin Matuska 		} else {
21581ad8388SMartin Matuska 			// Now we can set coder->memusage since we know that
21681ad8388SMartin Matuska 			// the filter chain is valid. We don't want
21781ad8388SMartin Matuska 			// lzma_memusage() to return UINT64_MAX in case of
21881ad8388SMartin Matuska 			// invalid filter chain.
21981ad8388SMartin Matuska 			coder->memusage = memusage;
22081ad8388SMartin Matuska 
22181ad8388SMartin Matuska 			if (memusage > coder->memlimit) {
22281ad8388SMartin Matuska 				// The chain would need too much memory.
22381ad8388SMartin Matuska 				ret = LZMA_MEMLIMIT_ERROR;
22481ad8388SMartin Matuska 			} else {
22581ad8388SMartin Matuska 				// Memory usage is OK.
22681ad8388SMartin Matuska 				// Initialize the Block decoder.
22781ad8388SMartin Matuska 				ret = lzma_block_decoder_init(
22881ad8388SMartin Matuska 						&coder->block_decoder,
22981ad8388SMartin Matuska 						allocator,
23081ad8388SMartin Matuska 						&coder->block_options);
23181ad8388SMartin Matuska 			}
23281ad8388SMartin Matuska 		}
23381ad8388SMartin Matuska 
23481ad8388SMartin Matuska 		// Free the allocated filter options since they are needed
23581ad8388SMartin Matuska 		// only to initialize the Block decoder.
23681ad8388SMartin Matuska 		for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i)
23781ad8388SMartin Matuska 			lzma_free(filters[i].options, allocator);
23881ad8388SMartin Matuska 
23981ad8388SMartin Matuska 		coder->block_options.filters = NULL;
24081ad8388SMartin Matuska 
24181ad8388SMartin Matuska 		// Check if memory usage calculation and Block enocoder
24281ad8388SMartin Matuska 		// initialization succeeded.
24381ad8388SMartin Matuska 		if (ret != LZMA_OK)
24481ad8388SMartin Matuska 			return ret;
24581ad8388SMartin Matuska 
24681ad8388SMartin Matuska 		coder->sequence = SEQ_BLOCK;
24781ad8388SMartin Matuska 	}
24881ad8388SMartin Matuska 
24981ad8388SMartin Matuska 	// Fall through
25081ad8388SMartin Matuska 
25181ad8388SMartin Matuska 	case SEQ_BLOCK: {
25281ad8388SMartin Matuska 		const lzma_ret ret = coder->block_decoder.code(
25381ad8388SMartin Matuska 				coder->block_decoder.coder, allocator,
25481ad8388SMartin Matuska 				in, in_pos, in_size, out, out_pos, out_size,
25581ad8388SMartin Matuska 				action);
25681ad8388SMartin Matuska 
25781ad8388SMartin Matuska 		if (ret != LZMA_STREAM_END)
25881ad8388SMartin Matuska 			return ret;
25981ad8388SMartin Matuska 
26081ad8388SMartin Matuska 		// Block decoded successfully. Add the new size pair to
26181ad8388SMartin Matuska 		// the Index hash.
26281ad8388SMartin Matuska 		return_if_error(lzma_index_hash_append(coder->index_hash,
26381ad8388SMartin Matuska 				lzma_block_unpadded_size(
26481ad8388SMartin Matuska 					&coder->block_options),
26581ad8388SMartin Matuska 				coder->block_options.uncompressed_size));
26681ad8388SMartin Matuska 
26781ad8388SMartin Matuska 		coder->sequence = SEQ_BLOCK_HEADER;
26881ad8388SMartin Matuska 		break;
26981ad8388SMartin Matuska 	}
27081ad8388SMartin Matuska 
27181ad8388SMartin Matuska 	case SEQ_INDEX: {
27281ad8388SMartin Matuska 		// If we don't have any input, don't call
27381ad8388SMartin Matuska 		// lzma_index_hash_decode() since it would return
27481ad8388SMartin Matuska 		// LZMA_BUF_ERROR, which we must not do here.
27581ad8388SMartin Matuska 		if (*in_pos >= in_size)
27681ad8388SMartin Matuska 			return LZMA_OK;
27781ad8388SMartin Matuska 
27881ad8388SMartin Matuska 		// Decode the Index and compare it to the hash calculated
27981ad8388SMartin Matuska 		// from the sizes of the Blocks (if any).
28081ad8388SMartin Matuska 		const lzma_ret ret = lzma_index_hash_decode(coder->index_hash,
28181ad8388SMartin Matuska 				in, in_pos, in_size);
28281ad8388SMartin Matuska 		if (ret != LZMA_STREAM_END)
28381ad8388SMartin Matuska 			return ret;
28481ad8388SMartin Matuska 
28581ad8388SMartin Matuska 		coder->sequence = SEQ_STREAM_FOOTER;
28681ad8388SMartin Matuska 	}
28781ad8388SMartin Matuska 
28881ad8388SMartin Matuska 	// Fall through
28981ad8388SMartin Matuska 
29081ad8388SMartin Matuska 	case SEQ_STREAM_FOOTER: {
29181ad8388SMartin Matuska 		// Copy the Stream Footer to the internal buffer.
29281ad8388SMartin Matuska 		lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
29381ad8388SMartin Matuska 				LZMA_STREAM_HEADER_SIZE);
29481ad8388SMartin Matuska 
29581ad8388SMartin Matuska 		// Return if we didn't get the whole Stream Footer yet.
29681ad8388SMartin Matuska 		if (coder->pos < LZMA_STREAM_HEADER_SIZE)
29781ad8388SMartin Matuska 			return LZMA_OK;
29881ad8388SMartin Matuska 
29981ad8388SMartin Matuska 		coder->pos = 0;
30081ad8388SMartin Matuska 
30181ad8388SMartin Matuska 		// Decode the Stream Footer. The decoder gives
30281ad8388SMartin Matuska 		// LZMA_FORMAT_ERROR if the magic bytes don't match,
30381ad8388SMartin Matuska 		// so convert that return code to LZMA_DATA_ERROR.
30481ad8388SMartin Matuska 		lzma_stream_flags footer_flags;
30581ad8388SMartin Matuska 		const lzma_ret ret = lzma_stream_footer_decode(
30681ad8388SMartin Matuska 				&footer_flags, coder->buffer);
30781ad8388SMartin Matuska 		if (ret != LZMA_OK)
30881ad8388SMartin Matuska 			return ret == LZMA_FORMAT_ERROR
30981ad8388SMartin Matuska 					? LZMA_DATA_ERROR : ret;
31081ad8388SMartin Matuska 
31181ad8388SMartin Matuska 		// Check that Index Size stored in the Stream Footer matches
31281ad8388SMartin Matuska 		// the real size of the Index field.
31381ad8388SMartin Matuska 		if (lzma_index_hash_size(coder->index_hash)
31481ad8388SMartin Matuska 				!= footer_flags.backward_size)
31581ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
31681ad8388SMartin Matuska 
31781ad8388SMartin Matuska 		// Compare that the Stream Flags fields are identical in
31881ad8388SMartin Matuska 		// both Stream Header and Stream Footer.
31981ad8388SMartin Matuska 		return_if_error(lzma_stream_flags_compare(
32081ad8388SMartin Matuska 				&coder->stream_flags, &footer_flags));
32181ad8388SMartin Matuska 
32281ad8388SMartin Matuska 		if (!coder->concatenated)
32381ad8388SMartin Matuska 			return LZMA_STREAM_END;
32481ad8388SMartin Matuska 
32581ad8388SMartin Matuska 		coder->sequence = SEQ_STREAM_PADDING;
32681ad8388SMartin Matuska 	}
32781ad8388SMartin Matuska 
32881ad8388SMartin Matuska 	// Fall through
32981ad8388SMartin Matuska 
33081ad8388SMartin Matuska 	case SEQ_STREAM_PADDING:
33181ad8388SMartin Matuska 		assert(coder->concatenated);
33281ad8388SMartin Matuska 
33381ad8388SMartin Matuska 		// Skip over possible Stream Padding.
33481ad8388SMartin Matuska 		while (true) {
33581ad8388SMartin Matuska 			if (*in_pos >= in_size) {
33681ad8388SMartin Matuska 				// Unless LZMA_FINISH was used, we cannot
33781ad8388SMartin Matuska 				// know if there's more input coming later.
33881ad8388SMartin Matuska 				if (action != LZMA_FINISH)
33981ad8388SMartin Matuska 					return LZMA_OK;
34081ad8388SMartin Matuska 
34181ad8388SMartin Matuska 				// Stream Padding must be a multiple of
34281ad8388SMartin Matuska 				// four bytes.
34381ad8388SMartin Matuska 				return coder->pos == 0
34481ad8388SMartin Matuska 						? LZMA_STREAM_END
34581ad8388SMartin Matuska 						: LZMA_DATA_ERROR;
34681ad8388SMartin Matuska 			}
34781ad8388SMartin Matuska 
34881ad8388SMartin Matuska 			// If the byte is not zero, it probably indicates
34981ad8388SMartin Matuska 			// beginning of a new Stream (or the file is corrupt).
35081ad8388SMartin Matuska 			if (in[*in_pos] != 0x00)
35181ad8388SMartin Matuska 				break;
35281ad8388SMartin Matuska 
35381ad8388SMartin Matuska 			++*in_pos;
35481ad8388SMartin Matuska 			coder->pos = (coder->pos + 1) & 3;
35581ad8388SMartin Matuska 		}
35681ad8388SMartin Matuska 
35781ad8388SMartin Matuska 		// Stream Padding must be a multiple of four bytes (empty
35881ad8388SMartin Matuska 		// Stream Padding is OK).
35981ad8388SMartin Matuska 		if (coder->pos != 0) {
36081ad8388SMartin Matuska 			++*in_pos;
36181ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
36281ad8388SMartin Matuska 		}
36381ad8388SMartin Matuska 
36481ad8388SMartin Matuska 		// Prepare to decode the next Stream.
36581ad8388SMartin Matuska 		return_if_error(stream_decoder_reset(coder, allocator));
36681ad8388SMartin Matuska 		break;
36781ad8388SMartin Matuska 
36881ad8388SMartin Matuska 	default:
36981ad8388SMartin Matuska 		assert(0);
37081ad8388SMartin Matuska 		return LZMA_PROG_ERROR;
37181ad8388SMartin Matuska 	}
37281ad8388SMartin Matuska 
37381ad8388SMartin Matuska 	// Never reached
37481ad8388SMartin Matuska }
37581ad8388SMartin Matuska 
37681ad8388SMartin Matuska 
37781ad8388SMartin Matuska static void
378*53200025SRui Paulo stream_decoder_end(lzma_coder *coder, const lzma_allocator *allocator)
37981ad8388SMartin Matuska {
38081ad8388SMartin Matuska 	lzma_next_end(&coder->block_decoder, allocator);
38181ad8388SMartin Matuska 	lzma_index_hash_end(coder->index_hash, allocator);
38281ad8388SMartin Matuska 	lzma_free(coder, allocator);
38381ad8388SMartin Matuska 	return;
38481ad8388SMartin Matuska }
38581ad8388SMartin Matuska 
38681ad8388SMartin Matuska 
38781ad8388SMartin Matuska static lzma_check
38881ad8388SMartin Matuska stream_decoder_get_check(const lzma_coder *coder)
38981ad8388SMartin Matuska {
39081ad8388SMartin Matuska 	return coder->stream_flags.check;
39181ad8388SMartin Matuska }
39281ad8388SMartin Matuska 
39381ad8388SMartin Matuska 
39481ad8388SMartin Matuska static lzma_ret
39581ad8388SMartin Matuska stream_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
39681ad8388SMartin Matuska 		uint64_t *old_memlimit, uint64_t new_memlimit)
39781ad8388SMartin Matuska {
39881ad8388SMartin Matuska 	*memusage = coder->memusage;
39981ad8388SMartin Matuska 	*old_memlimit = coder->memlimit;
40081ad8388SMartin Matuska 
40181ad8388SMartin Matuska 	if (new_memlimit != 0) {
40281ad8388SMartin Matuska 		if (new_memlimit < coder->memusage)
40381ad8388SMartin Matuska 			return LZMA_MEMLIMIT_ERROR;
40481ad8388SMartin Matuska 
40581ad8388SMartin Matuska 		coder->memlimit = new_memlimit;
40681ad8388SMartin Matuska 	}
40781ad8388SMartin Matuska 
40881ad8388SMartin Matuska 	return LZMA_OK;
40981ad8388SMartin Matuska }
41081ad8388SMartin Matuska 
41181ad8388SMartin Matuska 
41281ad8388SMartin Matuska extern lzma_ret
413*53200025SRui Paulo lzma_stream_decoder_init(
414*53200025SRui Paulo 		lzma_next_coder *next, const lzma_allocator *allocator,
41581ad8388SMartin Matuska 		uint64_t memlimit, uint32_t flags)
41681ad8388SMartin Matuska {
41781ad8388SMartin Matuska 	lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator);
41881ad8388SMartin Matuska 
41981ad8388SMartin Matuska 	if (memlimit == 0)
42081ad8388SMartin Matuska 		return LZMA_PROG_ERROR;
42181ad8388SMartin Matuska 
42281ad8388SMartin Matuska 	if (flags & ~LZMA_SUPPORTED_FLAGS)
42381ad8388SMartin Matuska 		return LZMA_OPTIONS_ERROR;
42481ad8388SMartin Matuska 
42581ad8388SMartin Matuska 	if (next->coder == NULL) {
42681ad8388SMartin Matuska 		next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
42781ad8388SMartin Matuska 		if (next->coder == NULL)
42881ad8388SMartin Matuska 			return LZMA_MEM_ERROR;
42981ad8388SMartin Matuska 
43081ad8388SMartin Matuska 		next->code = &stream_decode;
43181ad8388SMartin Matuska 		next->end = &stream_decoder_end;
43281ad8388SMartin Matuska 		next->get_check = &stream_decoder_get_check;
43381ad8388SMartin Matuska 		next->memconfig = &stream_decoder_memconfig;
43481ad8388SMartin Matuska 
43581ad8388SMartin Matuska 		next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
43681ad8388SMartin Matuska 		next->coder->index_hash = NULL;
43781ad8388SMartin Matuska 	}
43881ad8388SMartin Matuska 
43981ad8388SMartin Matuska 	next->coder->memlimit = memlimit;
44081ad8388SMartin Matuska 	next->coder->memusage = LZMA_MEMUSAGE_BASE;
44181ad8388SMartin Matuska 	next->coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0;
44281ad8388SMartin Matuska 	next->coder->tell_unsupported_check
44381ad8388SMartin Matuska 			= (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
44481ad8388SMartin Matuska 	next->coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
445*53200025SRui Paulo 	next->coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0;
44681ad8388SMartin Matuska 	next->coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
44781ad8388SMartin Matuska 	next->coder->first_stream = true;
44881ad8388SMartin Matuska 
44981ad8388SMartin Matuska 	return stream_decoder_reset(next->coder, allocator);
45081ad8388SMartin Matuska }
45181ad8388SMartin Matuska 
45281ad8388SMartin Matuska 
45381ad8388SMartin Matuska extern LZMA_API(lzma_ret)
45481ad8388SMartin Matuska lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
45581ad8388SMartin Matuska {
45681ad8388SMartin Matuska 	lzma_next_strm_init(lzma_stream_decoder_init, strm, memlimit, flags);
45781ad8388SMartin Matuska 
45881ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_RUN] = true;
45981ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_FINISH] = true;
46081ad8388SMartin Matuska 
46181ad8388SMartin Matuska 	return LZMA_OK;
46281ad8388SMartin Matuska }
463