xref: /freebsd/contrib/xz/src/liblzma/common/alone_decoder.c (revision 4928135658a9d0eaee37003df6137ab363fcb0b4)
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 
18 typedef 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 
52 static lzma_ret
53 alone_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 
170 static void
171 alone_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 
180 static lzma_ret
181 alone_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 
200 extern lzma_ret
201 lzma_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 	lzma_alone_coder *coder = next->coder;
207 
208 	if (coder == NULL) {
209 		coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
210 		if (coder == NULL)
211 			return LZMA_MEM_ERROR;
212 
213 		next->coder = coder;
214 		next->code = &alone_decode;
215 		next->end = &alone_decoder_end;
216 		next->memconfig = &alone_decoder_memconfig;
217 		coder->next = LZMA_NEXT_CODER_INIT;
218 	}
219 
220 	coder->sequence = SEQ_PROPERTIES;
221 	coder->picky = picky;
222 	coder->pos = 0;
223 	coder->options.dict_size = 0;
224 	coder->options.preset_dict = NULL;
225 	coder->options.preset_dict_size = 0;
226 	coder->uncompressed_size = 0;
227 	coder->memlimit = my_max(1, memlimit);
228 	coder->memusage = LZMA_MEMUSAGE_BASE;
229 
230 	return LZMA_OK;
231 }
232 
233 
234 extern LZMA_API(lzma_ret)
235 lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
236 {
237 	lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false);
238 
239 	strm->internal->supported_actions[LZMA_RUN] = true;
240 	strm->internal->supported_actions[LZMA_FINISH] = true;
241 
242 	return LZMA_OK;
243 }
244