1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file filter_flags_encoder.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_encoder.h"
24 /// \brief Calculates the size of the Filter Properties field
26 /// This currently can return only LZMA_OK or LZMA_HEADER_ERROR, but
27 /// with some new filters it may return also LZMA_PROG_ERROR.
29 get_properties_size(uint32_t *size, const lzma_options_filter *options)
31 lzma_ret ret = LZMA_OK;
33 switch (options->id) {
34 #ifdef HAVE_FILTER_COPY
35 case LZMA_FILTER_COPY:
40 #ifdef HAVE_FILTER_SUBBLOCK
41 case LZMA_FILTER_SUBBLOCK:
46 #ifdef HAVE_FILTER_SIMPLE
47 # ifdef HAVE_FILTER_X86
50 # ifdef HAVE_FILTER_POWERPC
51 case LZMA_FILTER_POWERPC:
53 # ifdef HAVE_FILTER_IA64
54 case LZMA_FILTER_IA64:
56 # ifdef HAVE_FILTER_ARM
59 # ifdef HAVE_FILTER_ARMTHUMB
60 case LZMA_FILTER_ARMTHUMB:
62 # ifdef HAVE_FILTER_SPARC
63 case LZMA_FILTER_SPARC:
65 if (options->options == NULL || ((const lzma_options_simple *)(
66 options->options))->start_offset == 0)
73 #ifdef HAVE_FILTER_DELTA
74 case LZMA_FILTER_DELTA:
79 #ifdef HAVE_FILTER_LZMA
80 case LZMA_FILTER_LZMA:
86 // Unknown filter - if the Filter ID is a proper VLI,
87 // return LZMA_HEADER_ERROR instead of LZMA_PROG_ERROR,
88 // because it's possible that we just don't have support
89 // compiled in for the requested filter.
90 ret = options->id <= LZMA_VLI_VALUE_MAX
91 ? LZMA_HEADER_ERROR : LZMA_PROG_ERROR;
99 extern LZMA_API lzma_ret
100 lzma_filter_flags_size(uint32_t *size, const lzma_options_filter *options)
102 // Get size of Filter Properties.
104 const lzma_ret ret = get_properties_size(&prop_size, options);
108 // Size of Filter ID field if it exists.
110 size_t prop_size_size;
111 if (options->id < 0xE0
112 && (lzma_vli)(prop_size) == options->id / 0x20) {
113 // ID and Size of Filter Properties fit into Misc.
118 // At least Filter ID is stored using the External ID field.
119 id_size = lzma_vli_size(options->id);
121 return LZMA_PROG_ERROR;
123 if (prop_size <= 30) {
124 // Size of Filter Properties fits into Misc still.
127 // The Size of Filter Properties field is used too.
128 prop_size_size = lzma_vli_size(prop_size);
129 if (prop_size_size == 0)
130 return LZMA_PROG_ERROR;
134 // 1 is for the Misc field.
135 *size = 1 + id_size + prop_size_size + prop_size;
141 #ifdef HAVE_FILTER_SIMPLE
142 /// Encodes Filter Properties of the so called simple filters
144 properties_simple(uint8_t *out, size_t *out_pos, size_t out_size,
145 const lzma_options_simple *options)
147 if (options == NULL || options->start_offset == 0)
150 if (out_size - *out_pos < 4)
151 return LZMA_BUF_ERROR;
153 for (size_t i = 0; i < 4; ++i)
154 out[(*out_pos)++] = options->start_offset >> (i * 8);
161 #ifdef HAVE_FILTER_DELTA
162 /// Encodes Filter Properties of the Delta filter
164 properties_delta(uint8_t *out, size_t *out_pos, size_t out_size,
165 const lzma_options_delta *options)
168 return LZMA_PROG_ERROR;
170 // It's possible that newer liblzma versions will support larger
172 if (options->distance < LZMA_DELTA_DISTANCE_MIN
173 || options->distance > LZMA_DELTA_DISTANCE_MAX)
174 return LZMA_HEADER_ERROR;
176 if (out_size - *out_pos < 1)
177 return LZMA_BUF_ERROR;
179 out[*out_pos] = options->distance - LZMA_DELTA_DISTANCE_MIN;
187 #ifdef HAVE_FILTER_LZMA
188 /// Encodes LZMA Properties and Dictionary Flags (two bytes)
190 properties_lzma(uint8_t *out, size_t *out_pos, size_t out_size,
191 const lzma_options_lzma *options)
194 return LZMA_PROG_ERROR;
196 if (out_size - *out_pos < 2)
197 return LZMA_BUF_ERROR;
200 if (lzma_lzma_encode_properties(options, out + *out_pos))
201 return LZMA_HEADER_ERROR;
207 // Dictionary size is encoded using six bits of
208 // which one is mantissa and five are exponent.
210 // There are some limits that must hold to keep
211 // this coding working.
212 # if LZMA_DICTIONARY_SIZE_MAX > UINT32_MAX / 2
213 # error LZMA_DICTIONARY_SIZE_MAX is too big.
215 # if LZMA_DICTIONARY_SIZE_MIN < 1
216 # error LZMA_DICTIONARY_SIZE_MIN cannot be zero.
220 if (options->dictionary_size < LZMA_DICTIONARY_SIZE_MIN
221 || options->dictionary_size > LZMA_DICTIONARY_SIZE_MAX)
222 return LZMA_HEADER_ERROR;
224 if (options->dictionary_size == 1) {
226 out[*out_pos] = 0x00;
228 // TODO This could be more elegant.
230 while (((2 | ((i + 1) & 1)) << ((i - 1) / 2))
231 < options->dictionary_size)
243 extern LZMA_API lzma_ret
244 lzma_filter_flags_encode(uint8_t *out, size_t *out_pos, size_t out_size,
245 const lzma_options_filter *options)
247 // Minimum output is one byte (everything fits into Misc).
248 // The caller should have checked that there is enough output space,
249 // so we return LZMA_PROG_ERROR instead of LZMA_BUF_ERROR.
250 if (*out_pos >= out_size)
251 return LZMA_PROG_ERROR;
253 // Get size of Filter Properties.
255 lzma_ret ret = get_properties_size(&prop_size, options);
259 // Misc, External ID, and Size of Properties
260 if (options->id < 0xE0
261 && (lzma_vli)(prop_size) == options->id / 0x20) {
262 // ID and Size of Filter Properties fit into Misc.
263 out[*out_pos] = options->id;
266 } else if (prop_size <= 30) {
267 // Size of Filter Properties fits into Misc.
268 out[*out_pos] = prop_size + 0xE0;
271 // External ID is used to encode the Filter ID. If encoding
272 // the VLI fails, it's because the caller has given as too
273 // little output space, which it should have checked already.
274 // So return LZMA_PROG_ERROR, not LZMA_BUF_ERROR.
276 if (lzma_vli_encode(options->id, &dummy, 1,
277 out, out_pos, out_size) != LZMA_STREAM_END)
278 return LZMA_PROG_ERROR;
281 // Nothing fits into Misc.
282 out[*out_pos] = 0xFF;
285 // External ID is used to encode the Filter ID.
287 if (lzma_vli_encode(options->id, &dummy, 1,
288 out, out_pos, out_size) != LZMA_STREAM_END)
289 return LZMA_PROG_ERROR;
291 // External Size of Filter Properties
293 if (lzma_vli_encode(prop_size, &dummy, 1,
294 out, out_pos, out_size) != LZMA_STREAM_END)
295 return LZMA_PROG_ERROR;
299 switch (options->id) {
300 #ifdef HAVE_FILTER_COPY
301 case LZMA_FILTER_COPY:
302 assert(prop_size == 0);
303 ret = options->options == NULL ? LZMA_OK : LZMA_HEADER_ERROR;
307 #ifdef HAVE_FILTER_SUBBLOCK
308 case LZMA_FILTER_SUBBLOCK:
309 assert(prop_size == 0);
314 #ifdef HAVE_FILTER_SIMPLE
315 # ifdef HAVE_FILTER_X86
316 case LZMA_FILTER_X86:
318 # ifdef HAVE_FILTER_POWERPC
319 case LZMA_FILTER_POWERPC:
321 # ifdef HAVE_FILTER_IA64
322 case LZMA_FILTER_IA64:
324 # ifdef HAVE_FILTER_ARM
325 case LZMA_FILTER_ARM:
327 # ifdef HAVE_FILTER_ARMTHUMB
328 case LZMA_FILTER_ARMTHUMB:
330 # ifdef HAVE_FILTER_SPARC
331 case LZMA_FILTER_SPARC:
333 ret = properties_simple(out, out_pos, out_size,
338 #ifdef HAVE_FILTER_DELTA
339 case LZMA_FILTER_DELTA:
340 ret = properties_delta(out, out_pos, out_size,
345 #ifdef HAVE_FILTER_LZMA
346 case LZMA_FILTER_LZMA:
347 ret = properties_lzma(out, out_pos, out_size,
354 ret = LZMA_PROG_ERROR;