1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file filter_flags_decoder.c
4 /// \brief Decodes a Filter Flags field
6 // Copyright (C) 2007 Lasse Collin
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 ///////////////////////////////////////////////////////////////////////////////
21 #include "lzma_decoder.h"
25 lzma_options_filter *options;
34 /// \brief Position in variable-length integers
37 /// \brief Size of Filter Properties
38 lzma_vli properties_size;
42 #ifdef HAVE_FILTER_SUBBLOCK
44 properties_subblock(lzma_coder *coder, lzma_allocator *allocator,
45 const uint8_t *in lzma_attribute((unused)),
46 size_t *in_pos lzma_attribute((unused)),
47 size_t in_size lzma_attribute((unused)))
49 if (coder->properties_size != 0)
50 return LZMA_HEADER_ERROR;
52 coder->options->options = lzma_alloc(
53 sizeof(lzma_options_subblock), allocator);
54 if (coder->options->options == NULL)
55 return LZMA_MEM_ERROR;
57 ((lzma_options_subblock *)(coder->options->options))
58 ->allow_subfilters = true;
59 return LZMA_STREAM_END;
64 #ifdef HAVE_FILTER_SIMPLE
66 properties_simple(lzma_coder *coder, lzma_allocator *allocator,
67 const uint8_t *in, size_t *in_pos, size_t in_size)
69 if (coder->properties_size == 0)
70 return LZMA_STREAM_END;
72 if (coder->properties_size != 4)
73 return LZMA_HEADER_ERROR;
75 lzma_options_simple *options = coder->options->options;
77 if (options == NULL) {
78 options = lzma_alloc(sizeof(lzma_options_simple), allocator);
80 return LZMA_MEM_ERROR;
82 options->start_offset = 0;
83 coder->options->options = options;
86 while (coder->pos < 4) {
87 if (*in_pos == in_size)
91 |= (uint32_t)(in[*in_pos]) << (8 * coder->pos);
96 // Don't leave an options structure allocated if start_offset is zero.
97 if (options->start_offset == 0) {
98 lzma_free(options, allocator);
99 coder->options->options = NULL;
102 return LZMA_STREAM_END;
107 #ifdef HAVE_FILTER_DELTA
109 properties_delta(lzma_coder *coder, lzma_allocator *allocator,
110 const uint8_t *in, size_t *in_pos, size_t in_size)
112 if (coder->properties_size != 1)
113 return LZMA_HEADER_ERROR;
115 if (*in_pos == in_size)
118 lzma_options_delta *options = lzma_alloc(
119 sizeof(lzma_options_delta), allocator);
121 return LZMA_MEM_ERROR;
123 coder->options->options = options;
125 options->distance = (uint32_t)(in[*in_pos]) + 1;
128 return LZMA_STREAM_END;
133 #ifdef HAVE_FILTER_LZMA
135 properties_lzma(lzma_coder *coder, lzma_allocator *allocator,
136 const uint8_t *in, size_t *in_pos, size_t in_size)
138 // LZMA properties are always two bytes (at least for now).
139 if (coder->properties_size != 2)
140 return LZMA_HEADER_ERROR;
142 assert(coder->pos < 2);
144 while (*in_pos < in_size) {
145 switch (coder->pos) {
147 // Allocate the options structure.
148 coder->options->options = lzma_alloc(
149 sizeof(lzma_options_lzma), allocator);
150 if (coder->options->options == NULL)
151 return LZMA_MEM_ERROR;
153 // Decode lc, lp, and pb.
154 if (lzma_lzma_decode_properties(
155 coder->options->options, in[*in_pos]))
156 return LZMA_HEADER_ERROR;
163 lzma_options_lzma *options = coder->options->options;
165 // Check that reserved bits are unset.
166 if (in[*in_pos] & 0xC0)
167 return LZMA_HEADER_ERROR;
169 // Decode the dictionary size. See the file format
170 // specification section 4.3.4.2 to understand this.
171 if (in[*in_pos] == 0) {
172 options->dictionary_size = 1;
174 } else if (in[*in_pos] > 59) {
175 // Dictionary size is over 1 GiB.
176 // It's not supported at the moment.
177 return LZMA_HEADER_ERROR;
178 # if LZMA_DICTIONARY_SIZE_MAX != UINT32_C(1) << 30
179 # error Update the if()-condition a few lines
180 # error above to match LZMA_DICTIONARY_SIZE_MAX.
184 options->dictionary_size
185 = 2 | ((in[*in_pos] + 1) & 1);
186 options->dictionary_size
187 <<= (in[*in_pos] - 1) / 2;
191 return LZMA_STREAM_END;
196 assert(coder->pos < 2);
203 filter_flags_decode(lzma_coder *coder, lzma_allocator *allocator,
204 const uint8_t *restrict in, size_t *restrict in_pos,
205 size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
206 size_t *restrict out_pos lzma_attribute((unused)),
207 size_t out_size lzma_attribute((unused)),
208 lzma_action action lzma_attribute((unused)))
210 while (*in_pos < in_size || coder->sequence == SEQ_PROPERTIES)
211 switch (coder->sequence) {
213 // Determine the Filter ID and Size of Filter Properties.
214 if (in[*in_pos] >= 0xE0) {
215 // Using External ID. Prepare the ID
216 // for variable-length integer parsing.
217 coder->options->id = 0;
219 if (in[*in_pos] == 0xFF) {
220 // Mark that Size of Filter Properties is
221 // unknown, so we know later that there is
222 // external Size of Filter Properties present.
223 coder->properties_size
224 = LZMA_VLI_VALUE_UNKNOWN;
226 // Take Size of Filter Properties from Misc.
227 coder->properties_size = in[*in_pos] - 0xE0;
230 coder->sequence = SEQ_ID;
233 // The Filter ID is the same as Misc.
234 coder->options->id = in[*in_pos];
236 // The Size of Filter Properties can be calculated
238 coder->properties_size = in[*in_pos] / 0x20;
240 coder->sequence = SEQ_PROPERTIES;
247 const lzma_ret ret = lzma_vli_decode(&coder->options->id,
248 &coder->pos, in, in_pos, in_size);
249 if (ret != LZMA_STREAM_END)
252 if (coder->properties_size == LZMA_VLI_VALUE_UNKNOWN) {
253 // We have also external Size of Filter
254 // Properties. Prepare the size for
255 // variable-length integer parsing.
256 coder->properties_size = 0;
257 coder->sequence = SEQ_SIZE;
259 coder->sequence = SEQ_PROPERTIES;
262 // Reset pos for its next job.
268 const lzma_ret ret = lzma_vli_decode(&coder->properties_size,
269 &coder->pos, in, in_pos, in_size);
270 if (ret != LZMA_STREAM_END)
274 coder->sequence = SEQ_PROPERTIES;
278 case SEQ_PROPERTIES: {
279 lzma_ret (*get_properties)(lzma_coder *coder,
280 lzma_allocator *allocator, const uint8_t *in,
281 size_t *in_pos, size_t in_size);
283 switch (coder->options->id) {
284 #ifdef HAVE_FILTER_COPY
285 case LZMA_FILTER_COPY:
286 return coder->properties_size > 0
287 ? LZMA_HEADER_ERROR : LZMA_STREAM_END;
289 #ifdef HAVE_FILTER_SUBBLOCK
290 case LZMA_FILTER_SUBBLOCK:
291 get_properties = &properties_subblock;
294 #ifdef HAVE_FILTER_SIMPLE
295 # ifdef HAVE_FILTER_X86
296 case LZMA_FILTER_X86:
298 # ifdef HAVE_FILTER_POWERPC
299 case LZMA_FILTER_POWERPC:
301 # ifdef HAVE_FILTER_IA64
302 case LZMA_FILTER_IA64:
304 # ifdef HAVE_FILTER_ARM
305 case LZMA_FILTER_ARM:
307 # ifdef HAVE_FILTER_ARMTHUMB
308 case LZMA_FILTER_ARMTHUMB:
310 # ifdef HAVE_FILTER_SPARC
311 case LZMA_FILTER_SPARC:
313 get_properties = &properties_simple;
316 #ifdef HAVE_FILTER_DELTA
317 case LZMA_FILTER_DELTA:
318 get_properties = &properties_delta;
321 #ifdef HAVE_FILTER_LZMA
322 case LZMA_FILTER_LZMA:
323 get_properties = &properties_lzma;
327 return LZMA_HEADER_ERROR;
330 return get_properties(coder, allocator, in, in_pos, in_size);
334 return LZMA_PROG_ERROR;
342 filter_flags_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
344 lzma_free(coder, allocator);
350 lzma_filter_flags_decoder_init(lzma_next_coder *next,
351 lzma_allocator *allocator, lzma_options_filter *options)
353 if (next->coder == NULL) {
354 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
355 if (next->coder == NULL)
356 return LZMA_MEM_ERROR;
358 next->code = &filter_flags_decode;
359 next->end = &filter_flags_decoder_end;
363 options->options = NULL;
365 next->coder->options = options;
366 next->coder->sequence = SEQ_MISC;
367 next->coder->pos = 0;
368 next->coder->properties_size = 0;
374 extern LZMA_API lzma_ret
375 lzma_filter_flags_decoder(lzma_stream *strm, lzma_options_filter *options)
377 lzma_next_strm_init(strm, lzma_filter_flags_decoder_init, options);
379 strm->internal->supported_actions[LZMA_RUN] = true;