1///////////////////////////////////////////////////////////////////////////////
2//
3/// \file       alone_decoder.c
4/// \brief      Decoder for LZMA_Alone files
5//
6//  Author:     Lasse Collin
7//
8//  This file has been put into the public domain.
9//  You can do whatever you want with this file.
10//
11///////////////////////////////////////////////////////////////////////////////
12
13#include "alone_decoder.h"
14#include "lzma_decoder.h"
15#include "lz_decoder.h"
16
17
18typedef struct {
19	lzma_next_coder next;
20
21	enum {
22		SEQ_PROPERTIES,
23		SEQ_DICTIONARY_SIZE,
24		SEQ_UNCOMPRESSED_SIZE,
25		SEQ_CODER_INIT,
26		SEQ_CODE,
27	} sequence;
28
29	/// If true, reject files that are unlikely to be .lzma files.
30	/// If false, more non-.lzma files get accepted and will give
31	/// LZMA_DATA_ERROR either immediately or after a few output bytes.
32	bool picky;
33
34	/// Position in the header fields
35	size_t pos;
36
37	/// Uncompressed size decoded from the header
38	lzma_vli uncompressed_size;
39
40	/// Memory usage limit
41	uint64_t memlimit;
42
43	/// Amount of memory actually needed (only an estimate)
44	uint64_t memusage;
45
46	/// Options decoded from the header needed to initialize
47	/// the LZMA decoder
48	lzma_options_lzma options;
49} lzma_alone_coder;
50
51
52static lzma_ret
53alone_decode(void *coder_ptr,
54		const lzma_allocator *allocator lzma_attribute((__unused__)),
55		const uint8_t *restrict in, size_t *restrict in_pos,
56		size_t in_size, uint8_t *restrict out,
57		size_t *restrict out_pos, size_t out_size,
58		lzma_action action)
59{
60	lzma_alone_coder *coder = coder_ptr;
61
62	while (*out_pos < out_size
63			&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
64	switch (coder->sequence) {
65	case SEQ_PROPERTIES:
66		if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
67			return LZMA_FORMAT_ERROR;
68
69		coder->sequence = SEQ_DICTIONARY_SIZE;
70		++*in_pos;
71		break;
72
73	case SEQ_DICTIONARY_SIZE:
74		coder->options.dict_size
75				|= (size_t)(in[*in_pos]) << (coder->pos * 8);
76
77		if (++coder->pos == 4) {
78			if (coder->picky && coder->options.dict_size
79					!= UINT32_MAX) {
80				// A hack to ditch tons of false positives:
81				// We allow only dictionary sizes that are
82				// 2^n or 2^n + 2^(n-1). LZMA_Alone created
83				// only files with 2^n, but accepts any
84				// dictionary size.
85				uint32_t d = coder->options.dict_size - 1;
86				d |= d >> 2;
87				d |= d >> 3;
88				d |= d >> 4;
89				d |= d >> 8;
90				d |= d >> 16;
91				++d;
92
93				if (d != coder->options.dict_size)
94					return LZMA_FORMAT_ERROR;
95			}
96
97			coder->pos = 0;
98			coder->sequence = SEQ_UNCOMPRESSED_SIZE;
99		}
100
101		++*in_pos;
102		break;
103
104	case SEQ_UNCOMPRESSED_SIZE:
105		coder->uncompressed_size
106				|= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
107		++*in_pos;
108		if (++coder->pos < 8)
109			break;
110
111		// Another hack to ditch false positives: Assume that
112		// if the uncompressed size is known, it must be less
113		// than 256 GiB.
114		if (coder->picky
115				&& coder->uncompressed_size != LZMA_VLI_UNKNOWN
116				&& coder->uncompressed_size
117					>= (LZMA_VLI_C(1) << 38))
118			return LZMA_FORMAT_ERROR;
119
120		// Calculate the memory usage so that it is ready
121		// for SEQ_CODER_INIT.
122		coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
123				+ LZMA_MEMUSAGE_BASE;
124
125		coder->pos = 0;
126		coder->sequence = SEQ_CODER_INIT;
127
128	// Fall through
129
130	case SEQ_CODER_INIT: {
131		if (coder->memusage > coder->memlimit)
132			return LZMA_MEMLIMIT_ERROR;
133
134		lzma_filter_info filters[2] = {
135			{
136				.init = &lzma_lzma_decoder_init,
137				.options = &coder->options,
138			}, {
139				.init = NULL,
140			}
141		};
142
143		const lzma_ret ret = lzma_next_filter_init(&coder->next,
144				allocator, filters);
145		if (ret != LZMA_OK)
146			return ret;
147
148		// Use a hack to set the uncompressed size.
149		lzma_lz_decoder_uncompressed(coder->next.coder,
150				coder->uncompressed_size);
151
152		coder->sequence = SEQ_CODE;
153		break;
154	}
155
156	case SEQ_CODE: {
157		return coder->next.code(coder->next.coder,
158				allocator, in, in_pos, in_size,
159				out, out_pos, out_size, action);
160	}
161
162	default:
163		return LZMA_PROG_ERROR;
164	}
165
166	return LZMA_OK;
167}
168
169
170static void
171alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
172{
173	lzma_alone_coder *coder = coder_ptr;
174	lzma_next_end(&coder->next, allocator);
175	lzma_free(coder, allocator);
176	return;
177}
178
179
180static lzma_ret
181alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
182		uint64_t *old_memlimit, uint64_t new_memlimit)
183{
184	lzma_alone_coder *coder = coder_ptr;
185
186	*memusage = coder->memusage;
187	*old_memlimit = coder->memlimit;
188
189	if (new_memlimit != 0) {
190		if (new_memlimit < coder->memusage)
191			return LZMA_MEMLIMIT_ERROR;
192
193		coder->memlimit = new_memlimit;
194	}
195
196	return LZMA_OK;
197}
198
199
200extern lzma_ret
201lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
202		uint64_t memlimit, bool picky)
203{
204	lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
205
206	if (memlimit == 0)
207		return LZMA_PROG_ERROR;
208
209	lzma_alone_coder *coder = next->coder;
210
211	if (coder == NULL) {
212		coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
213		if (coder == NULL)
214			return LZMA_MEM_ERROR;
215
216		next->coder = coder;
217		next->code = &alone_decode;
218		next->end = &alone_decoder_end;
219		next->memconfig = &alone_decoder_memconfig;
220		coder->next = LZMA_NEXT_CODER_INIT;
221	}
222
223	coder->sequence = SEQ_PROPERTIES;
224	coder->picky = picky;
225	coder->pos = 0;
226	coder->options.dict_size = 0;
227	coder->options.preset_dict = NULL;
228	coder->options.preset_dict_size = 0;
229	coder->uncompressed_size = 0;
230	coder->memlimit = memlimit;
231	coder->memusage = LZMA_MEMUSAGE_BASE;
232
233	return LZMA_OK;
234}
235
236
237extern LZMA_API(lzma_ret)
238lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
239{
240	lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false);
241
242	strm->internal->supported_actions[LZMA_RUN] = true;
243	strm->internal->supported_actions[LZMA_FINISH] = true;
244
245	return LZMA_OK;
246}
247