18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * .xz Stream decoder
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Author: Lasse Collin <lasse.collin@tukaani.org>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file has been put into the public domain.
78c2ecf20Sopenharmony_ci * You can do whatever you want with this file.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "xz_private.h"
118c2ecf20Sopenharmony_ci#include "xz_stream.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* Hash used to validate the Index field */
148c2ecf20Sopenharmony_cistruct xz_dec_hash {
158c2ecf20Sopenharmony_ci	vli_type unpadded;
168c2ecf20Sopenharmony_ci	vli_type uncompressed;
178c2ecf20Sopenharmony_ci	uint32_t crc32;
188c2ecf20Sopenharmony_ci};
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct xz_dec {
218c2ecf20Sopenharmony_ci	/* Position in dec_main() */
228c2ecf20Sopenharmony_ci	enum {
238c2ecf20Sopenharmony_ci		SEQ_STREAM_HEADER,
248c2ecf20Sopenharmony_ci		SEQ_BLOCK_START,
258c2ecf20Sopenharmony_ci		SEQ_BLOCK_HEADER,
268c2ecf20Sopenharmony_ci		SEQ_BLOCK_UNCOMPRESS,
278c2ecf20Sopenharmony_ci		SEQ_BLOCK_PADDING,
288c2ecf20Sopenharmony_ci		SEQ_BLOCK_CHECK,
298c2ecf20Sopenharmony_ci		SEQ_INDEX,
308c2ecf20Sopenharmony_ci		SEQ_INDEX_PADDING,
318c2ecf20Sopenharmony_ci		SEQ_INDEX_CRC32,
328c2ecf20Sopenharmony_ci		SEQ_STREAM_FOOTER
338c2ecf20Sopenharmony_ci	} sequence;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* Position in variable-length integers and Check fields */
368c2ecf20Sopenharmony_ci	uint32_t pos;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	/* Variable-length integer decoded by dec_vli() */
398c2ecf20Sopenharmony_ci	vli_type vli;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* Saved in_pos and out_pos */
428c2ecf20Sopenharmony_ci	size_t in_start;
438c2ecf20Sopenharmony_ci	size_t out_start;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* CRC32 value in Block or Index */
468c2ecf20Sopenharmony_ci	uint32_t crc32;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* Type of the integrity check calculated from uncompressed data */
498c2ecf20Sopenharmony_ci	enum xz_check check_type;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* Operation mode */
528c2ecf20Sopenharmony_ci	enum xz_mode mode;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/*
558c2ecf20Sopenharmony_ci	 * True if the next call to xz_dec_run() is allowed to return
568c2ecf20Sopenharmony_ci	 * XZ_BUF_ERROR.
578c2ecf20Sopenharmony_ci	 */
588c2ecf20Sopenharmony_ci	bool allow_buf_error;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* Information stored in Block Header */
618c2ecf20Sopenharmony_ci	struct {
628c2ecf20Sopenharmony_ci		/*
638c2ecf20Sopenharmony_ci		 * Value stored in the Compressed Size field, or
648c2ecf20Sopenharmony_ci		 * VLI_UNKNOWN if Compressed Size is not present.
658c2ecf20Sopenharmony_ci		 */
668c2ecf20Sopenharmony_ci		vli_type compressed;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		/*
698c2ecf20Sopenharmony_ci		 * Value stored in the Uncompressed Size field, or
708c2ecf20Sopenharmony_ci		 * VLI_UNKNOWN if Uncompressed Size is not present.
718c2ecf20Sopenharmony_ci		 */
728c2ecf20Sopenharmony_ci		vli_type uncompressed;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		/* Size of the Block Header field */
758c2ecf20Sopenharmony_ci		uint32_t size;
768c2ecf20Sopenharmony_ci	} block_header;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* Information collected when decoding Blocks */
798c2ecf20Sopenharmony_ci	struct {
808c2ecf20Sopenharmony_ci		/* Observed compressed size of the current Block */
818c2ecf20Sopenharmony_ci		vli_type compressed;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		/* Observed uncompressed size of the current Block */
848c2ecf20Sopenharmony_ci		vli_type uncompressed;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		/* Number of Blocks decoded so far */
878c2ecf20Sopenharmony_ci		vli_type count;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		/*
908c2ecf20Sopenharmony_ci		 * Hash calculated from the Block sizes. This is used to
918c2ecf20Sopenharmony_ci		 * validate the Index field.
928c2ecf20Sopenharmony_ci		 */
938c2ecf20Sopenharmony_ci		struct xz_dec_hash hash;
948c2ecf20Sopenharmony_ci	} block;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* Variables needed when verifying the Index field */
978c2ecf20Sopenharmony_ci	struct {
988c2ecf20Sopenharmony_ci		/* Position in dec_index() */
998c2ecf20Sopenharmony_ci		enum {
1008c2ecf20Sopenharmony_ci			SEQ_INDEX_COUNT,
1018c2ecf20Sopenharmony_ci			SEQ_INDEX_UNPADDED,
1028c2ecf20Sopenharmony_ci			SEQ_INDEX_UNCOMPRESSED
1038c2ecf20Sopenharmony_ci		} sequence;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci		/* Size of the Index in bytes */
1068c2ecf20Sopenharmony_ci		vli_type size;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		/* Number of Records (matches block.count in valid files) */
1098c2ecf20Sopenharmony_ci		vli_type count;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		/*
1128c2ecf20Sopenharmony_ci		 * Hash calculated from the Records (matches block.hash in
1138c2ecf20Sopenharmony_ci		 * valid files).
1148c2ecf20Sopenharmony_ci		 */
1158c2ecf20Sopenharmony_ci		struct xz_dec_hash hash;
1168c2ecf20Sopenharmony_ci	} index;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * Temporary buffer needed to hold Stream Header, Block Header,
1208c2ecf20Sopenharmony_ci	 * and Stream Footer. The Block Header is the biggest (1 KiB)
1218c2ecf20Sopenharmony_ci	 * so we reserve space according to that. buf[] has to be aligned
1228c2ecf20Sopenharmony_ci	 * to a multiple of four bytes; the size_t variables before it
1238c2ecf20Sopenharmony_ci	 * should guarantee this.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci	struct {
1268c2ecf20Sopenharmony_ci		size_t pos;
1278c2ecf20Sopenharmony_ci		size_t size;
1288c2ecf20Sopenharmony_ci		uint8_t buf[1024];
1298c2ecf20Sopenharmony_ci	} temp;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	struct xz_dec_lzma2 *lzma2;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
1348c2ecf20Sopenharmony_ci	struct xz_dec_bcj *bcj;
1358c2ecf20Sopenharmony_ci	bool bcj_active;
1368c2ecf20Sopenharmony_ci#endif
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#ifdef XZ_DEC_ANY_CHECK
1408c2ecf20Sopenharmony_ci/* Sizes of the Check field with different Check IDs */
1418c2ecf20Sopenharmony_cistatic const uint8_t check_sizes[16] = {
1428c2ecf20Sopenharmony_ci	0,
1438c2ecf20Sopenharmony_ci	4, 4, 4,
1448c2ecf20Sopenharmony_ci	8, 8, 8,
1458c2ecf20Sopenharmony_ci	16, 16, 16,
1468c2ecf20Sopenharmony_ci	32, 32, 32,
1478c2ecf20Sopenharmony_ci	64, 64, 64
1488c2ecf20Sopenharmony_ci};
1498c2ecf20Sopenharmony_ci#endif
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/*
1528c2ecf20Sopenharmony_ci * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
1538c2ecf20Sopenharmony_ci * must have set s->temp.pos to indicate how much data we are supposed
1548c2ecf20Sopenharmony_ci * to copy into s->temp.buf. Return true once s->temp.pos has reached
1558c2ecf20Sopenharmony_ci * s->temp.size.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistatic bool fill_temp(struct xz_dec *s, struct xz_buf *b)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	size_t copy_size = min_t(size_t,
1608c2ecf20Sopenharmony_ci			b->in_size - b->in_pos, s->temp.size - s->temp.pos);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
1638c2ecf20Sopenharmony_ci	b->in_pos += copy_size;
1648c2ecf20Sopenharmony_ci	s->temp.pos += copy_size;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (s->temp.pos == s->temp.size) {
1678c2ecf20Sopenharmony_ci		s->temp.pos = 0;
1688c2ecf20Sopenharmony_ci		return true;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return false;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/* Decode a variable-length integer (little-endian base-128 encoding) */
1758c2ecf20Sopenharmony_cistatic enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
1768c2ecf20Sopenharmony_ci			   size_t *in_pos, size_t in_size)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	uint8_t byte;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (s->pos == 0)
1818c2ecf20Sopenharmony_ci		s->vli = 0;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	while (*in_pos < in_size) {
1848c2ecf20Sopenharmony_ci		byte = in[*in_pos];
1858c2ecf20Sopenharmony_ci		++*in_pos;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		s->vli |= (vli_type)(byte & 0x7F) << s->pos;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		if ((byte & 0x80) == 0) {
1908c2ecf20Sopenharmony_ci			/* Don't allow non-minimal encodings. */
1918c2ecf20Sopenharmony_ci			if (byte == 0 && s->pos != 0)
1928c2ecf20Sopenharmony_ci				return XZ_DATA_ERROR;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci			s->pos = 0;
1958c2ecf20Sopenharmony_ci			return XZ_STREAM_END;
1968c2ecf20Sopenharmony_ci		}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		s->pos += 7;
1998c2ecf20Sopenharmony_ci		if (s->pos == 7 * VLI_BYTES_MAX)
2008c2ecf20Sopenharmony_ci			return XZ_DATA_ERROR;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return XZ_OK;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/*
2078c2ecf20Sopenharmony_ci * Decode the Compressed Data field from a Block. Update and validate
2088c2ecf20Sopenharmony_ci * the observed compressed and uncompressed sizes of the Block so that
2098c2ecf20Sopenharmony_ci * they don't exceed the values possibly stored in the Block Header
2108c2ecf20Sopenharmony_ci * (validation assumes that no integer overflow occurs, since vli_type
2118c2ecf20Sopenharmony_ci * is normally uint64_t). Update the CRC32 if presence of the CRC32
2128c2ecf20Sopenharmony_ci * field was indicated in Stream Header.
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Once the decoding is finished, validate that the observed sizes match
2158c2ecf20Sopenharmony_ci * the sizes possibly stored in the Block Header. Update the hash and
2168c2ecf20Sopenharmony_ci * Block count, which are later used to validate the Index field.
2178c2ecf20Sopenharmony_ci */
2188c2ecf20Sopenharmony_cistatic enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	enum xz_ret ret;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	s->in_start = b->in_pos;
2238c2ecf20Sopenharmony_ci	s->out_start = b->out_pos;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
2268c2ecf20Sopenharmony_ci	if (s->bcj_active)
2278c2ecf20Sopenharmony_ci		ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
2288c2ecf20Sopenharmony_ci	else
2298c2ecf20Sopenharmony_ci#endif
2308c2ecf20Sopenharmony_ci		ret = xz_dec_lzma2_run(s->lzma2, b);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	s->block.compressed += b->in_pos - s->in_start;
2338c2ecf20Sopenharmony_ci	s->block.uncompressed += b->out_pos - s->out_start;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/*
2368c2ecf20Sopenharmony_ci	 * There is no need to separately check for VLI_UNKNOWN, since
2378c2ecf20Sopenharmony_ci	 * the observed sizes are always smaller than VLI_UNKNOWN.
2388c2ecf20Sopenharmony_ci	 */
2398c2ecf20Sopenharmony_ci	if (s->block.compressed > s->block_header.compressed
2408c2ecf20Sopenharmony_ci			|| s->block.uncompressed
2418c2ecf20Sopenharmony_ci				> s->block_header.uncompressed)
2428c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (s->check_type == XZ_CHECK_CRC32)
2458c2ecf20Sopenharmony_ci		s->crc32 = xz_crc32(b->out + s->out_start,
2468c2ecf20Sopenharmony_ci				b->out_pos - s->out_start, s->crc32);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (ret == XZ_STREAM_END) {
2498c2ecf20Sopenharmony_ci		if (s->block_header.compressed != VLI_UNKNOWN
2508c2ecf20Sopenharmony_ci				&& s->block_header.compressed
2518c2ecf20Sopenharmony_ci					!= s->block.compressed)
2528c2ecf20Sopenharmony_ci			return XZ_DATA_ERROR;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		if (s->block_header.uncompressed != VLI_UNKNOWN
2558c2ecf20Sopenharmony_ci				&& s->block_header.uncompressed
2568c2ecf20Sopenharmony_ci					!= s->block.uncompressed)
2578c2ecf20Sopenharmony_ci			return XZ_DATA_ERROR;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		s->block.hash.unpadded += s->block_header.size
2608c2ecf20Sopenharmony_ci				+ s->block.compressed;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci#ifdef XZ_DEC_ANY_CHECK
2638c2ecf20Sopenharmony_ci		s->block.hash.unpadded += check_sizes[s->check_type];
2648c2ecf20Sopenharmony_ci#else
2658c2ecf20Sopenharmony_ci		if (s->check_type == XZ_CHECK_CRC32)
2668c2ecf20Sopenharmony_ci			s->block.hash.unpadded += 4;
2678c2ecf20Sopenharmony_ci#endif
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		s->block.hash.uncompressed += s->block.uncompressed;
2708c2ecf20Sopenharmony_ci		s->block.hash.crc32 = xz_crc32(
2718c2ecf20Sopenharmony_ci				(const uint8_t *)&s->block.hash,
2728c2ecf20Sopenharmony_ci				sizeof(s->block.hash), s->block.hash.crc32);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		++s->block.count;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return ret;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/* Update the Index size and the CRC32 value. */
2818c2ecf20Sopenharmony_cistatic void index_update(struct xz_dec *s, const struct xz_buf *b)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	size_t in_used = b->in_pos - s->in_start;
2848c2ecf20Sopenharmony_ci	s->index.size += in_used;
2858c2ecf20Sopenharmony_ci	s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*
2898c2ecf20Sopenharmony_ci * Decode the Number of Records, Unpadded Size, and Uncompressed Size
2908c2ecf20Sopenharmony_ci * fields from the Index field. That is, Index Padding and CRC32 are not
2918c2ecf20Sopenharmony_ci * decoded by this function.
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
2948c2ecf20Sopenharmony_ci * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
2958c2ecf20Sopenharmony_ci */
2968c2ecf20Sopenharmony_cistatic enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	enum xz_ret ret;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	do {
3018c2ecf20Sopenharmony_ci		ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
3028c2ecf20Sopenharmony_ci		if (ret != XZ_STREAM_END) {
3038c2ecf20Sopenharmony_ci			index_update(s, b);
3048c2ecf20Sopenharmony_ci			return ret;
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		switch (s->index.sequence) {
3088c2ecf20Sopenharmony_ci		case SEQ_INDEX_COUNT:
3098c2ecf20Sopenharmony_ci			s->index.count = s->vli;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci			/*
3128c2ecf20Sopenharmony_ci			 * Validate that the Number of Records field
3138c2ecf20Sopenharmony_ci			 * indicates the same number of Records as
3148c2ecf20Sopenharmony_ci			 * there were Blocks in the Stream.
3158c2ecf20Sopenharmony_ci			 */
3168c2ecf20Sopenharmony_ci			if (s->index.count != s->block.count)
3178c2ecf20Sopenharmony_ci				return XZ_DATA_ERROR;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			s->index.sequence = SEQ_INDEX_UNPADDED;
3208c2ecf20Sopenharmony_ci			break;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		case SEQ_INDEX_UNPADDED:
3238c2ecf20Sopenharmony_ci			s->index.hash.unpadded += s->vli;
3248c2ecf20Sopenharmony_ci			s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
3258c2ecf20Sopenharmony_ci			break;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		case SEQ_INDEX_UNCOMPRESSED:
3288c2ecf20Sopenharmony_ci			s->index.hash.uncompressed += s->vli;
3298c2ecf20Sopenharmony_ci			s->index.hash.crc32 = xz_crc32(
3308c2ecf20Sopenharmony_ci					(const uint8_t *)&s->index.hash,
3318c2ecf20Sopenharmony_ci					sizeof(s->index.hash),
3328c2ecf20Sopenharmony_ci					s->index.hash.crc32);
3338c2ecf20Sopenharmony_ci			--s->index.count;
3348c2ecf20Sopenharmony_ci			s->index.sequence = SEQ_INDEX_UNPADDED;
3358c2ecf20Sopenharmony_ci			break;
3368c2ecf20Sopenharmony_ci		}
3378c2ecf20Sopenharmony_ci	} while (s->index.count > 0);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return XZ_STREAM_END;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/*
3438c2ecf20Sopenharmony_ci * Validate that the next four input bytes match the value of s->crc32.
3448c2ecf20Sopenharmony_ci * s->pos must be zero when starting to validate the first byte.
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_cistatic enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	do {
3498c2ecf20Sopenharmony_ci		if (b->in_pos == b->in_size)
3508c2ecf20Sopenharmony_ci			return XZ_OK;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])
3538c2ecf20Sopenharmony_ci			return XZ_DATA_ERROR;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		s->pos += 8;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	} while (s->pos < 32);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	s->crc32 = 0;
3608c2ecf20Sopenharmony_ci	s->pos = 0;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return XZ_STREAM_END;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci#ifdef XZ_DEC_ANY_CHECK
3668c2ecf20Sopenharmony_ci/*
3678c2ecf20Sopenharmony_ci * Skip over the Check field when the Check ID is not supported.
3688c2ecf20Sopenharmony_ci * Returns true once the whole Check field has been skipped over.
3698c2ecf20Sopenharmony_ci */
3708c2ecf20Sopenharmony_cistatic bool check_skip(struct xz_dec *s, struct xz_buf *b)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	while (s->pos < check_sizes[s->check_type]) {
3738c2ecf20Sopenharmony_ci		if (b->in_pos == b->in_size)
3748c2ecf20Sopenharmony_ci			return false;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		++b->in_pos;
3778c2ecf20Sopenharmony_ci		++s->pos;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	s->pos = 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return true;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci#endif
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
3878c2ecf20Sopenharmony_cistatic enum xz_ret dec_stream_header(struct xz_dec *s)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
3908c2ecf20Sopenharmony_ci		return XZ_FORMAT_ERROR;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
3938c2ecf20Sopenharmony_ci			!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
3948c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
3978c2ecf20Sopenharmony_ci		return XZ_OPTIONS_ERROR;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/*
4008c2ecf20Sopenharmony_ci	 * Of integrity checks, we support only none (Check ID = 0) and
4018c2ecf20Sopenharmony_ci	 * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
4028c2ecf20Sopenharmony_ci	 * we will accept other check types too, but then the check won't
4038c2ecf20Sopenharmony_ci	 * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
4048c2ecf20Sopenharmony_ci	 */
4058c2ecf20Sopenharmony_ci	if (s->temp.buf[HEADER_MAGIC_SIZE + 1] > XZ_CHECK_MAX)
4068c2ecf20Sopenharmony_ci		return XZ_OPTIONS_ERROR;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci#ifdef XZ_DEC_ANY_CHECK
4118c2ecf20Sopenharmony_ci	if (s->check_type > XZ_CHECK_CRC32)
4128c2ecf20Sopenharmony_ci		return XZ_UNSUPPORTED_CHECK;
4138c2ecf20Sopenharmony_ci#else
4148c2ecf20Sopenharmony_ci	if (s->check_type > XZ_CHECK_CRC32)
4158c2ecf20Sopenharmony_ci		return XZ_OPTIONS_ERROR;
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return XZ_OK;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
4228c2ecf20Sopenharmony_cistatic enum xz_ret dec_stream_footer(struct xz_dec *s)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
4258c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
4288c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/*
4318c2ecf20Sopenharmony_ci	 * Validate Backward Size. Note that we never added the size of the
4328c2ecf20Sopenharmony_ci	 * Index CRC32 field to s->index.size, thus we use s->index.size / 4
4338c2ecf20Sopenharmony_ci	 * instead of s->index.size / 4 - 1.
4348c2ecf20Sopenharmony_ci	 */
4358c2ecf20Sopenharmony_ci	if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
4368c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
4398c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/*
4428c2ecf20Sopenharmony_ci	 * Use XZ_STREAM_END instead of XZ_OK to be more convenient
4438c2ecf20Sopenharmony_ci	 * for the caller.
4448c2ecf20Sopenharmony_ci	 */
4458c2ecf20Sopenharmony_ci	return XZ_STREAM_END;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/* Decode the Block Header and initialize the filter chain. */
4498c2ecf20Sopenharmony_cistatic enum xz_ret dec_block_header(struct xz_dec *s)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	enum xz_ret ret;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/*
4548c2ecf20Sopenharmony_ci	 * Validate the CRC32. We know that the temp buffer is at least
4558c2ecf20Sopenharmony_ci	 * eight bytes so this is safe.
4568c2ecf20Sopenharmony_ci	 */
4578c2ecf20Sopenharmony_ci	s->temp.size -= 4;
4588c2ecf20Sopenharmony_ci	if (xz_crc32(s->temp.buf, s->temp.size, 0)
4598c2ecf20Sopenharmony_ci			!= get_le32(s->temp.buf + s->temp.size))
4608c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	s->temp.pos = 2;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/*
4658c2ecf20Sopenharmony_ci	 * Catch unsupported Block Flags. We support only one or two filters
4668c2ecf20Sopenharmony_ci	 * in the chain, so we catch that with the same test.
4678c2ecf20Sopenharmony_ci	 */
4688c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
4698c2ecf20Sopenharmony_ci	if (s->temp.buf[1] & 0x3E)
4708c2ecf20Sopenharmony_ci#else
4718c2ecf20Sopenharmony_ci	if (s->temp.buf[1] & 0x3F)
4728c2ecf20Sopenharmony_ci#endif
4738c2ecf20Sopenharmony_ci		return XZ_OPTIONS_ERROR;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* Compressed Size */
4768c2ecf20Sopenharmony_ci	if (s->temp.buf[1] & 0x40) {
4778c2ecf20Sopenharmony_ci		if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
4788c2ecf20Sopenharmony_ci					!= XZ_STREAM_END)
4798c2ecf20Sopenharmony_ci			return XZ_DATA_ERROR;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		s->block_header.compressed = s->vli;
4828c2ecf20Sopenharmony_ci	} else {
4838c2ecf20Sopenharmony_ci		s->block_header.compressed = VLI_UNKNOWN;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* Uncompressed Size */
4878c2ecf20Sopenharmony_ci	if (s->temp.buf[1] & 0x80) {
4888c2ecf20Sopenharmony_ci		if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
4898c2ecf20Sopenharmony_ci				!= XZ_STREAM_END)
4908c2ecf20Sopenharmony_ci			return XZ_DATA_ERROR;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		s->block_header.uncompressed = s->vli;
4938c2ecf20Sopenharmony_ci	} else {
4948c2ecf20Sopenharmony_ci		s->block_header.uncompressed = VLI_UNKNOWN;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
4988c2ecf20Sopenharmony_ci	/* If there are two filters, the first one must be a BCJ filter. */
4998c2ecf20Sopenharmony_ci	s->bcj_active = s->temp.buf[1] & 0x01;
5008c2ecf20Sopenharmony_ci	if (s->bcj_active) {
5018c2ecf20Sopenharmony_ci		if (s->temp.size - s->temp.pos < 2)
5028c2ecf20Sopenharmony_ci			return XZ_OPTIONS_ERROR;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
5058c2ecf20Sopenharmony_ci		if (ret != XZ_OK)
5068c2ecf20Sopenharmony_ci			return ret;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		/*
5098c2ecf20Sopenharmony_ci		 * We don't support custom start offset,
5108c2ecf20Sopenharmony_ci		 * so Size of Properties must be zero.
5118c2ecf20Sopenharmony_ci		 */
5128c2ecf20Sopenharmony_ci		if (s->temp.buf[s->temp.pos++] != 0x00)
5138c2ecf20Sopenharmony_ci			return XZ_OPTIONS_ERROR;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci#endif
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* Valid Filter Flags always take at least two bytes. */
5188c2ecf20Sopenharmony_ci	if (s->temp.size - s->temp.pos < 2)
5198c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* Filter ID = LZMA2 */
5228c2ecf20Sopenharmony_ci	if (s->temp.buf[s->temp.pos++] != 0x21)
5238c2ecf20Sopenharmony_ci		return XZ_OPTIONS_ERROR;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/* Size of Properties = 1-byte Filter Properties */
5268c2ecf20Sopenharmony_ci	if (s->temp.buf[s->temp.pos++] != 0x01)
5278c2ecf20Sopenharmony_ci		return XZ_OPTIONS_ERROR;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* Filter Properties contains LZMA2 dictionary size. */
5308c2ecf20Sopenharmony_ci	if (s->temp.size - s->temp.pos < 1)
5318c2ecf20Sopenharmony_ci		return XZ_DATA_ERROR;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
5348c2ecf20Sopenharmony_ci	if (ret != XZ_OK)
5358c2ecf20Sopenharmony_ci		return ret;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* The rest must be Header Padding. */
5388c2ecf20Sopenharmony_ci	while (s->temp.pos < s->temp.size)
5398c2ecf20Sopenharmony_ci		if (s->temp.buf[s->temp.pos++] != 0x00)
5408c2ecf20Sopenharmony_ci			return XZ_OPTIONS_ERROR;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	s->temp.pos = 0;
5438c2ecf20Sopenharmony_ci	s->block.compressed = 0;
5448c2ecf20Sopenharmony_ci	s->block.uncompressed = 0;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	return XZ_OK;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	enum xz_ret ret;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/*
5548c2ecf20Sopenharmony_ci	 * Store the start position for the case when we are in the middle
5558c2ecf20Sopenharmony_ci	 * of the Index field.
5568c2ecf20Sopenharmony_ci	 */
5578c2ecf20Sopenharmony_ci	s->in_start = b->in_pos;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	while (true) {
5608c2ecf20Sopenharmony_ci		switch (s->sequence) {
5618c2ecf20Sopenharmony_ci		case SEQ_STREAM_HEADER:
5628c2ecf20Sopenharmony_ci			/*
5638c2ecf20Sopenharmony_ci			 * Stream Header is copied to s->temp, and then
5648c2ecf20Sopenharmony_ci			 * decoded from there. This way if the caller
5658c2ecf20Sopenharmony_ci			 * gives us only little input at a time, we can
5668c2ecf20Sopenharmony_ci			 * still keep the Stream Header decoding code
5678c2ecf20Sopenharmony_ci			 * simple. Similar approach is used in many places
5688c2ecf20Sopenharmony_ci			 * in this file.
5698c2ecf20Sopenharmony_ci			 */
5708c2ecf20Sopenharmony_ci			if (!fill_temp(s, b))
5718c2ecf20Sopenharmony_ci				return XZ_OK;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci			/*
5748c2ecf20Sopenharmony_ci			 * If dec_stream_header() returns
5758c2ecf20Sopenharmony_ci			 * XZ_UNSUPPORTED_CHECK, it is still possible
5768c2ecf20Sopenharmony_ci			 * to continue decoding if working in multi-call
5778c2ecf20Sopenharmony_ci			 * mode. Thus, update s->sequence before calling
5788c2ecf20Sopenharmony_ci			 * dec_stream_header().
5798c2ecf20Sopenharmony_ci			 */
5808c2ecf20Sopenharmony_ci			s->sequence = SEQ_BLOCK_START;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci			ret = dec_stream_header(s);
5838c2ecf20Sopenharmony_ci			if (ret != XZ_OK)
5848c2ecf20Sopenharmony_ci				return ret;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci			/* fall through */
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		case SEQ_BLOCK_START:
5898c2ecf20Sopenharmony_ci			/* We need one byte of input to continue. */
5908c2ecf20Sopenharmony_ci			if (b->in_pos == b->in_size)
5918c2ecf20Sopenharmony_ci				return XZ_OK;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci			/* See if this is the beginning of the Index field. */
5948c2ecf20Sopenharmony_ci			if (b->in[b->in_pos] == 0) {
5958c2ecf20Sopenharmony_ci				s->in_start = b->in_pos++;
5968c2ecf20Sopenharmony_ci				s->sequence = SEQ_INDEX;
5978c2ecf20Sopenharmony_ci				break;
5988c2ecf20Sopenharmony_ci			}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci			/*
6018c2ecf20Sopenharmony_ci			 * Calculate the size of the Block Header and
6028c2ecf20Sopenharmony_ci			 * prepare to decode it.
6038c2ecf20Sopenharmony_ci			 */
6048c2ecf20Sopenharmony_ci			s->block_header.size
6058c2ecf20Sopenharmony_ci				= ((uint32_t)b->in[b->in_pos] + 1) * 4;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci			s->temp.size = s->block_header.size;
6088c2ecf20Sopenharmony_ci			s->temp.pos = 0;
6098c2ecf20Sopenharmony_ci			s->sequence = SEQ_BLOCK_HEADER;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci			/* fall through */
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci		case SEQ_BLOCK_HEADER:
6148c2ecf20Sopenharmony_ci			if (!fill_temp(s, b))
6158c2ecf20Sopenharmony_ci				return XZ_OK;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci			ret = dec_block_header(s);
6188c2ecf20Sopenharmony_ci			if (ret != XZ_OK)
6198c2ecf20Sopenharmony_ci				return ret;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci			s->sequence = SEQ_BLOCK_UNCOMPRESS;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci			/* fall through */
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		case SEQ_BLOCK_UNCOMPRESS:
6268c2ecf20Sopenharmony_ci			ret = dec_block(s, b);
6278c2ecf20Sopenharmony_ci			if (ret != XZ_STREAM_END)
6288c2ecf20Sopenharmony_ci				return ret;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci			s->sequence = SEQ_BLOCK_PADDING;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci			/* fall through */
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci		case SEQ_BLOCK_PADDING:
6358c2ecf20Sopenharmony_ci			/*
6368c2ecf20Sopenharmony_ci			 * Size of Compressed Data + Block Padding
6378c2ecf20Sopenharmony_ci			 * must be a multiple of four. We don't need
6388c2ecf20Sopenharmony_ci			 * s->block.compressed for anything else
6398c2ecf20Sopenharmony_ci			 * anymore, so we use it here to test the size
6408c2ecf20Sopenharmony_ci			 * of the Block Padding field.
6418c2ecf20Sopenharmony_ci			 */
6428c2ecf20Sopenharmony_ci			while (s->block.compressed & 3) {
6438c2ecf20Sopenharmony_ci				if (b->in_pos == b->in_size)
6448c2ecf20Sopenharmony_ci					return XZ_OK;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci				if (b->in[b->in_pos++] != 0)
6478c2ecf20Sopenharmony_ci					return XZ_DATA_ERROR;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci				++s->block.compressed;
6508c2ecf20Sopenharmony_ci			}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci			s->sequence = SEQ_BLOCK_CHECK;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci			/* fall through */
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci		case SEQ_BLOCK_CHECK:
6578c2ecf20Sopenharmony_ci			if (s->check_type == XZ_CHECK_CRC32) {
6588c2ecf20Sopenharmony_ci				ret = crc32_validate(s, b);
6598c2ecf20Sopenharmony_ci				if (ret != XZ_STREAM_END)
6608c2ecf20Sopenharmony_ci					return ret;
6618c2ecf20Sopenharmony_ci			}
6628c2ecf20Sopenharmony_ci#ifdef XZ_DEC_ANY_CHECK
6638c2ecf20Sopenharmony_ci			else if (!check_skip(s, b)) {
6648c2ecf20Sopenharmony_ci				return XZ_OK;
6658c2ecf20Sopenharmony_ci			}
6668c2ecf20Sopenharmony_ci#endif
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci			s->sequence = SEQ_BLOCK_START;
6698c2ecf20Sopenharmony_ci			break;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		case SEQ_INDEX:
6728c2ecf20Sopenharmony_ci			ret = dec_index(s, b);
6738c2ecf20Sopenharmony_ci			if (ret != XZ_STREAM_END)
6748c2ecf20Sopenharmony_ci				return ret;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci			s->sequence = SEQ_INDEX_PADDING;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci			/* fall through */
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		case SEQ_INDEX_PADDING:
6818c2ecf20Sopenharmony_ci			while ((s->index.size + (b->in_pos - s->in_start))
6828c2ecf20Sopenharmony_ci					& 3) {
6838c2ecf20Sopenharmony_ci				if (b->in_pos == b->in_size) {
6848c2ecf20Sopenharmony_ci					index_update(s, b);
6858c2ecf20Sopenharmony_ci					return XZ_OK;
6868c2ecf20Sopenharmony_ci				}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci				if (b->in[b->in_pos++] != 0)
6898c2ecf20Sopenharmony_ci					return XZ_DATA_ERROR;
6908c2ecf20Sopenharmony_ci			}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci			/* Finish the CRC32 value and Index size. */
6938c2ecf20Sopenharmony_ci			index_update(s, b);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci			/* Compare the hashes to validate the Index field. */
6968c2ecf20Sopenharmony_ci			if (!memeq(&s->block.hash, &s->index.hash,
6978c2ecf20Sopenharmony_ci					sizeof(s->block.hash)))
6988c2ecf20Sopenharmony_ci				return XZ_DATA_ERROR;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci			s->sequence = SEQ_INDEX_CRC32;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci			/* fall through */
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		case SEQ_INDEX_CRC32:
7058c2ecf20Sopenharmony_ci			ret = crc32_validate(s, b);
7068c2ecf20Sopenharmony_ci			if (ret != XZ_STREAM_END)
7078c2ecf20Sopenharmony_ci				return ret;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci			s->temp.size = STREAM_HEADER_SIZE;
7108c2ecf20Sopenharmony_ci			s->sequence = SEQ_STREAM_FOOTER;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci			/* fall through */
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		case SEQ_STREAM_FOOTER:
7158c2ecf20Sopenharmony_ci			if (!fill_temp(s, b))
7168c2ecf20Sopenharmony_ci				return XZ_OK;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci			return dec_stream_footer(s);
7198c2ecf20Sopenharmony_ci		}
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/* Never reached */
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci/*
7268c2ecf20Sopenharmony_ci * xz_dec_run() is a wrapper for dec_main() to handle some special cases in
7278c2ecf20Sopenharmony_ci * multi-call and single-call decoding.
7288c2ecf20Sopenharmony_ci *
7298c2ecf20Sopenharmony_ci * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
7308c2ecf20Sopenharmony_ci * are not going to make any progress anymore. This is to prevent the caller
7318c2ecf20Sopenharmony_ci * from calling us infinitely when the input file is truncated or otherwise
7328c2ecf20Sopenharmony_ci * corrupt. Since zlib-style API allows that the caller fills the input buffer
7338c2ecf20Sopenharmony_ci * only when the decoder doesn't produce any new output, we have to be careful
7348c2ecf20Sopenharmony_ci * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
7358c2ecf20Sopenharmony_ci * after the second consecutive call to xz_dec_run() that makes no progress.
7368c2ecf20Sopenharmony_ci *
7378c2ecf20Sopenharmony_ci * In single-call mode, if we couldn't decode everything and no error
7388c2ecf20Sopenharmony_ci * occurred, either the input is truncated or the output buffer is too small.
7398c2ecf20Sopenharmony_ci * Since we know that the last input byte never produces any output, we know
7408c2ecf20Sopenharmony_ci * that if all the input was consumed and decoding wasn't finished, the file
7418c2ecf20Sopenharmony_ci * must be corrupt. Otherwise the output buffer has to be too small or the
7428c2ecf20Sopenharmony_ci * file is corrupt in a way that decoding it produces too big output.
7438c2ecf20Sopenharmony_ci *
7448c2ecf20Sopenharmony_ci * If single-call decoding fails, we reset b->in_pos and b->out_pos back to
7458c2ecf20Sopenharmony_ci * their original values. This is because with some filter chains there won't
7468c2ecf20Sopenharmony_ci * be any valid uncompressed data in the output buffer unless the decoding
7478c2ecf20Sopenharmony_ci * actually succeeds (that's the price to pay of using the output buffer as
7488c2ecf20Sopenharmony_ci * the workspace).
7498c2ecf20Sopenharmony_ci */
7508c2ecf20Sopenharmony_ciXZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	size_t in_start;
7538c2ecf20Sopenharmony_ci	size_t out_start;
7548c2ecf20Sopenharmony_ci	enum xz_ret ret;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (DEC_IS_SINGLE(s->mode))
7578c2ecf20Sopenharmony_ci		xz_dec_reset(s);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	in_start = b->in_pos;
7608c2ecf20Sopenharmony_ci	out_start = b->out_pos;
7618c2ecf20Sopenharmony_ci	ret = dec_main(s, b);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (DEC_IS_SINGLE(s->mode)) {
7648c2ecf20Sopenharmony_ci		if (ret == XZ_OK)
7658c2ecf20Sopenharmony_ci			ret = b->in_pos == b->in_size
7668c2ecf20Sopenharmony_ci					? XZ_DATA_ERROR : XZ_BUF_ERROR;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		if (ret != XZ_STREAM_END) {
7698c2ecf20Sopenharmony_ci			b->in_pos = in_start;
7708c2ecf20Sopenharmony_ci			b->out_pos = out_start;
7718c2ecf20Sopenharmony_ci		}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	} else if (ret == XZ_OK && in_start == b->in_pos
7748c2ecf20Sopenharmony_ci			&& out_start == b->out_pos) {
7758c2ecf20Sopenharmony_ci		if (s->allow_buf_error)
7768c2ecf20Sopenharmony_ci			ret = XZ_BUF_ERROR;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		s->allow_buf_error = true;
7798c2ecf20Sopenharmony_ci	} else {
7808c2ecf20Sopenharmony_ci		s->allow_buf_error = false;
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	return ret;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ciXZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
7898c2ecf20Sopenharmony_ci	if (s == NULL)
7908c2ecf20Sopenharmony_ci		return NULL;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	s->mode = mode;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
7958c2ecf20Sopenharmony_ci	s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
7968c2ecf20Sopenharmony_ci	if (s->bcj == NULL)
7978c2ecf20Sopenharmony_ci		goto error_bcj;
7988c2ecf20Sopenharmony_ci#endif
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
8018c2ecf20Sopenharmony_ci	if (s->lzma2 == NULL)
8028c2ecf20Sopenharmony_ci		goto error_lzma2;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	xz_dec_reset(s);
8058c2ecf20Sopenharmony_ci	return s;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cierror_lzma2:
8088c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
8098c2ecf20Sopenharmony_ci	xz_dec_bcj_end(s->bcj);
8108c2ecf20Sopenharmony_cierror_bcj:
8118c2ecf20Sopenharmony_ci#endif
8128c2ecf20Sopenharmony_ci	kfree(s);
8138c2ecf20Sopenharmony_ci	return NULL;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ciXZ_EXTERN void xz_dec_reset(struct xz_dec *s)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	s->sequence = SEQ_STREAM_HEADER;
8198c2ecf20Sopenharmony_ci	s->allow_buf_error = false;
8208c2ecf20Sopenharmony_ci	s->pos = 0;
8218c2ecf20Sopenharmony_ci	s->crc32 = 0;
8228c2ecf20Sopenharmony_ci	memzero(&s->block, sizeof(s->block));
8238c2ecf20Sopenharmony_ci	memzero(&s->index, sizeof(s->index));
8248c2ecf20Sopenharmony_ci	s->temp.pos = 0;
8258c2ecf20Sopenharmony_ci	s->temp.size = STREAM_HEADER_SIZE;
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ciXZ_EXTERN void xz_dec_end(struct xz_dec *s)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	if (s != NULL) {
8318c2ecf20Sopenharmony_ci		xz_dec_lzma2_end(s->lzma2);
8328c2ecf20Sopenharmony_ci#ifdef XZ_DEC_BCJ
8338c2ecf20Sopenharmony_ci		xz_dec_bcj_end(s->bcj);
8348c2ecf20Sopenharmony_ci#endif
8358c2ecf20Sopenharmony_ci		kfree(s);
8368c2ecf20Sopenharmony_ci	}
8378c2ecf20Sopenharmony_ci}
838