xref: /freebsd/contrib/xz/src/liblzma/common/block_decoder.c (revision 532000256b898d5d3b0067ffa328715d18f4776d)
181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
281ad8388SMartin Matuska //
381ad8388SMartin Matuska /// \file       block_decoder.c
481ad8388SMartin Matuska /// \brief      Decodes .xz Blocks
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 "block_decoder.h"
1481ad8388SMartin Matuska #include "filter_decoder.h"
1581ad8388SMartin Matuska #include "check.h"
1681ad8388SMartin Matuska 
1781ad8388SMartin Matuska 
1881ad8388SMartin Matuska struct lzma_coder_s {
1981ad8388SMartin Matuska 	enum {
2081ad8388SMartin Matuska 		SEQ_CODE,
2181ad8388SMartin Matuska 		SEQ_PADDING,
2281ad8388SMartin Matuska 		SEQ_CHECK,
2381ad8388SMartin Matuska 	} sequence;
2481ad8388SMartin Matuska 
2581ad8388SMartin Matuska 	/// The filters in the chain; initialized with lzma_raw_decoder_init().
2681ad8388SMartin Matuska 	lzma_next_coder next;
2781ad8388SMartin Matuska 
2881ad8388SMartin Matuska 	/// Decoding options; we also write Compressed Size and Uncompressed
2981ad8388SMartin Matuska 	/// Size back to this structure when the decoding has been finished.
3081ad8388SMartin Matuska 	lzma_block *block;
3181ad8388SMartin Matuska 
3281ad8388SMartin Matuska 	/// Compressed Size calculated while decoding
3381ad8388SMartin Matuska 	lzma_vli compressed_size;
3481ad8388SMartin Matuska 
3581ad8388SMartin Matuska 	/// Uncompressed Size calculated while decoding
3681ad8388SMartin Matuska 	lzma_vli uncompressed_size;
3781ad8388SMartin Matuska 
3881ad8388SMartin Matuska 	/// Maximum allowed Compressed Size; this takes into account the
3981ad8388SMartin Matuska 	/// size of the Block Header and Check fields when Compressed Size
4081ad8388SMartin Matuska 	/// is unknown.
4181ad8388SMartin Matuska 	lzma_vli compressed_limit;
4281ad8388SMartin Matuska 
4381ad8388SMartin Matuska 	/// Position when reading the Check field
4481ad8388SMartin Matuska 	size_t check_pos;
4581ad8388SMartin Matuska 
4681ad8388SMartin Matuska 	/// Check of the uncompressed data
4781ad8388SMartin Matuska 	lzma_check_state check;
48*53200025SRui Paulo 
49*53200025SRui Paulo 	/// True if the integrity check won't be calculated and verified.
50*53200025SRui Paulo 	bool ignore_check;
5181ad8388SMartin Matuska };
5281ad8388SMartin Matuska 
5381ad8388SMartin Matuska 
5481ad8388SMartin Matuska static inline bool
5581ad8388SMartin Matuska update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
5681ad8388SMartin Matuska {
5781ad8388SMartin Matuska 	if (limit > LZMA_VLI_MAX)
5881ad8388SMartin Matuska 		limit = LZMA_VLI_MAX;
5981ad8388SMartin Matuska 
6081ad8388SMartin Matuska 	if (limit < *size || limit - *size < add)
6181ad8388SMartin Matuska 		return true;
6281ad8388SMartin Matuska 
6381ad8388SMartin Matuska 	*size += add;
6481ad8388SMartin Matuska 
6581ad8388SMartin Matuska 	return false;
6681ad8388SMartin Matuska }
6781ad8388SMartin Matuska 
6881ad8388SMartin Matuska 
6981ad8388SMartin Matuska static inline bool
7081ad8388SMartin Matuska is_size_valid(lzma_vli size, lzma_vli reference)
7181ad8388SMartin Matuska {
7281ad8388SMartin Matuska 	return reference == LZMA_VLI_UNKNOWN || reference == size;
7381ad8388SMartin Matuska }
7481ad8388SMartin Matuska 
7581ad8388SMartin Matuska 
7681ad8388SMartin Matuska static lzma_ret
77*53200025SRui Paulo block_decode(lzma_coder *coder, const lzma_allocator *allocator,
7881ad8388SMartin Matuska 		const uint8_t *restrict in, size_t *restrict in_pos,
7981ad8388SMartin Matuska 		size_t in_size, uint8_t *restrict out,
8081ad8388SMartin Matuska 		size_t *restrict out_pos, size_t out_size, lzma_action action)
8181ad8388SMartin Matuska {
8281ad8388SMartin Matuska 	switch (coder->sequence) {
8381ad8388SMartin Matuska 	case SEQ_CODE: {
8481ad8388SMartin Matuska 		const size_t in_start = *in_pos;
8581ad8388SMartin Matuska 		const size_t out_start = *out_pos;
8681ad8388SMartin Matuska 
8781ad8388SMartin Matuska 		const lzma_ret ret = coder->next.code(coder->next.coder,
8881ad8388SMartin Matuska 				allocator, in, in_pos, in_size,
8981ad8388SMartin Matuska 				out, out_pos, out_size, action);
9081ad8388SMartin Matuska 
9181ad8388SMartin Matuska 		const size_t in_used = *in_pos - in_start;
9281ad8388SMartin Matuska 		const size_t out_used = *out_pos - out_start;
9381ad8388SMartin Matuska 
9481ad8388SMartin Matuska 		// NOTE: We compare to compressed_limit here, which prevents
9581ad8388SMartin Matuska 		// the total size of the Block growing past LZMA_VLI_MAX.
9681ad8388SMartin Matuska 		if (update_size(&coder->compressed_size, in_used,
9781ad8388SMartin Matuska 					coder->compressed_limit)
9881ad8388SMartin Matuska 				|| update_size(&coder->uncompressed_size,
9981ad8388SMartin Matuska 					out_used,
10081ad8388SMartin Matuska 					coder->block->uncompressed_size))
10181ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
10281ad8388SMartin Matuska 
103*53200025SRui Paulo 		if (!coder->ignore_check)
10481ad8388SMartin Matuska 			lzma_check_update(&coder->check, coder->block->check,
10581ad8388SMartin Matuska 					out + out_start, out_used);
10681ad8388SMartin Matuska 
10781ad8388SMartin Matuska 		if (ret != LZMA_STREAM_END)
10881ad8388SMartin Matuska 			return ret;
10981ad8388SMartin Matuska 
11081ad8388SMartin Matuska 		// Compressed and Uncompressed Sizes are now at their final
11181ad8388SMartin Matuska 		// values. Verify that they match the values given to us.
11281ad8388SMartin Matuska 		if (!is_size_valid(coder->compressed_size,
11381ad8388SMartin Matuska 					coder->block->compressed_size)
11481ad8388SMartin Matuska 				|| !is_size_valid(coder->uncompressed_size,
11581ad8388SMartin Matuska 					coder->block->uncompressed_size))
11681ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
11781ad8388SMartin Matuska 
11881ad8388SMartin Matuska 		// Copy the values into coder->block. The caller
11981ad8388SMartin Matuska 		// may use this information to construct Index.
12081ad8388SMartin Matuska 		coder->block->compressed_size = coder->compressed_size;
12181ad8388SMartin Matuska 		coder->block->uncompressed_size = coder->uncompressed_size;
12281ad8388SMartin Matuska 
12381ad8388SMartin Matuska 		coder->sequence = SEQ_PADDING;
12481ad8388SMartin Matuska 	}
12581ad8388SMartin Matuska 
12681ad8388SMartin Matuska 	// Fall through
12781ad8388SMartin Matuska 
12881ad8388SMartin Matuska 	case SEQ_PADDING:
12981ad8388SMartin Matuska 		// Compressed Data is padded to a multiple of four bytes.
13081ad8388SMartin Matuska 		while (coder->compressed_size & 3) {
13181ad8388SMartin Matuska 			if (*in_pos >= in_size)
13281ad8388SMartin Matuska 				return LZMA_OK;
13381ad8388SMartin Matuska 
13481ad8388SMartin Matuska 			// We use compressed_size here just get the Padding
13581ad8388SMartin Matuska 			// right. The actual Compressed Size was stored to
13681ad8388SMartin Matuska 			// coder->block already, and won't be modified by
13781ad8388SMartin Matuska 			// us anymore.
13881ad8388SMartin Matuska 			++coder->compressed_size;
13981ad8388SMartin Matuska 
14081ad8388SMartin Matuska 			if (in[(*in_pos)++] != 0x00)
14181ad8388SMartin Matuska 				return LZMA_DATA_ERROR;
14281ad8388SMartin Matuska 		}
14381ad8388SMartin Matuska 
14481ad8388SMartin Matuska 		if (coder->block->check == LZMA_CHECK_NONE)
14581ad8388SMartin Matuska 			return LZMA_STREAM_END;
14681ad8388SMartin Matuska 
147*53200025SRui Paulo 		if (!coder->ignore_check)
14881ad8388SMartin Matuska 			lzma_check_finish(&coder->check, coder->block->check);
149*53200025SRui Paulo 
15081ad8388SMartin Matuska 		coder->sequence = SEQ_CHECK;
15181ad8388SMartin Matuska 
15281ad8388SMartin Matuska 	// Fall through
15381ad8388SMartin Matuska 
15481ad8388SMartin Matuska 	case SEQ_CHECK: {
15581ad8388SMartin Matuska 		const size_t check_size = lzma_check_size(coder->block->check);
15681ad8388SMartin Matuska 		lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
15781ad8388SMartin Matuska 				&coder->check_pos, check_size);
15881ad8388SMartin Matuska 		if (coder->check_pos < check_size)
15981ad8388SMartin Matuska 			return LZMA_OK;
16081ad8388SMartin Matuska 
16181ad8388SMartin Matuska 		// Validate the Check only if we support it.
16281ad8388SMartin Matuska 		// coder->check.buffer may be uninitialized
16381ad8388SMartin Matuska 		// when the Check ID is not supported.
164*53200025SRui Paulo 		if (!coder->ignore_check
165*53200025SRui Paulo 				&& lzma_check_is_supported(coder->block->check)
16681ad8388SMartin Matuska 				&& memcmp(coder->block->raw_check,
16781ad8388SMartin Matuska 					coder->check.buffer.u8,
16881ad8388SMartin Matuska 					check_size) != 0)
16981ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
17081ad8388SMartin Matuska 
17181ad8388SMartin Matuska 		return LZMA_STREAM_END;
17281ad8388SMartin Matuska 	}
17381ad8388SMartin Matuska 	}
17481ad8388SMartin Matuska 
17581ad8388SMartin Matuska 	return LZMA_PROG_ERROR;
17681ad8388SMartin Matuska }
17781ad8388SMartin Matuska 
17881ad8388SMartin Matuska 
17981ad8388SMartin Matuska static void
180*53200025SRui Paulo block_decoder_end(lzma_coder *coder, const lzma_allocator *allocator)
18181ad8388SMartin Matuska {
18281ad8388SMartin Matuska 	lzma_next_end(&coder->next, allocator);
18381ad8388SMartin Matuska 	lzma_free(coder, allocator);
18481ad8388SMartin Matuska 	return;
18581ad8388SMartin Matuska }
18681ad8388SMartin Matuska 
18781ad8388SMartin Matuska 
18881ad8388SMartin Matuska extern lzma_ret
189*53200025SRui Paulo lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
19081ad8388SMartin Matuska 		lzma_block *block)
19181ad8388SMartin Matuska {
19281ad8388SMartin Matuska 	lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
19381ad8388SMartin Matuska 
19481ad8388SMartin Matuska 	// Validate the options. lzma_block_unpadded_size() does that for us
19581ad8388SMartin Matuska 	// except for Uncompressed Size and filters. Filters are validated
19681ad8388SMartin Matuska 	// by the raw decoder.
19781ad8388SMartin Matuska 	if (lzma_block_unpadded_size(block) == 0
19881ad8388SMartin Matuska 			|| !lzma_vli_is_valid(block->uncompressed_size))
19981ad8388SMartin Matuska 		return LZMA_PROG_ERROR;
20081ad8388SMartin Matuska 
20181ad8388SMartin Matuska 	// Allocate and initialize *next->coder if needed.
20281ad8388SMartin Matuska 	if (next->coder == NULL) {
20381ad8388SMartin Matuska 		next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
20481ad8388SMartin Matuska 		if (next->coder == NULL)
20581ad8388SMartin Matuska 			return LZMA_MEM_ERROR;
20681ad8388SMartin Matuska 
20781ad8388SMartin Matuska 		next->code = &block_decode;
20881ad8388SMartin Matuska 		next->end = &block_decoder_end;
20981ad8388SMartin Matuska 		next->coder->next = LZMA_NEXT_CODER_INIT;
21081ad8388SMartin Matuska 	}
21181ad8388SMartin Matuska 
21281ad8388SMartin Matuska 	// Basic initializations
21381ad8388SMartin Matuska 	next->coder->sequence = SEQ_CODE;
21481ad8388SMartin Matuska 	next->coder->block = block;
21581ad8388SMartin Matuska 	next->coder->compressed_size = 0;
21681ad8388SMartin Matuska 	next->coder->uncompressed_size = 0;
21781ad8388SMartin Matuska 
21881ad8388SMartin Matuska 	// If Compressed Size is not known, we calculate the maximum allowed
21981ad8388SMartin Matuska 	// value so that encoded size of the Block (including Block Padding)
22081ad8388SMartin Matuska 	// is still a valid VLI and a multiple of four.
22181ad8388SMartin Matuska 	next->coder->compressed_limit
22281ad8388SMartin Matuska 			= block->compressed_size == LZMA_VLI_UNKNOWN
22381ad8388SMartin Matuska 				? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
22481ad8388SMartin Matuska 					- block->header_size
22581ad8388SMartin Matuska 					- lzma_check_size(block->check)
22681ad8388SMartin Matuska 				: block->compressed_size;
22781ad8388SMartin Matuska 
22881ad8388SMartin Matuska 	// Initialize the check. It's caller's problem if the Check ID is not
22981ad8388SMartin Matuska 	// supported, and the Block decoder cannot verify the Check field.
23081ad8388SMartin Matuska 	// Caller can test lzma_check_is_supported(block->check).
23181ad8388SMartin Matuska 	next->coder->check_pos = 0;
23281ad8388SMartin Matuska 	lzma_check_init(&next->coder->check, block->check);
23381ad8388SMartin Matuska 
234*53200025SRui Paulo 	next->coder->ignore_check = block->version >= 1
235*53200025SRui Paulo 			? block->ignore_check : false;
236*53200025SRui Paulo 
23781ad8388SMartin Matuska 	// Initialize the filter chain.
23881ad8388SMartin Matuska 	return lzma_raw_decoder_init(&next->coder->next, allocator,
23981ad8388SMartin Matuska 			block->filters);
24081ad8388SMartin Matuska }
24181ad8388SMartin Matuska 
24281ad8388SMartin Matuska 
24381ad8388SMartin Matuska extern LZMA_API(lzma_ret)
24481ad8388SMartin Matuska lzma_block_decoder(lzma_stream *strm, lzma_block *block)
24581ad8388SMartin Matuska {
24681ad8388SMartin Matuska 	lzma_next_strm_init(lzma_block_decoder_init, strm, block);
24781ad8388SMartin Matuska 
24881ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_RUN] = true;
24981ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_FINISH] = true;
25081ad8388SMartin Matuska 
25181ad8388SMartin Matuska 	return LZMA_OK;
25281ad8388SMartin Matuska }
253