162306a36Sopenharmony_ci/* Lzma decompressor for Linux kernel. Shamelessly snarfed
262306a36Sopenharmony_ci *from busybox 1.1.1
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *Linux kernel adaptation
562306a36Sopenharmony_ci *Copyright (C) 2006  Alain < alain@knaff.lu >
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *Based on small lzma deflate implementation/Small range coder
862306a36Sopenharmony_ci *implementation for lzma.
962306a36Sopenharmony_ci *Copyright (C) 2006  Aurelien Jacobs < aurel@gnuage.org >
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *Based on LzmaDecode.c from the LZMA SDK 4.22 (https://www.7-zip.org/)
1262306a36Sopenharmony_ci *Copyright (C) 1999-2005  Igor Pavlov
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *Copyrights of the parts, see headers below.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *This program is free software; you can redistribute it and/or
1862306a36Sopenharmony_ci *modify it under the terms of the GNU Lesser General Public
1962306a36Sopenharmony_ci *License as published by the Free Software Foundation; either
2062306a36Sopenharmony_ci *version 2.1 of the License, or (at your option) any later version.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *This program is distributed in the hope that it will be useful,
2362306a36Sopenharmony_ci *but WITHOUT ANY WARRANTY; without even the implied warranty of
2462306a36Sopenharmony_ci *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2562306a36Sopenharmony_ci *Lesser General Public License for more details.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *You should have received a copy of the GNU Lesser General Public
2862306a36Sopenharmony_ci *License along with this library; if not, write to the Free Software
2962306a36Sopenharmony_ci *Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#ifdef STATIC
3362306a36Sopenharmony_ci#define PREBOOT
3462306a36Sopenharmony_ci#else
3562306a36Sopenharmony_ci#include <linux/decompress/unlzma.h>
3662306a36Sopenharmony_ci#endif /* STATIC */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <linux/decompress/mm.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define	MIN(a, b) (((a) < (b)) ? (a) : (b))
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic long long INIT read_int(unsigned char *ptr, int size)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	int i;
4562306a36Sopenharmony_ci	long long ret = 0;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	for (i = 0; i < size; i++)
4862306a36Sopenharmony_ci		ret = (ret << 8) | ptr[size-i-1];
4962306a36Sopenharmony_ci	return ret;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define ENDIAN_CONVERT(x) \
5362306a36Sopenharmony_ci  x = (typeof(x))read_int((unsigned char *)&x, sizeof(x))
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Small range coder implementation for lzma.
5762306a36Sopenharmony_ci *Copyright (C) 2006  Aurelien Jacobs < aurel@gnuage.org >
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci *Based on LzmaDecode.c from the LZMA SDK 4.22 (https://www.7-zip.org/)
6062306a36Sopenharmony_ci *Copyright (c) 1999-2005  Igor Pavlov
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#include <linux/compiler.h>
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define LZMA_IOBUF_SIZE	0x10000
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct rc {
6862306a36Sopenharmony_ci	long (*fill)(void*, unsigned long);
6962306a36Sopenharmony_ci	uint8_t *ptr;
7062306a36Sopenharmony_ci	uint8_t *buffer;
7162306a36Sopenharmony_ci	uint8_t *buffer_end;
7262306a36Sopenharmony_ci	long buffer_size;
7362306a36Sopenharmony_ci	uint32_t code;
7462306a36Sopenharmony_ci	uint32_t range;
7562306a36Sopenharmony_ci	uint32_t bound;
7662306a36Sopenharmony_ci	void (*error)(char *);
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define RC_TOP_BITS 24
8162306a36Sopenharmony_ci#define RC_MOVE_BITS 5
8262306a36Sopenharmony_ci#define RC_MODEL_TOTAL_BITS 11
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic long INIT nofill(void *buffer, unsigned long len)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return -1;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* Called twice: once at startup and once in rc_normalize() */
9162306a36Sopenharmony_cistatic void INIT rc_read(struct rc *rc)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	rc->buffer_size = rc->fill((char *)rc->buffer, LZMA_IOBUF_SIZE);
9462306a36Sopenharmony_ci	if (rc->buffer_size <= 0)
9562306a36Sopenharmony_ci		rc->error("unexpected EOF");
9662306a36Sopenharmony_ci	rc->ptr = rc->buffer;
9762306a36Sopenharmony_ci	rc->buffer_end = rc->buffer + rc->buffer_size;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Called once */
10162306a36Sopenharmony_cistatic inline void INIT rc_init(struct rc *rc,
10262306a36Sopenharmony_ci				       long (*fill)(void*, unsigned long),
10362306a36Sopenharmony_ci				       char *buffer, long buffer_size)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	if (fill)
10662306a36Sopenharmony_ci		rc->fill = fill;
10762306a36Sopenharmony_ci	else
10862306a36Sopenharmony_ci		rc->fill = nofill;
10962306a36Sopenharmony_ci	rc->buffer = (uint8_t *)buffer;
11062306a36Sopenharmony_ci	rc->buffer_size = buffer_size;
11162306a36Sopenharmony_ci	rc->buffer_end = rc->buffer + rc->buffer_size;
11262306a36Sopenharmony_ci	rc->ptr = rc->buffer;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	rc->code = 0;
11562306a36Sopenharmony_ci	rc->range = 0xFFFFFFFF;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline void INIT rc_init_code(struct rc *rc)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	int i;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
12362306a36Sopenharmony_ci		if (rc->ptr >= rc->buffer_end)
12462306a36Sopenharmony_ci			rc_read(rc);
12562306a36Sopenharmony_ci		rc->code = (rc->code << 8) | *rc->ptr++;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* Called twice, but one callsite is in inline'd rc_is_bit_0_helper() */
13162306a36Sopenharmony_cistatic void INIT rc_do_normalize(struct rc *rc)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	if (rc->ptr >= rc->buffer_end)
13462306a36Sopenharmony_ci		rc_read(rc);
13562306a36Sopenharmony_ci	rc->range <<= 8;
13662306a36Sopenharmony_ci	rc->code = (rc->code << 8) | *rc->ptr++;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_cistatic inline void INIT rc_normalize(struct rc *rc)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	if (rc->range < (1 << RC_TOP_BITS))
14162306a36Sopenharmony_ci		rc_do_normalize(rc);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/* Called 9 times */
14562306a36Sopenharmony_ci/* Why rc_is_bit_0_helper exists?
14662306a36Sopenharmony_ci *Because we want to always expose (rc->code < rc->bound) to optimizer
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_cistatic inline uint32_t INIT rc_is_bit_0_helper(struct rc *rc, uint16_t *p)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	rc_normalize(rc);
15162306a36Sopenharmony_ci	rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
15262306a36Sopenharmony_ci	return rc->bound;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_cistatic inline int INIT rc_is_bit_0(struct rc *rc, uint16_t *p)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	uint32_t t = rc_is_bit_0_helper(rc, p);
15762306a36Sopenharmony_ci	return rc->code < t;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* Called ~10 times, but very small, thus inlined */
16162306a36Sopenharmony_cistatic inline void INIT rc_update_bit_0(struct rc *rc, uint16_t *p)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	rc->range = rc->bound;
16462306a36Sopenharmony_ci	*p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_cistatic inline void INIT rc_update_bit_1(struct rc *rc, uint16_t *p)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	rc->range -= rc->bound;
16962306a36Sopenharmony_ci	rc->code -= rc->bound;
17062306a36Sopenharmony_ci	*p -= *p >> RC_MOVE_BITS;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Called 4 times in unlzma loop */
17462306a36Sopenharmony_cistatic int INIT rc_get_bit(struct rc *rc, uint16_t *p, int *symbol)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	if (rc_is_bit_0(rc, p)) {
17762306a36Sopenharmony_ci		rc_update_bit_0(rc, p);
17862306a36Sopenharmony_ci		*symbol *= 2;
17962306a36Sopenharmony_ci		return 0;
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		rc_update_bit_1(rc, p);
18262306a36Sopenharmony_ci		*symbol = *symbol * 2 + 1;
18362306a36Sopenharmony_ci		return 1;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/* Called once */
18862306a36Sopenharmony_cistatic inline int INIT rc_direct_bit(struct rc *rc)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	rc_normalize(rc);
19162306a36Sopenharmony_ci	rc->range >>= 1;
19262306a36Sopenharmony_ci	if (rc->code >= rc->range) {
19362306a36Sopenharmony_ci		rc->code -= rc->range;
19462306a36Sopenharmony_ci		return 1;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/* Called twice */
20062306a36Sopenharmony_cistatic inline void INIT
20162306a36Sopenharmony_circ_bit_tree_decode(struct rc *rc, uint16_t *p, int num_levels, int *symbol)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	int i = num_levels;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	*symbol = 1;
20662306a36Sopenharmony_ci	while (i--)
20762306a36Sopenharmony_ci		rc_get_bit(rc, p + *symbol, symbol);
20862306a36Sopenharmony_ci	*symbol -= 1 << num_levels;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/*
21362306a36Sopenharmony_ci * Small lzma deflate implementation.
21462306a36Sopenharmony_ci * Copyright (C) 2006  Aurelien Jacobs < aurel@gnuage.org >
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci * Based on LzmaDecode.c from the LZMA SDK 4.22 (https://www.7-zip.org/)
21762306a36Sopenharmony_ci * Copyright (C) 1999-2005  Igor Pavlov
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct lzma_header {
22262306a36Sopenharmony_ci	uint8_t pos;
22362306a36Sopenharmony_ci	uint32_t dict_size;
22462306a36Sopenharmony_ci	uint64_t dst_size;
22562306a36Sopenharmony_ci} __attribute__ ((packed)) ;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define LZMA_BASE_SIZE 1846
22962306a36Sopenharmony_ci#define LZMA_LIT_SIZE 768
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci#define LZMA_NUM_POS_BITS_MAX 4
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci#define LZMA_LEN_NUM_LOW_BITS 3
23462306a36Sopenharmony_ci#define LZMA_LEN_NUM_MID_BITS 3
23562306a36Sopenharmony_ci#define LZMA_LEN_NUM_HIGH_BITS 8
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#define LZMA_LEN_CHOICE 0
23862306a36Sopenharmony_ci#define LZMA_LEN_CHOICE_2 (LZMA_LEN_CHOICE + 1)
23962306a36Sopenharmony_ci#define LZMA_LEN_LOW (LZMA_LEN_CHOICE_2 + 1)
24062306a36Sopenharmony_ci#define LZMA_LEN_MID (LZMA_LEN_LOW \
24162306a36Sopenharmony_ci		      + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS)))
24262306a36Sopenharmony_ci#define LZMA_LEN_HIGH (LZMA_LEN_MID \
24362306a36Sopenharmony_ci		       +(1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS)))
24462306a36Sopenharmony_ci#define LZMA_NUM_LEN_PROBS (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS))
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#define LZMA_NUM_STATES 12
24762306a36Sopenharmony_ci#define LZMA_NUM_LIT_STATES 7
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci#define LZMA_START_POS_MODEL_INDEX 4
25062306a36Sopenharmony_ci#define LZMA_END_POS_MODEL_INDEX 14
25162306a36Sopenharmony_ci#define LZMA_NUM_FULL_DISTANCES (1 << (LZMA_END_POS_MODEL_INDEX >> 1))
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#define LZMA_NUM_POS_SLOT_BITS 6
25462306a36Sopenharmony_ci#define LZMA_NUM_LEN_TO_POS_STATES 4
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci#define LZMA_NUM_ALIGN_BITS 4
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci#define LZMA_MATCH_MIN_LEN 2
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci#define LZMA_IS_MATCH 0
26162306a36Sopenharmony_ci#define LZMA_IS_REP (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX))
26262306a36Sopenharmony_ci#define LZMA_IS_REP_G0 (LZMA_IS_REP + LZMA_NUM_STATES)
26362306a36Sopenharmony_ci#define LZMA_IS_REP_G1 (LZMA_IS_REP_G0 + LZMA_NUM_STATES)
26462306a36Sopenharmony_ci#define LZMA_IS_REP_G2 (LZMA_IS_REP_G1 + LZMA_NUM_STATES)
26562306a36Sopenharmony_ci#define LZMA_IS_REP_0_LONG (LZMA_IS_REP_G2 + LZMA_NUM_STATES)
26662306a36Sopenharmony_ci#define LZMA_POS_SLOT (LZMA_IS_REP_0_LONG \
26762306a36Sopenharmony_ci		       + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX))
26862306a36Sopenharmony_ci#define LZMA_SPEC_POS (LZMA_POS_SLOT \
26962306a36Sopenharmony_ci		       +(LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS))
27062306a36Sopenharmony_ci#define LZMA_ALIGN (LZMA_SPEC_POS \
27162306a36Sopenharmony_ci		    + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX)
27262306a36Sopenharmony_ci#define LZMA_LEN_CODER (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS))
27362306a36Sopenharmony_ci#define LZMA_REP_LEN_CODER (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS)
27462306a36Sopenharmony_ci#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS)
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistruct writer {
27862306a36Sopenharmony_ci	uint8_t *buffer;
27962306a36Sopenharmony_ci	uint8_t previous_byte;
28062306a36Sopenharmony_ci	size_t buffer_pos;
28162306a36Sopenharmony_ci	int bufsize;
28262306a36Sopenharmony_ci	size_t global_pos;
28362306a36Sopenharmony_ci	long (*flush)(void*, unsigned long);
28462306a36Sopenharmony_ci	struct lzma_header *header;
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistruct cstate {
28862306a36Sopenharmony_ci	int state;
28962306a36Sopenharmony_ci	uint32_t rep0, rep1, rep2, rep3;
29062306a36Sopenharmony_ci};
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic inline size_t INIT get_pos(struct writer *wr)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	return
29562306a36Sopenharmony_ci		wr->global_pos + wr->buffer_pos;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic inline uint8_t INIT peek_old_byte(struct writer *wr,
29962306a36Sopenharmony_ci						uint32_t offs)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	if (!wr->flush) {
30262306a36Sopenharmony_ci		int32_t pos;
30362306a36Sopenharmony_ci		while (offs > wr->header->dict_size)
30462306a36Sopenharmony_ci			offs -= wr->header->dict_size;
30562306a36Sopenharmony_ci		pos = wr->buffer_pos - offs;
30662306a36Sopenharmony_ci		return wr->buffer[pos];
30762306a36Sopenharmony_ci	} else {
30862306a36Sopenharmony_ci		uint32_t pos = wr->buffer_pos - offs;
30962306a36Sopenharmony_ci		while (pos >= wr->header->dict_size)
31062306a36Sopenharmony_ci			pos += wr->header->dict_size;
31162306a36Sopenharmony_ci		return wr->buffer[pos];
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic inline int INIT write_byte(struct writer *wr, uint8_t byte)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	wr->buffer[wr->buffer_pos++] = wr->previous_byte = byte;
31962306a36Sopenharmony_ci	if (wr->flush && wr->buffer_pos == wr->header->dict_size) {
32062306a36Sopenharmony_ci		wr->buffer_pos = 0;
32162306a36Sopenharmony_ci		wr->global_pos += wr->header->dict_size;
32262306a36Sopenharmony_ci		if (wr->flush((char *)wr->buffer, wr->header->dict_size)
32362306a36Sopenharmony_ci				!= wr->header->dict_size)
32462306a36Sopenharmony_ci			return -1;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic inline int INIT copy_byte(struct writer *wr, uint32_t offs)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	return write_byte(wr, peek_old_byte(wr, offs));
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic inline int INIT copy_bytes(struct writer *wr,
33662306a36Sopenharmony_ci					 uint32_t rep0, int len)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	do {
33962306a36Sopenharmony_ci		if (copy_byte(wr, rep0))
34062306a36Sopenharmony_ci			return -1;
34162306a36Sopenharmony_ci		len--;
34262306a36Sopenharmony_ci	} while (len != 0 && wr->buffer_pos < wr->header->dst_size);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return len;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic inline int INIT process_bit0(struct writer *wr, struct rc *rc,
34862306a36Sopenharmony_ci				     struct cstate *cst, uint16_t *p,
34962306a36Sopenharmony_ci				     int pos_state, uint16_t *prob,
35062306a36Sopenharmony_ci				     int lc, uint32_t literal_pos_mask) {
35162306a36Sopenharmony_ci	int mi = 1;
35262306a36Sopenharmony_ci	rc_update_bit_0(rc, prob);
35362306a36Sopenharmony_ci	prob = (p + LZMA_LITERAL +
35462306a36Sopenharmony_ci		(LZMA_LIT_SIZE
35562306a36Sopenharmony_ci		 * (((get_pos(wr) & literal_pos_mask) << lc)
35662306a36Sopenharmony_ci		    + (wr->previous_byte >> (8 - lc))))
35762306a36Sopenharmony_ci		);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (cst->state >= LZMA_NUM_LIT_STATES) {
36062306a36Sopenharmony_ci		int match_byte = peek_old_byte(wr, cst->rep0);
36162306a36Sopenharmony_ci		do {
36262306a36Sopenharmony_ci			int bit;
36362306a36Sopenharmony_ci			uint16_t *prob_lit;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci			match_byte <<= 1;
36662306a36Sopenharmony_ci			bit = match_byte & 0x100;
36762306a36Sopenharmony_ci			prob_lit = prob + 0x100 + bit + mi;
36862306a36Sopenharmony_ci			if (rc_get_bit(rc, prob_lit, &mi)) {
36962306a36Sopenharmony_ci				if (!bit)
37062306a36Sopenharmony_ci					break;
37162306a36Sopenharmony_ci			} else {
37262306a36Sopenharmony_ci				if (bit)
37362306a36Sopenharmony_ci					break;
37462306a36Sopenharmony_ci			}
37562306a36Sopenharmony_ci		} while (mi < 0x100);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	while (mi < 0x100) {
37862306a36Sopenharmony_ci		uint16_t *prob_lit = prob + mi;
37962306a36Sopenharmony_ci		rc_get_bit(rc, prob_lit, &mi);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci	if (cst->state < 4)
38262306a36Sopenharmony_ci		cst->state = 0;
38362306a36Sopenharmony_ci	else if (cst->state < 10)
38462306a36Sopenharmony_ci		cst->state -= 3;
38562306a36Sopenharmony_ci	else
38662306a36Sopenharmony_ci		cst->state -= 6;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return write_byte(wr, mi);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic inline int INIT process_bit1(struct writer *wr, struct rc *rc,
39262306a36Sopenharmony_ci					    struct cstate *cst, uint16_t *p,
39362306a36Sopenharmony_ci					    int pos_state, uint16_t *prob) {
39462306a36Sopenharmony_ci	int offset;
39562306a36Sopenharmony_ci	uint16_t *prob_len;
39662306a36Sopenharmony_ci	int num_bits;
39762306a36Sopenharmony_ci	int len;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	rc_update_bit_1(rc, prob);
40062306a36Sopenharmony_ci	prob = p + LZMA_IS_REP + cst->state;
40162306a36Sopenharmony_ci	if (rc_is_bit_0(rc, prob)) {
40262306a36Sopenharmony_ci		rc_update_bit_0(rc, prob);
40362306a36Sopenharmony_ci		cst->rep3 = cst->rep2;
40462306a36Sopenharmony_ci		cst->rep2 = cst->rep1;
40562306a36Sopenharmony_ci		cst->rep1 = cst->rep0;
40662306a36Sopenharmony_ci		cst->state = cst->state < LZMA_NUM_LIT_STATES ? 0 : 3;
40762306a36Sopenharmony_ci		prob = p + LZMA_LEN_CODER;
40862306a36Sopenharmony_ci	} else {
40962306a36Sopenharmony_ci		rc_update_bit_1(rc, prob);
41062306a36Sopenharmony_ci		prob = p + LZMA_IS_REP_G0 + cst->state;
41162306a36Sopenharmony_ci		if (rc_is_bit_0(rc, prob)) {
41262306a36Sopenharmony_ci			rc_update_bit_0(rc, prob);
41362306a36Sopenharmony_ci			prob = (p + LZMA_IS_REP_0_LONG
41462306a36Sopenharmony_ci				+ (cst->state <<
41562306a36Sopenharmony_ci				   LZMA_NUM_POS_BITS_MAX) +
41662306a36Sopenharmony_ci				pos_state);
41762306a36Sopenharmony_ci			if (rc_is_bit_0(rc, prob)) {
41862306a36Sopenharmony_ci				rc_update_bit_0(rc, prob);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci				cst->state = cst->state < LZMA_NUM_LIT_STATES ?
42162306a36Sopenharmony_ci					9 : 11;
42262306a36Sopenharmony_ci				return copy_byte(wr, cst->rep0);
42362306a36Sopenharmony_ci			} else {
42462306a36Sopenharmony_ci				rc_update_bit_1(rc, prob);
42562306a36Sopenharmony_ci			}
42662306a36Sopenharmony_ci		} else {
42762306a36Sopenharmony_ci			uint32_t distance;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci			rc_update_bit_1(rc, prob);
43062306a36Sopenharmony_ci			prob = p + LZMA_IS_REP_G1 + cst->state;
43162306a36Sopenharmony_ci			if (rc_is_bit_0(rc, prob)) {
43262306a36Sopenharmony_ci				rc_update_bit_0(rc, prob);
43362306a36Sopenharmony_ci				distance = cst->rep1;
43462306a36Sopenharmony_ci			} else {
43562306a36Sopenharmony_ci				rc_update_bit_1(rc, prob);
43662306a36Sopenharmony_ci				prob = p + LZMA_IS_REP_G2 + cst->state;
43762306a36Sopenharmony_ci				if (rc_is_bit_0(rc, prob)) {
43862306a36Sopenharmony_ci					rc_update_bit_0(rc, prob);
43962306a36Sopenharmony_ci					distance = cst->rep2;
44062306a36Sopenharmony_ci				} else {
44162306a36Sopenharmony_ci					rc_update_bit_1(rc, prob);
44262306a36Sopenharmony_ci					distance = cst->rep3;
44362306a36Sopenharmony_ci					cst->rep3 = cst->rep2;
44462306a36Sopenharmony_ci				}
44562306a36Sopenharmony_ci				cst->rep2 = cst->rep1;
44662306a36Sopenharmony_ci			}
44762306a36Sopenharmony_ci			cst->rep1 = cst->rep0;
44862306a36Sopenharmony_ci			cst->rep0 = distance;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci		cst->state = cst->state < LZMA_NUM_LIT_STATES ? 8 : 11;
45162306a36Sopenharmony_ci		prob = p + LZMA_REP_LEN_CODER;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	prob_len = prob + LZMA_LEN_CHOICE;
45562306a36Sopenharmony_ci	if (rc_is_bit_0(rc, prob_len)) {
45662306a36Sopenharmony_ci		rc_update_bit_0(rc, prob_len);
45762306a36Sopenharmony_ci		prob_len = (prob + LZMA_LEN_LOW
45862306a36Sopenharmony_ci			    + (pos_state <<
45962306a36Sopenharmony_ci			       LZMA_LEN_NUM_LOW_BITS));
46062306a36Sopenharmony_ci		offset = 0;
46162306a36Sopenharmony_ci		num_bits = LZMA_LEN_NUM_LOW_BITS;
46262306a36Sopenharmony_ci	} else {
46362306a36Sopenharmony_ci		rc_update_bit_1(rc, prob_len);
46462306a36Sopenharmony_ci		prob_len = prob + LZMA_LEN_CHOICE_2;
46562306a36Sopenharmony_ci		if (rc_is_bit_0(rc, prob_len)) {
46662306a36Sopenharmony_ci			rc_update_bit_0(rc, prob_len);
46762306a36Sopenharmony_ci			prob_len = (prob + LZMA_LEN_MID
46862306a36Sopenharmony_ci				    + (pos_state <<
46962306a36Sopenharmony_ci				       LZMA_LEN_NUM_MID_BITS));
47062306a36Sopenharmony_ci			offset = 1 << LZMA_LEN_NUM_LOW_BITS;
47162306a36Sopenharmony_ci			num_bits = LZMA_LEN_NUM_MID_BITS;
47262306a36Sopenharmony_ci		} else {
47362306a36Sopenharmony_ci			rc_update_bit_1(rc, prob_len);
47462306a36Sopenharmony_ci			prob_len = prob + LZMA_LEN_HIGH;
47562306a36Sopenharmony_ci			offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
47662306a36Sopenharmony_ci				  + (1 << LZMA_LEN_NUM_MID_BITS));
47762306a36Sopenharmony_ci			num_bits = LZMA_LEN_NUM_HIGH_BITS;
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	rc_bit_tree_decode(rc, prob_len, num_bits, &len);
48262306a36Sopenharmony_ci	len += offset;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (cst->state < 4) {
48562306a36Sopenharmony_ci		int pos_slot;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		cst->state += LZMA_NUM_LIT_STATES;
48862306a36Sopenharmony_ci		prob =
48962306a36Sopenharmony_ci			p + LZMA_POS_SLOT +
49062306a36Sopenharmony_ci			((len <
49162306a36Sopenharmony_ci			  LZMA_NUM_LEN_TO_POS_STATES ? len :
49262306a36Sopenharmony_ci			  LZMA_NUM_LEN_TO_POS_STATES - 1)
49362306a36Sopenharmony_ci			 << LZMA_NUM_POS_SLOT_BITS);
49462306a36Sopenharmony_ci		rc_bit_tree_decode(rc, prob,
49562306a36Sopenharmony_ci				   LZMA_NUM_POS_SLOT_BITS,
49662306a36Sopenharmony_ci				   &pos_slot);
49762306a36Sopenharmony_ci		if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
49862306a36Sopenharmony_ci			int i, mi;
49962306a36Sopenharmony_ci			num_bits = (pos_slot >> 1) - 1;
50062306a36Sopenharmony_ci			cst->rep0 = 2 | (pos_slot & 1);
50162306a36Sopenharmony_ci			if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
50262306a36Sopenharmony_ci				cst->rep0 <<= num_bits;
50362306a36Sopenharmony_ci				prob = p + LZMA_SPEC_POS +
50462306a36Sopenharmony_ci					cst->rep0 - pos_slot - 1;
50562306a36Sopenharmony_ci			} else {
50662306a36Sopenharmony_ci				num_bits -= LZMA_NUM_ALIGN_BITS;
50762306a36Sopenharmony_ci				while (num_bits--)
50862306a36Sopenharmony_ci					cst->rep0 = (cst->rep0 << 1) |
50962306a36Sopenharmony_ci						rc_direct_bit(rc);
51062306a36Sopenharmony_ci				prob = p + LZMA_ALIGN;
51162306a36Sopenharmony_ci				cst->rep0 <<= LZMA_NUM_ALIGN_BITS;
51262306a36Sopenharmony_ci				num_bits = LZMA_NUM_ALIGN_BITS;
51362306a36Sopenharmony_ci			}
51462306a36Sopenharmony_ci			i = 1;
51562306a36Sopenharmony_ci			mi = 1;
51662306a36Sopenharmony_ci			while (num_bits--) {
51762306a36Sopenharmony_ci				if (rc_get_bit(rc, prob + mi, &mi))
51862306a36Sopenharmony_ci					cst->rep0 |= i;
51962306a36Sopenharmony_ci				i <<= 1;
52062306a36Sopenharmony_ci			}
52162306a36Sopenharmony_ci		} else
52262306a36Sopenharmony_ci			cst->rep0 = pos_slot;
52362306a36Sopenharmony_ci		if (++(cst->rep0) == 0)
52462306a36Sopenharmony_ci			return 0;
52562306a36Sopenharmony_ci		if (cst->rep0 > wr->header->dict_size
52662306a36Sopenharmony_ci				|| cst->rep0 > get_pos(wr))
52762306a36Sopenharmony_ci			return -1;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	len += LZMA_MATCH_MIN_LEN;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	return copy_bytes(wr, cst->rep0, len);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ciSTATIC inline int INIT unlzma(unsigned char *buf, long in_len,
53862306a36Sopenharmony_ci			      long (*fill)(void*, unsigned long),
53962306a36Sopenharmony_ci			      long (*flush)(void*, unsigned long),
54062306a36Sopenharmony_ci			      unsigned char *output,
54162306a36Sopenharmony_ci			      long *posp,
54262306a36Sopenharmony_ci			      void(*error)(char *x)
54362306a36Sopenharmony_ci	)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct lzma_header header;
54662306a36Sopenharmony_ci	int lc, pb, lp;
54762306a36Sopenharmony_ci	uint32_t pos_state_mask;
54862306a36Sopenharmony_ci	uint32_t literal_pos_mask;
54962306a36Sopenharmony_ci	uint16_t *p;
55062306a36Sopenharmony_ci	int num_probs;
55162306a36Sopenharmony_ci	struct rc rc;
55262306a36Sopenharmony_ci	int i, mi;
55362306a36Sopenharmony_ci	struct writer wr;
55462306a36Sopenharmony_ci	struct cstate cst;
55562306a36Sopenharmony_ci	unsigned char *inbuf;
55662306a36Sopenharmony_ci	int ret = -1;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	rc.error = error;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (buf)
56162306a36Sopenharmony_ci		inbuf = buf;
56262306a36Sopenharmony_ci	else
56362306a36Sopenharmony_ci		inbuf = malloc(LZMA_IOBUF_SIZE);
56462306a36Sopenharmony_ci	if (!inbuf) {
56562306a36Sopenharmony_ci		error("Could not allocate input buffer");
56662306a36Sopenharmony_ci		goto exit_0;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	cst.state = 0;
57062306a36Sopenharmony_ci	cst.rep0 = cst.rep1 = cst.rep2 = cst.rep3 = 1;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	wr.header = &header;
57362306a36Sopenharmony_ci	wr.flush = flush;
57462306a36Sopenharmony_ci	wr.global_pos = 0;
57562306a36Sopenharmony_ci	wr.previous_byte = 0;
57662306a36Sopenharmony_ci	wr.buffer_pos = 0;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	rc_init(&rc, fill, inbuf, in_len);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	for (i = 0; i < sizeof(header); i++) {
58162306a36Sopenharmony_ci		if (rc.ptr >= rc.buffer_end)
58262306a36Sopenharmony_ci			rc_read(&rc);
58362306a36Sopenharmony_ci		((unsigned char *)&header)[i] = *rc.ptr++;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (header.pos >= (9 * 5 * 5)) {
58762306a36Sopenharmony_ci		error("bad header");
58862306a36Sopenharmony_ci		goto exit_1;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	mi = 0;
59262306a36Sopenharmony_ci	lc = header.pos;
59362306a36Sopenharmony_ci	while (lc >= 9) {
59462306a36Sopenharmony_ci		mi++;
59562306a36Sopenharmony_ci		lc -= 9;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci	pb = 0;
59862306a36Sopenharmony_ci	lp = mi;
59962306a36Sopenharmony_ci	while (lp >= 5) {
60062306a36Sopenharmony_ci		pb++;
60162306a36Sopenharmony_ci		lp -= 5;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci	pos_state_mask = (1 << pb) - 1;
60462306a36Sopenharmony_ci	literal_pos_mask = (1 << lp) - 1;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	ENDIAN_CONVERT(header.dict_size);
60762306a36Sopenharmony_ci	ENDIAN_CONVERT(header.dst_size);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (header.dict_size == 0)
61062306a36Sopenharmony_ci		header.dict_size = 1;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (output)
61362306a36Sopenharmony_ci		wr.buffer = output;
61462306a36Sopenharmony_ci	else {
61562306a36Sopenharmony_ci		wr.bufsize = MIN(header.dst_size, header.dict_size);
61662306a36Sopenharmony_ci		wr.buffer = large_malloc(wr.bufsize);
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	if (wr.buffer == NULL)
61962306a36Sopenharmony_ci		goto exit_1;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
62262306a36Sopenharmony_ci	p = (uint16_t *) large_malloc(num_probs * sizeof(*p));
62362306a36Sopenharmony_ci	if (p == NULL)
62462306a36Sopenharmony_ci		goto exit_2;
62562306a36Sopenharmony_ci	num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
62662306a36Sopenharmony_ci	for (i = 0; i < num_probs; i++)
62762306a36Sopenharmony_ci		p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	rc_init_code(&rc);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	while (get_pos(&wr) < header.dst_size) {
63262306a36Sopenharmony_ci		int pos_state =	get_pos(&wr) & pos_state_mask;
63362306a36Sopenharmony_ci		uint16_t *prob = p + LZMA_IS_MATCH +
63462306a36Sopenharmony_ci			(cst.state << LZMA_NUM_POS_BITS_MAX) + pos_state;
63562306a36Sopenharmony_ci		if (rc_is_bit_0(&rc, prob)) {
63662306a36Sopenharmony_ci			if (process_bit0(&wr, &rc, &cst, p, pos_state, prob,
63762306a36Sopenharmony_ci					lc, literal_pos_mask)) {
63862306a36Sopenharmony_ci				error("LZMA data is corrupt");
63962306a36Sopenharmony_ci				goto exit_3;
64062306a36Sopenharmony_ci			}
64162306a36Sopenharmony_ci		} else {
64262306a36Sopenharmony_ci			if (process_bit1(&wr, &rc, &cst, p, pos_state, prob)) {
64362306a36Sopenharmony_ci				error("LZMA data is corrupt");
64462306a36Sopenharmony_ci				goto exit_3;
64562306a36Sopenharmony_ci			}
64662306a36Sopenharmony_ci			if (cst.rep0 == 0)
64762306a36Sopenharmony_ci				break;
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci		if (rc.buffer_size <= 0)
65062306a36Sopenharmony_ci			goto exit_3;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (posp)
65462306a36Sopenharmony_ci		*posp = rc.ptr-rc.buffer;
65562306a36Sopenharmony_ci	if (!wr.flush || wr.flush(wr.buffer, wr.buffer_pos) == wr.buffer_pos)
65662306a36Sopenharmony_ci		ret = 0;
65762306a36Sopenharmony_ciexit_3:
65862306a36Sopenharmony_ci	large_free(p);
65962306a36Sopenharmony_ciexit_2:
66062306a36Sopenharmony_ci	if (!output)
66162306a36Sopenharmony_ci		large_free(wr.buffer);
66262306a36Sopenharmony_ciexit_1:
66362306a36Sopenharmony_ci	if (!buf)
66462306a36Sopenharmony_ci		free(inbuf);
66562306a36Sopenharmony_ciexit_0:
66662306a36Sopenharmony_ci	return ret;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci#ifdef PREBOOT
67062306a36Sopenharmony_ciSTATIC int INIT __decompress(unsigned char *buf, long in_len,
67162306a36Sopenharmony_ci			      long (*fill)(void*, unsigned long),
67262306a36Sopenharmony_ci			      long (*flush)(void*, unsigned long),
67362306a36Sopenharmony_ci			      unsigned char *output, long out_len,
67462306a36Sopenharmony_ci			      long *posp,
67562306a36Sopenharmony_ci			      void (*error)(char *x))
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	return unlzma(buf, in_len - 4, fill, flush, output, posp, error);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci#endif
680