1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file filter_common.c
4 /// \brief Filter-specific stuff common for both encoder and decoder
6 // Copyright (C) 2008 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 ///////////////////////////////////////////////////////////////////////////////
20 #include "filter_common.h"
27 /// True if it is OK to use this filter as non-last filter in
31 /// True if it is OK to use this filter as the last filter in
35 /// True if the filter may change the size of the data (that is, the
36 /// amount of encoded output can be different than the amount of
37 /// uncompressed input).
41 #if defined (HAVE_ENCODER_LZMA) || defined(HAVE_DECODER_LZMA)
43 .id = LZMA_FILTER_LZMA,
49 #ifdef HAVE_DECODER_LZMA2
51 .id = LZMA_FILTER_LZMA2,
57 #if defined(HAVE_ENCODER_SUBBLOCK) || defined(HAVE_DECODER_SUBBLOCK)
59 .id = LZMA_FILTER_SUBBLOCK,
65 #ifdef HAVE_DECODER_X86
67 .id = LZMA_FILTER_X86,
70 .changes_size = false,
73 #if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
75 .id = LZMA_FILTER_POWERPC,
78 .changes_size = false,
81 #ifdef HAVE_DECODER_IA64
83 .id = LZMA_FILTER_IA64,
86 .changes_size = false,
89 #if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
91 .id = LZMA_FILTER_ARM,
94 .changes_size = false,
97 #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
99 .id = LZMA_FILTER_ARMTHUMB,
102 .changes_size = false,
105 #if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
107 .id = LZMA_FILTER_SPARC,
110 .changes_size = false,
113 #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
115 .id = LZMA_FILTER_DELTA,
118 .changes_size = false,
122 .id = LZMA_VLI_UNKNOWN
128 validate_chain(const lzma_filter *filters, size_t *count)
130 // There must be at least one filter.
131 if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
132 return LZMA_PROG_ERROR;
134 // Number of non-last filters that may change the size of the data
135 // significantly (that is, more than 1-2 % or so).
136 size_t changes_size_count = 0;
138 // True if it is OK to add a new filter after the current filter.
139 bool non_last_ok = true;
141 // True if the last filter in the given chain is actually usable as
142 // the last filter. Only filters that support embedding End of Payload
143 // Marker can be used as the last filter in the chain.
144 bool last_ok = false;
149 for (j = 0; filters[i].id != features[j].id; ++j)
150 if (features[j].id == LZMA_VLI_UNKNOWN)
151 return LZMA_OPTIONS_ERROR;
153 // If the previous filter in the chain cannot be a non-last
154 // filter, the chain is invalid.
156 return LZMA_OPTIONS_ERROR;
158 non_last_ok = features[j].non_last_ok;
159 last_ok = features[j].last_ok;
160 changes_size_count += features[j].changes_size;
162 } while (filters[++i].id != LZMA_VLI_UNKNOWN);
164 // There must be 1-4 filters. The last filter must be usable as
165 // the last filter in the chain. At maximum of three filters are
166 // allowed to change the size of the data.
167 if (i > LZMA_BLOCK_FILTERS_MAX || !last_ok || changes_size_count > 3)
168 return LZMA_OPTIONS_ERROR;
176 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
177 const lzma_filter *options,
178 lzma_filter_find coder_find, bool is_encoder)
180 // Do some basic validation and get the number of filters.
182 return_if_error(validate_chain(options, &count));
184 // Set the filter functions and copy the options pointer.
185 lzma_filter_info filters[LZMA_BLOCK_FILTERS_MAX + 1];
187 for (size_t i = 0; i < count; ++i) {
188 // The order of the filters is reversed in the
189 // encoder. It allows more efficient handling
190 // of the uncompressed data.
191 const size_t j = count - i - 1;
193 const lzma_filter_coder *const fc
194 = coder_find(options[i].id);
195 if (fc == NULL || fc->init == NULL)
196 return LZMA_OPTIONS_ERROR;
198 filters[j].init = fc->init;
199 filters[j].options = options[i].options;
202 for (size_t i = 0; i < count; ++i) {
203 const lzma_filter_coder *const fc
204 = coder_find(options[i].id);
205 if (fc == NULL || fc->init == NULL)
206 return LZMA_OPTIONS_ERROR;
208 filters[i].init = fc->init;
209 filters[i].options = options[i].options;
213 // Terminate the array.
214 filters[count].init = NULL;
216 // Initialize the filters.
217 const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
219 lzma_next_end(next, allocator);
226 lzma_memusage_coder(lzma_filter_find coder_find,
227 const lzma_filter *filters)
229 // The chain has to have at least one filter.
230 if (filters[0].id == LZMA_VLI_UNKNOWN)
237 const lzma_filter_coder *const fc
238 = coder_find(filters[i].id);
240 return UINT64_MAX; // Unsupported Filter ID
242 if (fc->memusage == NULL) {
243 // This filter doesn't have a function to calculate
244 // the memory usage. Such filters need only little
245 // memory, so we use 1 KiB as a good estimate.
248 // Call the filter-specific memory usage calculation
251 = fc->memusage(filters[i].options);
252 if (usage == UINT64_MAX)
253 return UINT64_MAX; // Invalid options
257 } while (filters[++i].id != LZMA_VLI_UNKNOWN);
259 // Add some fixed amount of extra. It's to compensate memory usage
260 // of Stream, Block etc. coders, malloc() overhead, stack etc.
261 return total + (1U << 15);