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