xref: /freebsd-src/sys/contrib/xz-embedded/linux/lib/xz/xz_dec_stream.c (revision cd3a777bca91669fc4711d1eff66c40f3f62a223)
163dab8eeSAdrian Chadd /*
263dab8eeSAdrian Chadd  * .xz Stream decoder
363dab8eeSAdrian Chadd  *
463dab8eeSAdrian Chadd  * Author: Lasse Collin <lasse.collin@tukaani.org>
563dab8eeSAdrian Chadd  *
663dab8eeSAdrian Chadd  * This file has been put into the public domain.
763dab8eeSAdrian Chadd  * You can do whatever you want with this file.
863dab8eeSAdrian Chadd  */
963dab8eeSAdrian Chadd 
1063dab8eeSAdrian Chadd #include "xz_private.h"
1163dab8eeSAdrian Chadd #include "xz_stream.h"
1263dab8eeSAdrian Chadd 
13f0bd5302SXin LI #ifdef XZ_USE_CRC64
14f0bd5302SXin LI #	define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
15f0bd5302SXin LI #else
16f0bd5302SXin LI #	define IS_CRC64(check_type) false
17f0bd5302SXin LI #endif
18f0bd5302SXin LI 
1963dab8eeSAdrian Chadd /* Hash used to validate the Index field */
2063dab8eeSAdrian Chadd struct xz_dec_hash {
2163dab8eeSAdrian Chadd 	vli_type unpadded;
2263dab8eeSAdrian Chadd 	vli_type uncompressed;
2363dab8eeSAdrian Chadd 	uint32_t crc32;
2463dab8eeSAdrian Chadd };
2563dab8eeSAdrian Chadd 
2663dab8eeSAdrian Chadd struct xz_dec {
2763dab8eeSAdrian Chadd 	/* Position in dec_main() */
2863dab8eeSAdrian Chadd 	enum {
2963dab8eeSAdrian Chadd 		SEQ_STREAM_HEADER,
3063dab8eeSAdrian Chadd 		SEQ_BLOCK_START,
3163dab8eeSAdrian Chadd 		SEQ_BLOCK_HEADER,
3263dab8eeSAdrian Chadd 		SEQ_BLOCK_UNCOMPRESS,
3363dab8eeSAdrian Chadd 		SEQ_BLOCK_PADDING,
3463dab8eeSAdrian Chadd 		SEQ_BLOCK_CHECK,
3563dab8eeSAdrian Chadd 		SEQ_INDEX,
3663dab8eeSAdrian Chadd 		SEQ_INDEX_PADDING,
3763dab8eeSAdrian Chadd 		SEQ_INDEX_CRC32,
38*cd3a777bSXin LI 		SEQ_STREAM_FOOTER,
39*cd3a777bSXin LI 		SEQ_STREAM_PADDING
4063dab8eeSAdrian Chadd 	} sequence;
4163dab8eeSAdrian Chadd 
4263dab8eeSAdrian Chadd 	/* Position in variable-length integers and Check fields */
4363dab8eeSAdrian Chadd 	uint32_t pos;
4463dab8eeSAdrian Chadd 
4563dab8eeSAdrian Chadd 	/* Variable-length integer decoded by dec_vli() */
4663dab8eeSAdrian Chadd 	vli_type vli;
4763dab8eeSAdrian Chadd 
4863dab8eeSAdrian Chadd 	/* Saved in_pos and out_pos */
4963dab8eeSAdrian Chadd 	size_t in_start;
5063dab8eeSAdrian Chadd 	size_t out_start;
5163dab8eeSAdrian Chadd 
52f0bd5302SXin LI #ifdef XZ_USE_CRC64
53f0bd5302SXin LI 	/* CRC32 or CRC64 value in Block or CRC32 value in Index */
54f0bd5302SXin LI 	uint64_t crc;
55f0bd5302SXin LI #else
5663dab8eeSAdrian Chadd 	/* CRC32 value in Block or Index */
57f0bd5302SXin LI 	uint32_t crc;
58f0bd5302SXin LI #endif
5963dab8eeSAdrian Chadd 
6063dab8eeSAdrian Chadd 	/* Type of the integrity check calculated from uncompressed data */
6163dab8eeSAdrian Chadd 	enum xz_check check_type;
6263dab8eeSAdrian Chadd 
6363dab8eeSAdrian Chadd 	/* Operation mode */
6463dab8eeSAdrian Chadd 	enum xz_mode mode;
6563dab8eeSAdrian Chadd 
6663dab8eeSAdrian Chadd 	/*
6763dab8eeSAdrian Chadd 	 * True if the next call to xz_dec_run() is allowed to return
6863dab8eeSAdrian Chadd 	 * XZ_BUF_ERROR.
6963dab8eeSAdrian Chadd 	 */
7063dab8eeSAdrian Chadd 	bool allow_buf_error;
7163dab8eeSAdrian Chadd 
7263dab8eeSAdrian Chadd 	/* Information stored in Block Header */
7363dab8eeSAdrian Chadd 	struct {
7463dab8eeSAdrian Chadd 		/*
7563dab8eeSAdrian Chadd 		 * Value stored in the Compressed Size field, or
7663dab8eeSAdrian Chadd 		 * VLI_UNKNOWN if Compressed Size is not present.
7763dab8eeSAdrian Chadd 		 */
7863dab8eeSAdrian Chadd 		vli_type compressed;
7963dab8eeSAdrian Chadd 
8063dab8eeSAdrian Chadd 		/*
8163dab8eeSAdrian Chadd 		 * Value stored in the Uncompressed Size field, or
8263dab8eeSAdrian Chadd 		 * VLI_UNKNOWN if Uncompressed Size is not present.
8363dab8eeSAdrian Chadd 		 */
8463dab8eeSAdrian Chadd 		vli_type uncompressed;
8563dab8eeSAdrian Chadd 
8663dab8eeSAdrian Chadd 		/* Size of the Block Header field */
8763dab8eeSAdrian Chadd 		uint32_t size;
8863dab8eeSAdrian Chadd 	} block_header;
8963dab8eeSAdrian Chadd 
9063dab8eeSAdrian Chadd 	/* Information collected when decoding Blocks */
9163dab8eeSAdrian Chadd 	struct {
9263dab8eeSAdrian Chadd 		/* Observed compressed size of the current Block */
9363dab8eeSAdrian Chadd 		vli_type compressed;
9463dab8eeSAdrian Chadd 
9563dab8eeSAdrian Chadd 		/* Observed uncompressed size of the current Block */
9663dab8eeSAdrian Chadd 		vli_type uncompressed;
9763dab8eeSAdrian Chadd 
9863dab8eeSAdrian Chadd 		/* Number of Blocks decoded so far */
9963dab8eeSAdrian Chadd 		vli_type count;
10063dab8eeSAdrian Chadd 
10163dab8eeSAdrian Chadd 		/*
10263dab8eeSAdrian Chadd 		 * Hash calculated from the Block sizes. This is used to
10363dab8eeSAdrian Chadd 		 * validate the Index field.
10463dab8eeSAdrian Chadd 		 */
10563dab8eeSAdrian Chadd 		struct xz_dec_hash hash;
10663dab8eeSAdrian Chadd 	} block;
10763dab8eeSAdrian Chadd 
10863dab8eeSAdrian Chadd 	/* Variables needed when verifying the Index field */
10963dab8eeSAdrian Chadd 	struct {
11063dab8eeSAdrian Chadd 		/* Position in dec_index() */
11163dab8eeSAdrian Chadd 		enum {
11263dab8eeSAdrian Chadd 			SEQ_INDEX_COUNT,
11363dab8eeSAdrian Chadd 			SEQ_INDEX_UNPADDED,
11463dab8eeSAdrian Chadd 			SEQ_INDEX_UNCOMPRESSED
11563dab8eeSAdrian Chadd 		} sequence;
11663dab8eeSAdrian Chadd 
11763dab8eeSAdrian Chadd 		/* Size of the Index in bytes */
11863dab8eeSAdrian Chadd 		vli_type size;
11963dab8eeSAdrian Chadd 
12063dab8eeSAdrian Chadd 		/* Number of Records (matches block.count in valid files) */
12163dab8eeSAdrian Chadd 		vli_type count;
12263dab8eeSAdrian Chadd 
12363dab8eeSAdrian Chadd 		/*
12463dab8eeSAdrian Chadd 		 * Hash calculated from the Records (matches block.hash in
12563dab8eeSAdrian Chadd 		 * valid files).
12663dab8eeSAdrian Chadd 		 */
12763dab8eeSAdrian Chadd 		struct xz_dec_hash hash;
12863dab8eeSAdrian Chadd 	} index;
12963dab8eeSAdrian Chadd 
13063dab8eeSAdrian Chadd 	/*
13163dab8eeSAdrian Chadd 	 * Temporary buffer needed to hold Stream Header, Block Header,
13263dab8eeSAdrian Chadd 	 * and Stream Footer. The Block Header is the biggest (1 KiB)
13363dab8eeSAdrian Chadd 	 * so we reserve space according to that. buf[] has to be aligned
13463dab8eeSAdrian Chadd 	 * to a multiple of four bytes; the size_t variables before it
13563dab8eeSAdrian Chadd 	 * should guarantee this.
13663dab8eeSAdrian Chadd 	 */
13763dab8eeSAdrian Chadd 	struct {
13863dab8eeSAdrian Chadd 		size_t pos;
13963dab8eeSAdrian Chadd 		size_t size;
14063dab8eeSAdrian Chadd 		uint8_t buf[1024];
14163dab8eeSAdrian Chadd 	} temp;
14263dab8eeSAdrian Chadd 
14363dab8eeSAdrian Chadd 	struct xz_dec_lzma2 *lzma2;
14463dab8eeSAdrian Chadd 
14563dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
14663dab8eeSAdrian Chadd 	struct xz_dec_bcj *bcj;
14763dab8eeSAdrian Chadd 	bool bcj_active;
14863dab8eeSAdrian Chadd #endif
14963dab8eeSAdrian Chadd };
15063dab8eeSAdrian Chadd 
15163dab8eeSAdrian Chadd #ifdef XZ_DEC_ANY_CHECK
15263dab8eeSAdrian Chadd /* Sizes of the Check field with different Check IDs */
15363dab8eeSAdrian Chadd static const uint8_t check_sizes[16] = {
15463dab8eeSAdrian Chadd 	0,
15563dab8eeSAdrian Chadd 	4, 4, 4,
15663dab8eeSAdrian Chadd 	8, 8, 8,
15763dab8eeSAdrian Chadd 	16, 16, 16,
15863dab8eeSAdrian Chadd 	32, 32, 32,
15963dab8eeSAdrian Chadd 	64, 64, 64
16063dab8eeSAdrian Chadd };
16163dab8eeSAdrian Chadd #endif
16263dab8eeSAdrian Chadd 
16363dab8eeSAdrian Chadd /*
16463dab8eeSAdrian Chadd  * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
16563dab8eeSAdrian Chadd  * must have set s->temp.pos to indicate how much data we are supposed
16663dab8eeSAdrian Chadd  * to copy into s->temp.buf. Return true once s->temp.pos has reached
16763dab8eeSAdrian Chadd  * s->temp.size.
16863dab8eeSAdrian Chadd  */
fill_temp(struct xz_dec * s,struct xz_buf * b)16963dab8eeSAdrian Chadd static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
17063dab8eeSAdrian Chadd {
17163dab8eeSAdrian Chadd 	size_t copy_size = min_t(size_t,
17263dab8eeSAdrian Chadd 			b->in_size - b->in_pos, s->temp.size - s->temp.pos);
17363dab8eeSAdrian Chadd 
17463dab8eeSAdrian Chadd 	memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
17563dab8eeSAdrian Chadd 	b->in_pos += copy_size;
17663dab8eeSAdrian Chadd 	s->temp.pos += copy_size;
17763dab8eeSAdrian Chadd 
17863dab8eeSAdrian Chadd 	if (s->temp.pos == s->temp.size) {
17963dab8eeSAdrian Chadd 		s->temp.pos = 0;
18063dab8eeSAdrian Chadd 		return true;
18163dab8eeSAdrian Chadd 	}
18263dab8eeSAdrian Chadd 
18363dab8eeSAdrian Chadd 	return false;
18463dab8eeSAdrian Chadd }
18563dab8eeSAdrian Chadd 
18663dab8eeSAdrian Chadd /* Decode a variable-length integer (little-endian base-128 encoding) */
dec_vli(struct xz_dec * s,const uint8_t * in,size_t * in_pos,size_t in_size)18763dab8eeSAdrian Chadd static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
18863dab8eeSAdrian Chadd 			   size_t *in_pos, size_t in_size)
18963dab8eeSAdrian Chadd {
19063dab8eeSAdrian Chadd 	uint8_t byte;
19163dab8eeSAdrian Chadd 
19263dab8eeSAdrian Chadd 	if (s->pos == 0)
19363dab8eeSAdrian Chadd 		s->vli = 0;
19463dab8eeSAdrian Chadd 
19563dab8eeSAdrian Chadd 	while (*in_pos < in_size) {
19663dab8eeSAdrian Chadd 		byte = in[*in_pos];
19763dab8eeSAdrian Chadd 		++*in_pos;
19863dab8eeSAdrian Chadd 
19963dab8eeSAdrian Chadd 		s->vli |= (vli_type)(byte & 0x7F) << s->pos;
20063dab8eeSAdrian Chadd 
20163dab8eeSAdrian Chadd 		if ((byte & 0x80) == 0) {
20263dab8eeSAdrian Chadd 			/* Don't allow non-minimal encodings. */
20363dab8eeSAdrian Chadd 			if (byte == 0 && s->pos != 0)
20463dab8eeSAdrian Chadd 				return XZ_DATA_ERROR;
20563dab8eeSAdrian Chadd 
20663dab8eeSAdrian Chadd 			s->pos = 0;
20763dab8eeSAdrian Chadd 			return XZ_STREAM_END;
20863dab8eeSAdrian Chadd 		}
20963dab8eeSAdrian Chadd 
21063dab8eeSAdrian Chadd 		s->pos += 7;
21163dab8eeSAdrian Chadd 		if (s->pos == 7 * VLI_BYTES_MAX)
21263dab8eeSAdrian Chadd 			return XZ_DATA_ERROR;
21363dab8eeSAdrian Chadd 	}
21463dab8eeSAdrian Chadd 
21563dab8eeSAdrian Chadd 	return XZ_OK;
21663dab8eeSAdrian Chadd }
21763dab8eeSAdrian Chadd 
21863dab8eeSAdrian Chadd /*
21963dab8eeSAdrian Chadd  * Decode the Compressed Data field from a Block. Update and validate
22063dab8eeSAdrian Chadd  * the observed compressed and uncompressed sizes of the Block so that
22163dab8eeSAdrian Chadd  * they don't exceed the values possibly stored in the Block Header
22263dab8eeSAdrian Chadd  * (validation assumes that no integer overflow occurs, since vli_type
223f0bd5302SXin LI  * is normally uint64_t). Update the CRC32 or CRC64 value if presence of
224f0bd5302SXin LI  * the CRC32 or CRC64 field was indicated in Stream Header.
22563dab8eeSAdrian Chadd  *
22663dab8eeSAdrian Chadd  * Once the decoding is finished, validate that the observed sizes match
22763dab8eeSAdrian Chadd  * the sizes possibly stored in the Block Header. Update the hash and
22863dab8eeSAdrian Chadd  * Block count, which are later used to validate the Index field.
22963dab8eeSAdrian Chadd  */
dec_block(struct xz_dec * s,struct xz_buf * b)23063dab8eeSAdrian Chadd static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
23163dab8eeSAdrian Chadd {
23263dab8eeSAdrian Chadd 	enum xz_ret ret;
23363dab8eeSAdrian Chadd 
23463dab8eeSAdrian Chadd 	s->in_start = b->in_pos;
23563dab8eeSAdrian Chadd 	s->out_start = b->out_pos;
23663dab8eeSAdrian Chadd 
23763dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
23863dab8eeSAdrian Chadd 	if (s->bcj_active)
23963dab8eeSAdrian Chadd 		ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
24063dab8eeSAdrian Chadd 	else
24163dab8eeSAdrian Chadd #endif
24263dab8eeSAdrian Chadd 		ret = xz_dec_lzma2_run(s->lzma2, b);
24363dab8eeSAdrian Chadd 
24463dab8eeSAdrian Chadd 	s->block.compressed += b->in_pos - s->in_start;
24563dab8eeSAdrian Chadd 	s->block.uncompressed += b->out_pos - s->out_start;
24663dab8eeSAdrian Chadd 
24763dab8eeSAdrian Chadd 	/*
24863dab8eeSAdrian Chadd 	 * There is no need to separately check for VLI_UNKNOWN, since
24963dab8eeSAdrian Chadd 	 * the observed sizes are always smaller than VLI_UNKNOWN.
25063dab8eeSAdrian Chadd 	 */
25163dab8eeSAdrian Chadd 	if (s->block.compressed > s->block_header.compressed
25263dab8eeSAdrian Chadd 			|| s->block.uncompressed
25363dab8eeSAdrian Chadd 				> s->block_header.uncompressed)
25463dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
25563dab8eeSAdrian Chadd 
25663dab8eeSAdrian Chadd 	if (s->check_type == XZ_CHECK_CRC32)
257f0bd5302SXin LI 		s->crc = xz_crc32(b->out + s->out_start,
258f0bd5302SXin LI 				b->out_pos - s->out_start, s->crc);
259f0bd5302SXin LI #ifdef XZ_USE_CRC64
260f0bd5302SXin LI 	else if (s->check_type == XZ_CHECK_CRC64)
261f0bd5302SXin LI 		s->crc = xz_crc64(b->out + s->out_start,
262f0bd5302SXin LI 				b->out_pos - s->out_start, s->crc);
263f0bd5302SXin LI #endif
26463dab8eeSAdrian Chadd 
26563dab8eeSAdrian Chadd 	if (ret == XZ_STREAM_END) {
26663dab8eeSAdrian Chadd 		if (s->block_header.compressed != VLI_UNKNOWN
26763dab8eeSAdrian Chadd 				&& s->block_header.compressed
26863dab8eeSAdrian Chadd 					!= s->block.compressed)
26963dab8eeSAdrian Chadd 			return XZ_DATA_ERROR;
27063dab8eeSAdrian Chadd 
27163dab8eeSAdrian Chadd 		if (s->block_header.uncompressed != VLI_UNKNOWN
27263dab8eeSAdrian Chadd 				&& s->block_header.uncompressed
27363dab8eeSAdrian Chadd 					!= s->block.uncompressed)
27463dab8eeSAdrian Chadd 			return XZ_DATA_ERROR;
27563dab8eeSAdrian Chadd 
27663dab8eeSAdrian Chadd 		s->block.hash.unpadded += s->block_header.size
27763dab8eeSAdrian Chadd 				+ s->block.compressed;
27863dab8eeSAdrian Chadd 
27963dab8eeSAdrian Chadd #ifdef XZ_DEC_ANY_CHECK
28063dab8eeSAdrian Chadd 		s->block.hash.unpadded += check_sizes[s->check_type];
28163dab8eeSAdrian Chadd #else
28263dab8eeSAdrian Chadd 		if (s->check_type == XZ_CHECK_CRC32)
28363dab8eeSAdrian Chadd 			s->block.hash.unpadded += 4;
284f0bd5302SXin LI 		else if (IS_CRC64(s->check_type))
285f0bd5302SXin LI 			s->block.hash.unpadded += 8;
28663dab8eeSAdrian Chadd #endif
28763dab8eeSAdrian Chadd 
28863dab8eeSAdrian Chadd 		s->block.hash.uncompressed += s->block.uncompressed;
28963dab8eeSAdrian Chadd 		s->block.hash.crc32 = xz_crc32(
29063dab8eeSAdrian Chadd 				(const uint8_t *)&s->block.hash,
29163dab8eeSAdrian Chadd 				sizeof(s->block.hash), s->block.hash.crc32);
29263dab8eeSAdrian Chadd 
29363dab8eeSAdrian Chadd 		++s->block.count;
29463dab8eeSAdrian Chadd 	}
29563dab8eeSAdrian Chadd 
29663dab8eeSAdrian Chadd 	return ret;
29763dab8eeSAdrian Chadd }
29863dab8eeSAdrian Chadd 
29963dab8eeSAdrian Chadd /* Update the Index size and the CRC32 value. */
index_update(struct xz_dec * s,const struct xz_buf * b)30063dab8eeSAdrian Chadd static void index_update(struct xz_dec *s, const struct xz_buf *b)
30163dab8eeSAdrian Chadd {
30263dab8eeSAdrian Chadd 	size_t in_used = b->in_pos - s->in_start;
30363dab8eeSAdrian Chadd 	s->index.size += in_used;
304f0bd5302SXin LI 	s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
30563dab8eeSAdrian Chadd }
30663dab8eeSAdrian Chadd 
30763dab8eeSAdrian Chadd /*
30863dab8eeSAdrian Chadd  * Decode the Number of Records, Unpadded Size, and Uncompressed Size
30963dab8eeSAdrian Chadd  * fields from the Index field. That is, Index Padding and CRC32 are not
31063dab8eeSAdrian Chadd  * decoded by this function.
31163dab8eeSAdrian Chadd  *
31263dab8eeSAdrian Chadd  * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
31363dab8eeSAdrian Chadd  * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
31463dab8eeSAdrian Chadd  */
dec_index(struct xz_dec * s,struct xz_buf * b)31563dab8eeSAdrian Chadd static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
31663dab8eeSAdrian Chadd {
31763dab8eeSAdrian Chadd 	enum xz_ret ret;
31863dab8eeSAdrian Chadd 
31963dab8eeSAdrian Chadd 	do {
32063dab8eeSAdrian Chadd 		ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
32163dab8eeSAdrian Chadd 		if (ret != XZ_STREAM_END) {
32263dab8eeSAdrian Chadd 			index_update(s, b);
32363dab8eeSAdrian Chadd 			return ret;
32463dab8eeSAdrian Chadd 		}
32563dab8eeSAdrian Chadd 
32663dab8eeSAdrian Chadd 		switch (s->index.sequence) {
32763dab8eeSAdrian Chadd 		case SEQ_INDEX_COUNT:
32863dab8eeSAdrian Chadd 			s->index.count = s->vli;
32963dab8eeSAdrian Chadd 
33063dab8eeSAdrian Chadd 			/*
33163dab8eeSAdrian Chadd 			 * Validate that the Number of Records field
33263dab8eeSAdrian Chadd 			 * indicates the same number of Records as
33363dab8eeSAdrian Chadd 			 * there were Blocks in the Stream.
33463dab8eeSAdrian Chadd 			 */
33563dab8eeSAdrian Chadd 			if (s->index.count != s->block.count)
33663dab8eeSAdrian Chadd 				return XZ_DATA_ERROR;
33763dab8eeSAdrian Chadd 
33863dab8eeSAdrian Chadd 			s->index.sequence = SEQ_INDEX_UNPADDED;
33963dab8eeSAdrian Chadd 			break;
34063dab8eeSAdrian Chadd 
34163dab8eeSAdrian Chadd 		case SEQ_INDEX_UNPADDED:
34263dab8eeSAdrian Chadd 			s->index.hash.unpadded += s->vli;
34363dab8eeSAdrian Chadd 			s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
34463dab8eeSAdrian Chadd 			break;
34563dab8eeSAdrian Chadd 
34663dab8eeSAdrian Chadd 		case SEQ_INDEX_UNCOMPRESSED:
34763dab8eeSAdrian Chadd 			s->index.hash.uncompressed += s->vli;
34863dab8eeSAdrian Chadd 			s->index.hash.crc32 = xz_crc32(
34963dab8eeSAdrian Chadd 					(const uint8_t *)&s->index.hash,
35063dab8eeSAdrian Chadd 					sizeof(s->index.hash),
35163dab8eeSAdrian Chadd 					s->index.hash.crc32);
35263dab8eeSAdrian Chadd 			--s->index.count;
35363dab8eeSAdrian Chadd 			s->index.sequence = SEQ_INDEX_UNPADDED;
35463dab8eeSAdrian Chadd 			break;
35563dab8eeSAdrian Chadd 		}
35663dab8eeSAdrian Chadd 	} while (s->index.count > 0);
35763dab8eeSAdrian Chadd 
35863dab8eeSAdrian Chadd 	return XZ_STREAM_END;
35963dab8eeSAdrian Chadd }
36063dab8eeSAdrian Chadd 
36163dab8eeSAdrian Chadd /*
362f0bd5302SXin LI  * Validate that the next four or eight input bytes match the value
363f0bd5302SXin LI  * of s->crc. s->pos must be zero when starting to validate the first byte.
364f0bd5302SXin LI  * The "bits" argument allows using the same code for both CRC32 and CRC64.
36563dab8eeSAdrian Chadd  */
crc_validate(struct xz_dec * s,struct xz_buf * b,uint32_t bits)366f0bd5302SXin LI static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
367f0bd5302SXin LI 				uint32_t bits)
36863dab8eeSAdrian Chadd {
36963dab8eeSAdrian Chadd 	do {
37063dab8eeSAdrian Chadd 		if (b->in_pos == b->in_size)
37163dab8eeSAdrian Chadd 			return XZ_OK;
37263dab8eeSAdrian Chadd 
373f0bd5302SXin LI 		if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
37463dab8eeSAdrian Chadd 			return XZ_DATA_ERROR;
37563dab8eeSAdrian Chadd 
37663dab8eeSAdrian Chadd 		s->pos += 8;
37763dab8eeSAdrian Chadd 
378f0bd5302SXin LI 	} while (s->pos < bits);
37963dab8eeSAdrian Chadd 
380f0bd5302SXin LI 	s->crc = 0;
38163dab8eeSAdrian Chadd 	s->pos = 0;
38263dab8eeSAdrian Chadd 
38363dab8eeSAdrian Chadd 	return XZ_STREAM_END;
38463dab8eeSAdrian Chadd }
38563dab8eeSAdrian Chadd 
38663dab8eeSAdrian Chadd #ifdef XZ_DEC_ANY_CHECK
38763dab8eeSAdrian Chadd /*
38863dab8eeSAdrian Chadd  * Skip over the Check field when the Check ID is not supported.
38963dab8eeSAdrian Chadd  * Returns true once the whole Check field has been skipped over.
39063dab8eeSAdrian Chadd  */
check_skip(struct xz_dec * s,struct xz_buf * b)39163dab8eeSAdrian Chadd static bool check_skip(struct xz_dec *s, struct xz_buf *b)
39263dab8eeSAdrian Chadd {
39363dab8eeSAdrian Chadd 	while (s->pos < check_sizes[s->check_type]) {
39463dab8eeSAdrian Chadd 		if (b->in_pos == b->in_size)
39563dab8eeSAdrian Chadd 			return false;
39663dab8eeSAdrian Chadd 
39763dab8eeSAdrian Chadd 		++b->in_pos;
39863dab8eeSAdrian Chadd 		++s->pos;
39963dab8eeSAdrian Chadd 	}
40063dab8eeSAdrian Chadd 
40163dab8eeSAdrian Chadd 	s->pos = 0;
40263dab8eeSAdrian Chadd 
40363dab8eeSAdrian Chadd 	return true;
40463dab8eeSAdrian Chadd }
40563dab8eeSAdrian Chadd #endif
40663dab8eeSAdrian Chadd 
40763dab8eeSAdrian Chadd /* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
dec_stream_header(struct xz_dec * s)40863dab8eeSAdrian Chadd static enum xz_ret dec_stream_header(struct xz_dec *s)
40963dab8eeSAdrian Chadd {
41063dab8eeSAdrian Chadd 	if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
41163dab8eeSAdrian Chadd 		return XZ_FORMAT_ERROR;
41263dab8eeSAdrian Chadd 
41363dab8eeSAdrian Chadd 	if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
41463dab8eeSAdrian Chadd 			!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
41563dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
41663dab8eeSAdrian Chadd 
41763dab8eeSAdrian Chadd 	if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
41863dab8eeSAdrian Chadd 		return XZ_OPTIONS_ERROR;
41963dab8eeSAdrian Chadd 
42063dab8eeSAdrian Chadd 	/*
421f0bd5302SXin LI 	 * Of integrity checks, we support none (Check ID = 0),
422f0bd5302SXin LI 	 * CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
423f0bd5302SXin LI 	 * However, if XZ_DEC_ANY_CHECK is defined, we will accept other
424f0bd5302SXin LI 	 * check types too, but then the check won't be verified and
425f0bd5302SXin LI 	 * a warning (XZ_UNSUPPORTED_CHECK) will be given.
42663dab8eeSAdrian Chadd 	 */
427*cd3a777bSXin LI 	if (s->temp.buf[HEADER_MAGIC_SIZE + 1] > XZ_CHECK_MAX)
428*cd3a777bSXin LI 		return XZ_OPTIONS_ERROR;
429*cd3a777bSXin LI 
43063dab8eeSAdrian Chadd 	s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
43163dab8eeSAdrian Chadd 
43263dab8eeSAdrian Chadd #ifdef XZ_DEC_ANY_CHECK
433f0bd5302SXin LI 	if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
43463dab8eeSAdrian Chadd 		return XZ_UNSUPPORTED_CHECK;
43563dab8eeSAdrian Chadd #else
436f0bd5302SXin LI 	if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
43763dab8eeSAdrian Chadd 		return XZ_OPTIONS_ERROR;
43863dab8eeSAdrian Chadd #endif
43963dab8eeSAdrian Chadd 
44063dab8eeSAdrian Chadd 	return XZ_OK;
44163dab8eeSAdrian Chadd }
44263dab8eeSAdrian Chadd 
44363dab8eeSAdrian Chadd /* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
dec_stream_footer(struct xz_dec * s)44463dab8eeSAdrian Chadd static enum xz_ret dec_stream_footer(struct xz_dec *s)
44563dab8eeSAdrian Chadd {
44663dab8eeSAdrian Chadd 	if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
44763dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
44863dab8eeSAdrian Chadd 
44963dab8eeSAdrian Chadd 	if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
45063dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
45163dab8eeSAdrian Chadd 
45263dab8eeSAdrian Chadd 	/*
45363dab8eeSAdrian Chadd 	 * Validate Backward Size. Note that we never added the size of the
45463dab8eeSAdrian Chadd 	 * Index CRC32 field to s->index.size, thus we use s->index.size / 4
45563dab8eeSAdrian Chadd 	 * instead of s->index.size / 4 - 1.
45663dab8eeSAdrian Chadd 	 */
45763dab8eeSAdrian Chadd 	if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
45863dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
45963dab8eeSAdrian Chadd 
46063dab8eeSAdrian Chadd 	if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
46163dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
46263dab8eeSAdrian Chadd 
46363dab8eeSAdrian Chadd 	/*
46463dab8eeSAdrian Chadd 	 * Use XZ_STREAM_END instead of XZ_OK to be more convenient
46563dab8eeSAdrian Chadd 	 * for the caller.
46663dab8eeSAdrian Chadd 	 */
46763dab8eeSAdrian Chadd 	return XZ_STREAM_END;
46863dab8eeSAdrian Chadd }
46963dab8eeSAdrian Chadd 
47063dab8eeSAdrian Chadd /* Decode the Block Header and initialize the filter chain. */
dec_block_header(struct xz_dec * s)47163dab8eeSAdrian Chadd static enum xz_ret dec_block_header(struct xz_dec *s)
47263dab8eeSAdrian Chadd {
47363dab8eeSAdrian Chadd 	enum xz_ret ret;
47463dab8eeSAdrian Chadd 
47563dab8eeSAdrian Chadd 	/*
47663dab8eeSAdrian Chadd 	 * Validate the CRC32. We know that the temp buffer is at least
47763dab8eeSAdrian Chadd 	 * eight bytes so this is safe.
47863dab8eeSAdrian Chadd 	 */
47963dab8eeSAdrian Chadd 	s->temp.size -= 4;
48063dab8eeSAdrian Chadd 	if (xz_crc32(s->temp.buf, s->temp.size, 0)
48163dab8eeSAdrian Chadd 			!= get_le32(s->temp.buf + s->temp.size))
48263dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
48363dab8eeSAdrian Chadd 
48463dab8eeSAdrian Chadd 	s->temp.pos = 2;
48563dab8eeSAdrian Chadd 
48663dab8eeSAdrian Chadd 	/*
48763dab8eeSAdrian Chadd 	 * Catch unsupported Block Flags. We support only one or two filters
48863dab8eeSAdrian Chadd 	 * in the chain, so we catch that with the same test.
48963dab8eeSAdrian Chadd 	 */
49063dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
49163dab8eeSAdrian Chadd 	if (s->temp.buf[1] & 0x3E)
49263dab8eeSAdrian Chadd #else
49363dab8eeSAdrian Chadd 	if (s->temp.buf[1] & 0x3F)
49463dab8eeSAdrian Chadd #endif
49563dab8eeSAdrian Chadd 		return XZ_OPTIONS_ERROR;
49663dab8eeSAdrian Chadd 
49763dab8eeSAdrian Chadd 	/* Compressed Size */
49863dab8eeSAdrian Chadd 	if (s->temp.buf[1] & 0x40) {
49963dab8eeSAdrian Chadd 		if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
50063dab8eeSAdrian Chadd 					!= XZ_STREAM_END)
50163dab8eeSAdrian Chadd 			return XZ_DATA_ERROR;
50263dab8eeSAdrian Chadd 
50363dab8eeSAdrian Chadd 		s->block_header.compressed = s->vli;
50463dab8eeSAdrian Chadd 	} else {
50563dab8eeSAdrian Chadd 		s->block_header.compressed = VLI_UNKNOWN;
50663dab8eeSAdrian Chadd 	}
50763dab8eeSAdrian Chadd 
50863dab8eeSAdrian Chadd 	/* Uncompressed Size */
50963dab8eeSAdrian Chadd 	if (s->temp.buf[1] & 0x80) {
51063dab8eeSAdrian Chadd 		if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
51163dab8eeSAdrian Chadd 				!= XZ_STREAM_END)
51263dab8eeSAdrian Chadd 			return XZ_DATA_ERROR;
51363dab8eeSAdrian Chadd 
51463dab8eeSAdrian Chadd 		s->block_header.uncompressed = s->vli;
51563dab8eeSAdrian Chadd 	} else {
51663dab8eeSAdrian Chadd 		s->block_header.uncompressed = VLI_UNKNOWN;
51763dab8eeSAdrian Chadd 	}
51863dab8eeSAdrian Chadd 
51963dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
52063dab8eeSAdrian Chadd 	/* If there are two filters, the first one must be a BCJ filter. */
52163dab8eeSAdrian Chadd 	s->bcj_active = s->temp.buf[1] & 0x01;
52263dab8eeSAdrian Chadd 	if (s->bcj_active) {
52363dab8eeSAdrian Chadd 		if (s->temp.size - s->temp.pos < 2)
52463dab8eeSAdrian Chadd 			return XZ_OPTIONS_ERROR;
52563dab8eeSAdrian Chadd 
52663dab8eeSAdrian Chadd 		ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
52763dab8eeSAdrian Chadd 		if (ret != XZ_OK)
52863dab8eeSAdrian Chadd 			return ret;
52963dab8eeSAdrian Chadd 
53063dab8eeSAdrian Chadd 		/*
53163dab8eeSAdrian Chadd 		 * We don't support custom start offset,
53263dab8eeSAdrian Chadd 		 * so Size of Properties must be zero.
53363dab8eeSAdrian Chadd 		 */
53463dab8eeSAdrian Chadd 		if (s->temp.buf[s->temp.pos++] != 0x00)
53563dab8eeSAdrian Chadd 			return XZ_OPTIONS_ERROR;
53663dab8eeSAdrian Chadd 	}
53763dab8eeSAdrian Chadd #endif
53863dab8eeSAdrian Chadd 
53963dab8eeSAdrian Chadd 	/* Valid Filter Flags always take at least two bytes. */
54063dab8eeSAdrian Chadd 	if (s->temp.size - s->temp.pos < 2)
54163dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
54263dab8eeSAdrian Chadd 
54363dab8eeSAdrian Chadd 	/* Filter ID = LZMA2 */
54463dab8eeSAdrian Chadd 	if (s->temp.buf[s->temp.pos++] != 0x21)
54563dab8eeSAdrian Chadd 		return XZ_OPTIONS_ERROR;
54663dab8eeSAdrian Chadd 
54763dab8eeSAdrian Chadd 	/* Size of Properties = 1-byte Filter Properties */
54863dab8eeSAdrian Chadd 	if (s->temp.buf[s->temp.pos++] != 0x01)
54963dab8eeSAdrian Chadd 		return XZ_OPTIONS_ERROR;
55063dab8eeSAdrian Chadd 
55163dab8eeSAdrian Chadd 	/* Filter Properties contains LZMA2 dictionary size. */
55263dab8eeSAdrian Chadd 	if (s->temp.size - s->temp.pos < 1)
55363dab8eeSAdrian Chadd 		return XZ_DATA_ERROR;
55463dab8eeSAdrian Chadd 
55563dab8eeSAdrian Chadd 	ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
55663dab8eeSAdrian Chadd 	if (ret != XZ_OK)
55763dab8eeSAdrian Chadd 		return ret;
55863dab8eeSAdrian Chadd 
55963dab8eeSAdrian Chadd 	/* The rest must be Header Padding. */
56063dab8eeSAdrian Chadd 	while (s->temp.pos < s->temp.size)
56163dab8eeSAdrian Chadd 		if (s->temp.buf[s->temp.pos++] != 0x00)
56263dab8eeSAdrian Chadd 			return XZ_OPTIONS_ERROR;
56363dab8eeSAdrian Chadd 
56463dab8eeSAdrian Chadd 	s->temp.pos = 0;
56563dab8eeSAdrian Chadd 	s->block.compressed = 0;
56663dab8eeSAdrian Chadd 	s->block.uncompressed = 0;
56763dab8eeSAdrian Chadd 
56863dab8eeSAdrian Chadd 	return XZ_OK;
56963dab8eeSAdrian Chadd }
57063dab8eeSAdrian Chadd 
dec_main(struct xz_dec * s,struct xz_buf * b)57163dab8eeSAdrian Chadd static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
57263dab8eeSAdrian Chadd {
57363dab8eeSAdrian Chadd 	enum xz_ret ret;
57463dab8eeSAdrian Chadd 
57563dab8eeSAdrian Chadd 	/*
57663dab8eeSAdrian Chadd 	 * Store the start position for the case when we are in the middle
57763dab8eeSAdrian Chadd 	 * of the Index field.
57863dab8eeSAdrian Chadd 	 */
57963dab8eeSAdrian Chadd 	s->in_start = b->in_pos;
58063dab8eeSAdrian Chadd 
58163dab8eeSAdrian Chadd 	while (true) {
58263dab8eeSAdrian Chadd 		switch (s->sequence) {
58363dab8eeSAdrian Chadd 		case SEQ_STREAM_HEADER:
58463dab8eeSAdrian Chadd 			/*
58563dab8eeSAdrian Chadd 			 * Stream Header is copied to s->temp, and then
58663dab8eeSAdrian Chadd 			 * decoded from there. This way if the caller
58763dab8eeSAdrian Chadd 			 * gives us only little input at a time, we can
58863dab8eeSAdrian Chadd 			 * still keep the Stream Header decoding code
58963dab8eeSAdrian Chadd 			 * simple. Similar approach is used in many places
59063dab8eeSAdrian Chadd 			 * in this file.
59163dab8eeSAdrian Chadd 			 */
59263dab8eeSAdrian Chadd 			if (!fill_temp(s, b))
59363dab8eeSAdrian Chadd 				return XZ_OK;
59463dab8eeSAdrian Chadd 
59563dab8eeSAdrian Chadd 			/*
59663dab8eeSAdrian Chadd 			 * If dec_stream_header() returns
59763dab8eeSAdrian Chadd 			 * XZ_UNSUPPORTED_CHECK, it is still possible
59863dab8eeSAdrian Chadd 			 * to continue decoding if working in multi-call
59963dab8eeSAdrian Chadd 			 * mode. Thus, update s->sequence before calling
60063dab8eeSAdrian Chadd 			 * dec_stream_header().
60163dab8eeSAdrian Chadd 			 */
60263dab8eeSAdrian Chadd 			s->sequence = SEQ_BLOCK_START;
60363dab8eeSAdrian Chadd 
60463dab8eeSAdrian Chadd 			ret = dec_stream_header(s);
60563dab8eeSAdrian Chadd 			if (ret != XZ_OK)
60663dab8eeSAdrian Chadd 				return ret;
60763dab8eeSAdrian Chadd 
608*cd3a777bSXin LI 		/* Fall through */
609*cd3a777bSXin LI 
61063dab8eeSAdrian Chadd 		case SEQ_BLOCK_START:
61163dab8eeSAdrian Chadd 			/* We need one byte of input to continue. */
61263dab8eeSAdrian Chadd 			if (b->in_pos == b->in_size)
61363dab8eeSAdrian Chadd 				return XZ_OK;
61463dab8eeSAdrian Chadd 
61563dab8eeSAdrian Chadd 			/* See if this is the beginning of the Index field. */
61663dab8eeSAdrian Chadd 			if (b->in[b->in_pos] == 0) {
61763dab8eeSAdrian Chadd 				s->in_start = b->in_pos++;
61863dab8eeSAdrian Chadd 				s->sequence = SEQ_INDEX;
61963dab8eeSAdrian Chadd 				break;
62063dab8eeSAdrian Chadd 			}
62163dab8eeSAdrian Chadd 
62263dab8eeSAdrian Chadd 			/*
62363dab8eeSAdrian Chadd 			 * Calculate the size of the Block Header and
62463dab8eeSAdrian Chadd 			 * prepare to decode it.
62563dab8eeSAdrian Chadd 			 */
62663dab8eeSAdrian Chadd 			s->block_header.size
62763dab8eeSAdrian Chadd 				= ((uint32_t)b->in[b->in_pos] + 1) * 4;
62863dab8eeSAdrian Chadd 
62963dab8eeSAdrian Chadd 			s->temp.size = s->block_header.size;
63063dab8eeSAdrian Chadd 			s->temp.pos = 0;
63163dab8eeSAdrian Chadd 			s->sequence = SEQ_BLOCK_HEADER;
63263dab8eeSAdrian Chadd 
633*cd3a777bSXin LI 		/* Fall through */
634*cd3a777bSXin LI 
63563dab8eeSAdrian Chadd 		case SEQ_BLOCK_HEADER:
63663dab8eeSAdrian Chadd 			if (!fill_temp(s, b))
63763dab8eeSAdrian Chadd 				return XZ_OK;
63863dab8eeSAdrian Chadd 
63963dab8eeSAdrian Chadd 			ret = dec_block_header(s);
64063dab8eeSAdrian Chadd 			if (ret != XZ_OK)
64163dab8eeSAdrian Chadd 				return ret;
64263dab8eeSAdrian Chadd 
64363dab8eeSAdrian Chadd 			s->sequence = SEQ_BLOCK_UNCOMPRESS;
64463dab8eeSAdrian Chadd 
645*cd3a777bSXin LI 		/* Fall through */
646*cd3a777bSXin LI 
64763dab8eeSAdrian Chadd 		case SEQ_BLOCK_UNCOMPRESS:
64863dab8eeSAdrian Chadd 			ret = dec_block(s, b);
64963dab8eeSAdrian Chadd 			if (ret != XZ_STREAM_END)
65063dab8eeSAdrian Chadd 				return ret;
65163dab8eeSAdrian Chadd 
65263dab8eeSAdrian Chadd 			s->sequence = SEQ_BLOCK_PADDING;
65363dab8eeSAdrian Chadd 
654*cd3a777bSXin LI 		/* Fall through */
655*cd3a777bSXin LI 
65663dab8eeSAdrian Chadd 		case SEQ_BLOCK_PADDING:
65763dab8eeSAdrian Chadd 			/*
65863dab8eeSAdrian Chadd 			 * Size of Compressed Data + Block Padding
65963dab8eeSAdrian Chadd 			 * must be a multiple of four. We don't need
66063dab8eeSAdrian Chadd 			 * s->block.compressed for anything else
66163dab8eeSAdrian Chadd 			 * anymore, so we use it here to test the size
66263dab8eeSAdrian Chadd 			 * of the Block Padding field.
66363dab8eeSAdrian Chadd 			 */
66463dab8eeSAdrian Chadd 			while (s->block.compressed & 3) {
66563dab8eeSAdrian Chadd 				if (b->in_pos == b->in_size)
66663dab8eeSAdrian Chadd 					return XZ_OK;
66763dab8eeSAdrian Chadd 
66863dab8eeSAdrian Chadd 				if (b->in[b->in_pos++] != 0)
66963dab8eeSAdrian Chadd 					return XZ_DATA_ERROR;
67063dab8eeSAdrian Chadd 
67163dab8eeSAdrian Chadd 				++s->block.compressed;
67263dab8eeSAdrian Chadd 			}
67363dab8eeSAdrian Chadd 
67463dab8eeSAdrian Chadd 			s->sequence = SEQ_BLOCK_CHECK;
67563dab8eeSAdrian Chadd 
676*cd3a777bSXin LI 		/* Fall through */
677*cd3a777bSXin LI 
67863dab8eeSAdrian Chadd 		case SEQ_BLOCK_CHECK:
67963dab8eeSAdrian Chadd 			if (s->check_type == XZ_CHECK_CRC32) {
680f0bd5302SXin LI 				ret = crc_validate(s, b, 32);
681f0bd5302SXin LI 				if (ret != XZ_STREAM_END)
682f0bd5302SXin LI 					return ret;
683f0bd5302SXin LI 			}
684f0bd5302SXin LI 			else if (IS_CRC64(s->check_type)) {
685f0bd5302SXin LI 				ret = crc_validate(s, b, 64);
68663dab8eeSAdrian Chadd 				if (ret != XZ_STREAM_END)
68763dab8eeSAdrian Chadd 					return ret;
68863dab8eeSAdrian Chadd 			}
68963dab8eeSAdrian Chadd #ifdef XZ_DEC_ANY_CHECK
69063dab8eeSAdrian Chadd 			else if (!check_skip(s, b)) {
69163dab8eeSAdrian Chadd 				return XZ_OK;
69263dab8eeSAdrian Chadd 			}
69363dab8eeSAdrian Chadd #endif
69463dab8eeSAdrian Chadd 
69563dab8eeSAdrian Chadd 			s->sequence = SEQ_BLOCK_START;
69663dab8eeSAdrian Chadd 			break;
69763dab8eeSAdrian Chadd 
69863dab8eeSAdrian Chadd 		case SEQ_INDEX:
69963dab8eeSAdrian Chadd 			ret = dec_index(s, b);
70063dab8eeSAdrian Chadd 			if (ret != XZ_STREAM_END)
70163dab8eeSAdrian Chadd 				return ret;
70263dab8eeSAdrian Chadd 
70363dab8eeSAdrian Chadd 			s->sequence = SEQ_INDEX_PADDING;
70463dab8eeSAdrian Chadd 
705*cd3a777bSXin LI 		/* Fall through */
706*cd3a777bSXin LI 
70763dab8eeSAdrian Chadd 		case SEQ_INDEX_PADDING:
70863dab8eeSAdrian Chadd 			while ((s->index.size + (b->in_pos - s->in_start))
70963dab8eeSAdrian Chadd 					& 3) {
71063dab8eeSAdrian Chadd 				if (b->in_pos == b->in_size) {
71163dab8eeSAdrian Chadd 					index_update(s, b);
71263dab8eeSAdrian Chadd 					return XZ_OK;
71363dab8eeSAdrian Chadd 				}
71463dab8eeSAdrian Chadd 
71563dab8eeSAdrian Chadd 				if (b->in[b->in_pos++] != 0)
71663dab8eeSAdrian Chadd 					return XZ_DATA_ERROR;
71763dab8eeSAdrian Chadd 			}
71863dab8eeSAdrian Chadd 
71963dab8eeSAdrian Chadd 			/* Finish the CRC32 value and Index size. */
72063dab8eeSAdrian Chadd 			index_update(s, b);
72163dab8eeSAdrian Chadd 
72263dab8eeSAdrian Chadd 			/* Compare the hashes to validate the Index field. */
72363dab8eeSAdrian Chadd 			if (!memeq(&s->block.hash, &s->index.hash,
72463dab8eeSAdrian Chadd 					sizeof(s->block.hash)))
72563dab8eeSAdrian Chadd 				return XZ_DATA_ERROR;
72663dab8eeSAdrian Chadd 
72763dab8eeSAdrian Chadd 			s->sequence = SEQ_INDEX_CRC32;
72863dab8eeSAdrian Chadd 
729*cd3a777bSXin LI 		/* Fall through */
730*cd3a777bSXin LI 
73163dab8eeSAdrian Chadd 		case SEQ_INDEX_CRC32:
732f0bd5302SXin LI 			ret = crc_validate(s, b, 32);
73363dab8eeSAdrian Chadd 			if (ret != XZ_STREAM_END)
73463dab8eeSAdrian Chadd 				return ret;
73563dab8eeSAdrian Chadd 
73663dab8eeSAdrian Chadd 			s->temp.size = STREAM_HEADER_SIZE;
73763dab8eeSAdrian Chadd 			s->sequence = SEQ_STREAM_FOOTER;
73863dab8eeSAdrian Chadd 
739*cd3a777bSXin LI 		/* Fall through */
740*cd3a777bSXin LI 
74163dab8eeSAdrian Chadd 		case SEQ_STREAM_FOOTER:
74263dab8eeSAdrian Chadd 			if (!fill_temp(s, b))
74363dab8eeSAdrian Chadd 				return XZ_OK;
74463dab8eeSAdrian Chadd 
74563dab8eeSAdrian Chadd 			return dec_stream_footer(s);
746*cd3a777bSXin LI 
747*cd3a777bSXin LI 		case SEQ_STREAM_PADDING:
748*cd3a777bSXin LI 			/* Never reached, only silencing a warning */
749*cd3a777bSXin LI 			break;
75063dab8eeSAdrian Chadd 		}
75163dab8eeSAdrian Chadd 	}
75263dab8eeSAdrian Chadd 
75363dab8eeSAdrian Chadd 	/* Never reached */
75463dab8eeSAdrian Chadd }
75563dab8eeSAdrian Chadd 
75663dab8eeSAdrian Chadd /*
75763dab8eeSAdrian Chadd  * xz_dec_run() is a wrapper for dec_main() to handle some special cases in
75863dab8eeSAdrian Chadd  * multi-call and single-call decoding.
75963dab8eeSAdrian Chadd  *
76063dab8eeSAdrian Chadd  * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
76163dab8eeSAdrian Chadd  * are not going to make any progress anymore. This is to prevent the caller
76263dab8eeSAdrian Chadd  * from calling us infinitely when the input file is truncated or otherwise
76363dab8eeSAdrian Chadd  * corrupt. Since zlib-style API allows that the caller fills the input buffer
76463dab8eeSAdrian Chadd  * only when the decoder doesn't produce any new output, we have to be careful
76563dab8eeSAdrian Chadd  * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
76663dab8eeSAdrian Chadd  * after the second consecutive call to xz_dec_run() that makes no progress.
76763dab8eeSAdrian Chadd  *
76863dab8eeSAdrian Chadd  * In single-call mode, if we couldn't decode everything and no error
76963dab8eeSAdrian Chadd  * occurred, either the input is truncated or the output buffer is too small.
77063dab8eeSAdrian Chadd  * Since we know that the last input byte never produces any output, we know
77163dab8eeSAdrian Chadd  * that if all the input was consumed and decoding wasn't finished, the file
77263dab8eeSAdrian Chadd  * must be corrupt. Otherwise the output buffer has to be too small or the
77363dab8eeSAdrian Chadd  * file is corrupt in a way that decoding it produces too big output.
77463dab8eeSAdrian Chadd  *
77563dab8eeSAdrian Chadd  * If single-call decoding fails, we reset b->in_pos and b->out_pos back to
77663dab8eeSAdrian Chadd  * their original values. This is because with some filter chains there won't
77763dab8eeSAdrian Chadd  * be any valid uncompressed data in the output buffer unless the decoding
77863dab8eeSAdrian Chadd  * actually succeeds (that's the price to pay of using the output buffer as
77963dab8eeSAdrian Chadd  * the workspace).
78063dab8eeSAdrian Chadd  */
xz_dec_run(struct xz_dec * s,struct xz_buf * b)78163dab8eeSAdrian Chadd XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
78263dab8eeSAdrian Chadd {
78363dab8eeSAdrian Chadd 	size_t in_start;
78463dab8eeSAdrian Chadd 	size_t out_start;
78563dab8eeSAdrian Chadd 	enum xz_ret ret;
78663dab8eeSAdrian Chadd 
78763dab8eeSAdrian Chadd 	if (DEC_IS_SINGLE(s->mode))
78863dab8eeSAdrian Chadd 		xz_dec_reset(s);
78963dab8eeSAdrian Chadd 
79063dab8eeSAdrian Chadd 	in_start = b->in_pos;
79163dab8eeSAdrian Chadd 	out_start = b->out_pos;
79263dab8eeSAdrian Chadd 	ret = dec_main(s, b);
79363dab8eeSAdrian Chadd 
79463dab8eeSAdrian Chadd 	if (DEC_IS_SINGLE(s->mode)) {
79563dab8eeSAdrian Chadd 		if (ret == XZ_OK)
79663dab8eeSAdrian Chadd 			ret = b->in_pos == b->in_size
79763dab8eeSAdrian Chadd 					? XZ_DATA_ERROR : XZ_BUF_ERROR;
79863dab8eeSAdrian Chadd 
79963dab8eeSAdrian Chadd 		if (ret != XZ_STREAM_END) {
80063dab8eeSAdrian Chadd 			b->in_pos = in_start;
80163dab8eeSAdrian Chadd 			b->out_pos = out_start;
80263dab8eeSAdrian Chadd 		}
80363dab8eeSAdrian Chadd 
80463dab8eeSAdrian Chadd 	} else if (ret == XZ_OK && in_start == b->in_pos
80563dab8eeSAdrian Chadd 			&& out_start == b->out_pos) {
80663dab8eeSAdrian Chadd 		if (s->allow_buf_error)
80763dab8eeSAdrian Chadd 			ret = XZ_BUF_ERROR;
80863dab8eeSAdrian Chadd 
80963dab8eeSAdrian Chadd 		s->allow_buf_error = true;
81063dab8eeSAdrian Chadd 	} else {
81163dab8eeSAdrian Chadd 		s->allow_buf_error = false;
81263dab8eeSAdrian Chadd 	}
81363dab8eeSAdrian Chadd 
81463dab8eeSAdrian Chadd 	return ret;
81563dab8eeSAdrian Chadd }
81663dab8eeSAdrian Chadd 
817*cd3a777bSXin LI #ifdef XZ_DEC_CONCATENATED
xz_dec_catrun(struct xz_dec * s,struct xz_buf * b,int finish)818*cd3a777bSXin LI XZ_EXTERN enum xz_ret xz_dec_catrun(struct xz_dec *s, struct xz_buf *b,
819*cd3a777bSXin LI 				    int finish)
820*cd3a777bSXin LI {
821*cd3a777bSXin LI 	enum xz_ret ret;
822*cd3a777bSXin LI 
823*cd3a777bSXin LI 	if (DEC_IS_SINGLE(s->mode)) {
824*cd3a777bSXin LI 		xz_dec_reset(s);
825*cd3a777bSXin LI 		finish = true;
826*cd3a777bSXin LI 	}
827*cd3a777bSXin LI 
828*cd3a777bSXin LI 	while (true) {
829*cd3a777bSXin LI 		if (s->sequence == SEQ_STREAM_PADDING) {
830*cd3a777bSXin LI 			/*
831*cd3a777bSXin LI 			 * Skip Stream Padding. Its size must be a multiple
832*cd3a777bSXin LI 			 * of four bytes which is tracked with s->pos.
833*cd3a777bSXin LI 			 */
834*cd3a777bSXin LI 			while (true) {
835*cd3a777bSXin LI 				if (b->in_pos == b->in_size) {
836*cd3a777bSXin LI 					/*
837*cd3a777bSXin LI 					 * Note that if we are repeatedly
838*cd3a777bSXin LI 					 * given no input and finish is false,
839*cd3a777bSXin LI 					 * we will keep returning XZ_OK even
840*cd3a777bSXin LI 					 * though no progress is being made.
841*cd3a777bSXin LI 					 * The lack of XZ_BUF_ERROR support
842*cd3a777bSXin LI 					 * isn't a problem here because a
843*cd3a777bSXin LI 					 * reasonable caller will eventually
844*cd3a777bSXin LI 					 * provide more input or set finish
845*cd3a777bSXin LI 					 * to true.
846*cd3a777bSXin LI 					 */
847*cd3a777bSXin LI 					if (!finish)
848*cd3a777bSXin LI 						return XZ_OK;
849*cd3a777bSXin LI 
850*cd3a777bSXin LI 					if (s->pos != 0)
851*cd3a777bSXin LI 						return XZ_DATA_ERROR;
852*cd3a777bSXin LI 
853*cd3a777bSXin LI 					return XZ_STREAM_END;
854*cd3a777bSXin LI 				}
855*cd3a777bSXin LI 
856*cd3a777bSXin LI 				if (b->in[b->in_pos] != 0x00) {
857*cd3a777bSXin LI 					if (s->pos != 0)
858*cd3a777bSXin LI 						return XZ_DATA_ERROR;
859*cd3a777bSXin LI 
860*cd3a777bSXin LI 					break;
861*cd3a777bSXin LI 				}
862*cd3a777bSXin LI 
863*cd3a777bSXin LI 				++b->in_pos;
864*cd3a777bSXin LI 				s->pos = (s->pos + 1) & 3;
865*cd3a777bSXin LI 			}
866*cd3a777bSXin LI 
867*cd3a777bSXin LI 			/*
868*cd3a777bSXin LI 			 * More input remains. It should be a new Stream.
869*cd3a777bSXin LI 			 *
870*cd3a777bSXin LI 			 * In single-call mode xz_dec_run() will always call
871*cd3a777bSXin LI 			 * xz_dec_reset(). Thus, we need to do it here only
872*cd3a777bSXin LI 			 * in multi-call mode.
873*cd3a777bSXin LI 			 */
874*cd3a777bSXin LI 			if (DEC_IS_MULTI(s->mode))
875*cd3a777bSXin LI 				xz_dec_reset(s);
876*cd3a777bSXin LI 		}
877*cd3a777bSXin LI 
878*cd3a777bSXin LI 		ret = xz_dec_run(s, b);
879*cd3a777bSXin LI 
880*cd3a777bSXin LI 		if (ret != XZ_STREAM_END)
881*cd3a777bSXin LI 			break;
882*cd3a777bSXin LI 
883*cd3a777bSXin LI 		s->sequence = SEQ_STREAM_PADDING;
884*cd3a777bSXin LI 	}
885*cd3a777bSXin LI 
886*cd3a777bSXin LI 	return ret;
887*cd3a777bSXin LI }
888*cd3a777bSXin LI #endif
889*cd3a777bSXin LI 
xz_dec_init(enum xz_mode mode,uint32_t dict_max)89063dab8eeSAdrian Chadd XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
89163dab8eeSAdrian Chadd {
89263dab8eeSAdrian Chadd 	struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
89363dab8eeSAdrian Chadd 	if (s == NULL)
89463dab8eeSAdrian Chadd 		return NULL;
89563dab8eeSAdrian Chadd 
89663dab8eeSAdrian Chadd 	s->mode = mode;
89763dab8eeSAdrian Chadd 
89863dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
89963dab8eeSAdrian Chadd 	s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
90063dab8eeSAdrian Chadd 	if (s->bcj == NULL)
90163dab8eeSAdrian Chadd 		goto error_bcj;
90263dab8eeSAdrian Chadd #endif
90363dab8eeSAdrian Chadd 
90463dab8eeSAdrian Chadd 	s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
90563dab8eeSAdrian Chadd 	if (s->lzma2 == NULL)
90663dab8eeSAdrian Chadd 		goto error_lzma2;
90763dab8eeSAdrian Chadd 
90863dab8eeSAdrian Chadd 	xz_dec_reset(s);
90963dab8eeSAdrian Chadd 	return s;
91063dab8eeSAdrian Chadd 
91163dab8eeSAdrian Chadd error_lzma2:
91263dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
91363dab8eeSAdrian Chadd 	xz_dec_bcj_end(s->bcj);
91463dab8eeSAdrian Chadd error_bcj:
91563dab8eeSAdrian Chadd #endif
91663dab8eeSAdrian Chadd 	kfree(s);
91763dab8eeSAdrian Chadd 	return NULL;
91863dab8eeSAdrian Chadd }
91963dab8eeSAdrian Chadd 
xz_dec_reset(struct xz_dec * s)92063dab8eeSAdrian Chadd XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
92163dab8eeSAdrian Chadd {
92263dab8eeSAdrian Chadd 	s->sequence = SEQ_STREAM_HEADER;
92363dab8eeSAdrian Chadd 	s->allow_buf_error = false;
92463dab8eeSAdrian Chadd 	s->pos = 0;
925f0bd5302SXin LI 	s->crc = 0;
92663dab8eeSAdrian Chadd 	memzero(&s->block, sizeof(s->block));
92763dab8eeSAdrian Chadd 	memzero(&s->index, sizeof(s->index));
92863dab8eeSAdrian Chadd 	s->temp.pos = 0;
92963dab8eeSAdrian Chadd 	s->temp.size = STREAM_HEADER_SIZE;
93063dab8eeSAdrian Chadd }
93163dab8eeSAdrian Chadd 
xz_dec_end(struct xz_dec * s)93263dab8eeSAdrian Chadd XZ_EXTERN void xz_dec_end(struct xz_dec *s)
93363dab8eeSAdrian Chadd {
93463dab8eeSAdrian Chadd 	if (s != NULL) {
93563dab8eeSAdrian Chadd 		xz_dec_lzma2_end(s->lzma2);
93663dab8eeSAdrian Chadd #ifdef XZ_DEC_BCJ
93763dab8eeSAdrian Chadd 		xz_dec_bcj_end(s->bcj);
93863dab8eeSAdrian Chadd #endif
93963dab8eeSAdrian Chadd 		kfree(s);
94063dab8eeSAdrian Chadd 	}
94163dab8eeSAdrian Chadd }
942