1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file filter_common.c
4 /// \brief Filter-specific stuff common for both encoder and decoder
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
13 #include "filter_common.h"
20 /// Size of the filter-specific options structure
23 /// True if it is OK to use this filter as non-last filter in
27 /// True if it is OK to use this filter as the last filter in
31 /// True if the filter may change the size of the data (that is, the
32 /// amount of encoded output can be different than the amount of
33 /// uncompressed input).
37 #if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
39 .id = LZMA_FILTER_LZMA1,
40 .options_size = sizeof(lzma_options_lzma),
46 #ifdef HAVE_DECODER_LZMA2
48 .id = LZMA_FILTER_LZMA2,
49 .options_size = sizeof(lzma_options_lzma),
55 #if defined(HAVE_ENCODER_SUBBLOCK) || defined(HAVE_DECODER_SUBBLOCK)
57 .id = LZMA_FILTER_SUBBLOCK,
58 .options_size = sizeof(lzma_options_subblock),
64 #ifdef HAVE_DECODER_X86
66 .id = LZMA_FILTER_X86,
67 .options_size = sizeof(lzma_options_bcj),
70 .changes_size = false,
73 #if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
75 .id = LZMA_FILTER_POWERPC,
76 .options_size = sizeof(lzma_options_bcj),
79 .changes_size = false,
82 #ifdef HAVE_DECODER_IA64
84 .id = LZMA_FILTER_IA64,
85 .options_size = sizeof(lzma_options_bcj),
88 .changes_size = false,
91 #if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
93 .id = LZMA_FILTER_ARM,
94 .options_size = sizeof(lzma_options_bcj),
97 .changes_size = false,
100 #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
102 .id = LZMA_FILTER_ARMTHUMB,
103 .options_size = sizeof(lzma_options_bcj),
106 .changes_size = false,
109 #if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
111 .id = LZMA_FILTER_SPARC,
112 .options_size = sizeof(lzma_options_bcj),
115 .changes_size = false,
118 #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
120 .id = LZMA_FILTER_DELTA,
121 .options_size = sizeof(lzma_options_delta),
124 .changes_size = false,
128 .id = LZMA_VLI_UNKNOWN
133 extern LZMA_API(lzma_ret)
134 lzma_filters_dup(const lzma_filter *src, lzma_filter *dest,
135 lzma_allocator *allocator)
137 if (src == NULL || dest == NULL)
138 return LZMA_PROG_ERROR;
142 for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
143 // There must be a maximum of four filters plus
144 // the array terminator.
145 if (i == LZMA_FILTERS_MAX) {
146 ret = LZMA_OPTIONS_ERROR;
150 dest[i].id = src[i].id;
152 if (src[i].options == NULL) {
153 dest[i].options = NULL;
155 // See if the filter is supported only when the
156 // options is not NULL. This might be convenient
157 // sometimes if the app is actually copying only
158 // a partial filter chain with a place holder ID.
160 // When options is not NULL, the Filter ID must be
161 // supported by us, because otherwise we don't know
162 // how big the options are.
164 for (j = 0; src[i].id != features[j].id; ++j) {
165 if (features[j].id == LZMA_VLI_UNKNOWN) {
166 ret = LZMA_OPTIONS_ERROR;
171 // Allocate and copy the options.
172 dest[i].options = lzma_alloc(features[j].options_size,
174 if (dest[i].options == NULL) {
175 ret = LZMA_MEM_ERROR;
179 memcpy(dest[i].options, src[i].options,
180 features[j].options_size);
184 // Terminate the filter array.
185 assert(i <= LZMA_FILTERS_MAX + 1);
186 dest[i].id = LZMA_VLI_UNKNOWN;
187 dest[i].options = NULL;
192 // Free the options which we have already allocated.
194 lzma_free(dest[i].options, allocator);
195 dest[i].options = NULL;
203 validate_chain(const lzma_filter *filters, size_t *count)
205 // There must be at least one filter.
206 if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
207 return LZMA_PROG_ERROR;
209 // Number of non-last filters that may change the size of the data
210 // significantly (that is, more than 1-2 % or so).
211 size_t changes_size_count = 0;
213 // True if it is OK to add a new filter after the current filter.
214 bool non_last_ok = true;
216 // True if the last filter in the given chain is actually usable as
217 // the last filter. Only filters that support embedding End of Payload
218 // Marker can be used as the last filter in the chain.
219 bool last_ok = false;
224 for (j = 0; filters[i].id != features[j].id; ++j)
225 if (features[j].id == LZMA_VLI_UNKNOWN)
226 return LZMA_OPTIONS_ERROR;
228 // If the previous filter in the chain cannot be a non-last
229 // filter, the chain is invalid.
231 return LZMA_OPTIONS_ERROR;
233 non_last_ok = features[j].non_last_ok;
234 last_ok = features[j].last_ok;
235 changes_size_count += features[j].changes_size;
237 } while (filters[++i].id != LZMA_VLI_UNKNOWN);
239 // There must be 1-4 filters. The last filter must be usable as
240 // the last filter in the chain. A maximum of three filters are
241 // allowed to change the size of the data.
242 if (i > LZMA_FILTERS_MAX || !last_ok || changes_size_count > 3)
243 return LZMA_OPTIONS_ERROR;
251 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
252 const lzma_filter *options,
253 lzma_filter_find coder_find, bool is_encoder)
255 // Do some basic validation and get the number of filters.
257 return_if_error(validate_chain(options, &count));
259 // Set the filter functions and copy the options pointer.
260 lzma_filter_info filters[LZMA_FILTERS_MAX + 1];
262 for (size_t i = 0; i < count; ++i) {
263 // The order of the filters is reversed in the
264 // encoder. It allows more efficient handling
265 // of the uncompressed data.
266 const size_t j = count - i - 1;
268 const lzma_filter_coder *const fc
269 = coder_find(options[i].id);
270 if (fc == NULL || fc->init == NULL)
271 return LZMA_OPTIONS_ERROR;
273 filters[j].init = fc->init;
274 filters[j].options = options[i].options;
277 for (size_t i = 0; i < count; ++i) {
278 const lzma_filter_coder *const fc
279 = coder_find(options[i].id);
280 if (fc == NULL || fc->init == NULL)
281 return LZMA_OPTIONS_ERROR;
283 filters[i].init = fc->init;
284 filters[i].options = options[i].options;
288 // Terminate the array.
289 filters[count].init = NULL;
291 // Initialize the filters.
292 const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
294 lzma_next_end(next, allocator);
301 lzma_raw_coder_memusage(lzma_filter_find coder_find,
302 const lzma_filter *filters)
304 // The chain has to have at least one filter.
307 if (validate_chain(filters, &tmp) != LZMA_OK)
315 const lzma_filter_coder *const fc
316 = coder_find(filters[i].id);
318 return UINT64_MAX; // Unsupported Filter ID
320 if (fc->memusage == NULL) {
321 // This filter doesn't have a function to calculate
322 // the memory usage and validate the options. Such
323 // filters need only little memory, so we use 1 KiB
324 // as a good estimate. They also accept all possible
325 // options, so there's no need to worry about lack
329 // Call the filter-specific memory usage calculation
332 = fc->memusage(filters[i].options);
333 if (usage == UINT64_MAX)
334 return UINT64_MAX; // Invalid options
338 } while (filters[++i].id != LZMA_VLI_UNKNOWN);
340 // Add some fixed amount of extra. It's to compensate memory usage
341 // of Stream, Block etc. coders, malloc() overhead, stack etc.
342 return total + LZMA_MEMUSAGE_BASE;