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"
25 /// \brief Calculates the size of the Filter Properties field
27 /// This currently can return only LZMA_OK or LZMA_HEADER_ERROR, but
28 /// with some new filters it may return also LZMA_PROG_ERROR.
30 get_properties_size(uint32_t *size, const lzma_options_filter *options)
32 lzma_ret ret = LZMA_OK;
34 switch (options->id) {
35 #ifdef HAVE_FILTER_COPY
36 case LZMA_FILTER_COPY:
41 #ifdef HAVE_FILTER_SUBBLOCK
42 case LZMA_FILTER_SUBBLOCK:
47 #ifdef HAVE_FILTER_SIMPLE
48 # ifdef HAVE_FILTER_X86
51 # ifdef HAVE_FILTER_POWERPC
52 case LZMA_FILTER_POWERPC:
54 # ifdef HAVE_FILTER_IA64
55 case LZMA_FILTER_IA64:
57 # ifdef HAVE_FILTER_ARM
60 # ifdef HAVE_FILTER_ARMTHUMB
61 case LZMA_FILTER_ARMTHUMB:
63 # ifdef HAVE_FILTER_SPARC
64 case LZMA_FILTER_SPARC:
66 if (options->options == NULL || ((const lzma_options_simple *)(
67 options->options))->start_offset == 0)
74 #ifdef HAVE_FILTER_DELTA
75 case LZMA_FILTER_DELTA:
80 #ifdef HAVE_FILTER_LZMA
81 case LZMA_FILTER_LZMA:
87 // Unknown filter - if the Filter ID is a proper VLI,
88 // return LZMA_HEADER_ERROR instead of LZMA_PROG_ERROR,
89 // because it's possible that we just don't have support
90 // compiled in for the requested filter.
91 ret = options->id <= LZMA_VLI_VALUE_MAX
92 ? LZMA_HEADER_ERROR : LZMA_PROG_ERROR;
100 extern LZMA_API lzma_ret
101 lzma_filter_flags_size(uint32_t *size, const lzma_options_filter *options)
103 // Get size of Filter Properties.
105 const lzma_ret ret = get_properties_size(&prop_size, options);
109 // Size of Filter ID field if it exists.
111 size_t prop_size_size;
112 if (options->id < 0xE0
113 && (lzma_vli)(prop_size) == options->id / 0x20) {
114 // ID and Size of Filter Properties fit into Misc.
119 // At least Filter ID is stored using the External ID field.
120 id_size = lzma_vli_size(options->id);
122 return LZMA_PROG_ERROR;
124 if (prop_size <= 30) {
125 // Size of Filter Properties fits into Misc still.
128 // The Size of Filter Properties field is used too.
129 prop_size_size = lzma_vli_size(prop_size);
130 if (prop_size_size == 0)
131 return LZMA_PROG_ERROR;
135 // 1 is for the Misc field.
136 *size = 1 + id_size + prop_size_size + prop_size;
142 #ifdef HAVE_FILTER_SIMPLE
143 /// Encodes Filter Properties of the so called simple filters
145 properties_simple(uint8_t *out, size_t *out_pos, size_t out_size,
146 const lzma_options_simple *options)
148 if (options == NULL || options->start_offset == 0)
151 if (out_size - *out_pos < 4)
152 return LZMA_BUF_ERROR;
154 for (size_t i = 0; i < 4; ++i)
155 out[(*out_pos)++] = options->start_offset >> (i * 8);
162 #ifdef HAVE_FILTER_DELTA
163 /// Encodes Filter Properties of the Delta filter
165 properties_delta(uint8_t *out, size_t *out_pos, size_t out_size,
166 const lzma_options_delta *options)
169 return LZMA_PROG_ERROR;
171 // It's possible that newer liblzma versions will support larger
173 if (options->distance < LZMA_DELTA_DISTANCE_MIN
174 || options->distance > LZMA_DELTA_DISTANCE_MAX)
175 return LZMA_HEADER_ERROR;
177 if (out_size - *out_pos < 1)
178 return LZMA_BUF_ERROR;
180 out[*out_pos] = options->distance - LZMA_DELTA_DISTANCE_MIN;
188 #ifdef HAVE_FILTER_LZMA
189 /// Encodes LZMA Properties and Dictionary Flags (two bytes)
191 properties_lzma(uint8_t *out, size_t *out_pos, size_t out_size,
192 const lzma_options_lzma *options)
195 return LZMA_PROG_ERROR;
197 if (out_size - *out_pos < 2)
198 return LZMA_BUF_ERROR;
201 if (lzma_lzma_encode_properties(options, out + *out_pos))
202 return LZMA_HEADER_ERROR;
208 // Dictionary size is encoded using similar encoding that is used
209 // internally by LZMA.
211 // This won't work if dictionary size can be zero:
212 # if LZMA_DICTIONARY_SIZE_MIN < 1
213 # error LZMA_DICTIONARY_SIZE_MIN cannot be zero.
216 uint32_t d = options->dictionary_size;
219 if (d < LZMA_DICTIONARY_SIZE_MIN || d > LZMA_DICTIONARY_SIZE_MAX)
220 return LZMA_HEADER_ERROR;
222 // Round up to to the next 2^n or 2^n + 2^(n - 1) depending on which
232 // Get the highest two bits using the proper encoding:
233 out[*out_pos] = get_pos_slot(d) - 1;
241 extern LZMA_API lzma_ret
242 lzma_filter_flags_encode(uint8_t *out, size_t *out_pos, size_t out_size,
243 const lzma_options_filter *options)
245 // Minimum output is one byte (everything fits into Misc).
246 // The caller should have checked that there is enough output space,
247 // so we return LZMA_PROG_ERROR instead of LZMA_BUF_ERROR.
248 if (*out_pos >= out_size)
249 return LZMA_PROG_ERROR;
251 // Get size of Filter Properties.
253 lzma_ret ret = get_properties_size(&prop_size, options);
257 // Misc, External ID, and Size of Properties
258 if (options->id < 0xE0
259 && (lzma_vli)(prop_size) == options->id / 0x20) {
260 // ID and Size of Filter Properties fit into Misc.
261 out[*out_pos] = options->id;
264 } else if (prop_size <= 30) {
265 // Size of Filter Properties fits into Misc.
266 out[*out_pos] = prop_size + 0xE0;
269 // External ID is used to encode the Filter ID. If encoding
270 // the VLI fails, it's because the caller has given as too
271 // little output space, which it should have checked already.
272 // So return LZMA_PROG_ERROR, not LZMA_BUF_ERROR.
274 if (lzma_vli_encode(options->id, &dummy, 1,
275 out, out_pos, out_size) != LZMA_STREAM_END)
276 return LZMA_PROG_ERROR;
279 // Nothing fits into Misc.
280 out[*out_pos] = 0xFF;
283 // External ID is used to encode the Filter ID.
285 if (lzma_vli_encode(options->id, &dummy, 1,
286 out, out_pos, out_size) != LZMA_STREAM_END)
287 return LZMA_PROG_ERROR;
289 // External Size of Filter Properties
291 if (lzma_vli_encode(prop_size, &dummy, 1,
292 out, out_pos, out_size) != LZMA_STREAM_END)
293 return LZMA_PROG_ERROR;
297 switch (options->id) {
298 #ifdef HAVE_FILTER_COPY
299 case LZMA_FILTER_COPY:
300 assert(prop_size == 0);
301 ret = options->options == NULL ? LZMA_OK : LZMA_HEADER_ERROR;
305 #ifdef HAVE_FILTER_SUBBLOCK
306 case LZMA_FILTER_SUBBLOCK:
307 assert(prop_size == 0);
312 #ifdef HAVE_FILTER_SIMPLE
313 # ifdef HAVE_FILTER_X86
314 case LZMA_FILTER_X86:
316 # ifdef HAVE_FILTER_POWERPC
317 case LZMA_FILTER_POWERPC:
319 # ifdef HAVE_FILTER_IA64
320 case LZMA_FILTER_IA64:
322 # ifdef HAVE_FILTER_ARM
323 case LZMA_FILTER_ARM:
325 # ifdef HAVE_FILTER_ARMTHUMB
326 case LZMA_FILTER_ARMTHUMB:
328 # ifdef HAVE_FILTER_SPARC
329 case LZMA_FILTER_SPARC:
331 ret = properties_simple(out, out_pos, out_size,
336 #ifdef HAVE_FILTER_DELTA
337 case LZMA_FILTER_DELTA:
338 ret = properties_delta(out, out_pos, out_size,
343 #ifdef HAVE_FILTER_LZMA
344 case LZMA_FILTER_LZMA:
345 ret = properties_lzma(out, out_pos, out_size,
352 ret = LZMA_PROG_ERROR;