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 .id
= LZMA_FILTER_LZMA1EXT
,
47 .options_size
= sizeof(lzma_options_lzma
),
53 #if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
55 .id
= LZMA_FILTER_LZMA2
,
56 .options_size
= sizeof(lzma_options_lzma
),
62 #if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
64 .id
= LZMA_FILTER_X86
,
65 .options_size
= sizeof(lzma_options_bcj
),
68 .changes_size
= false,
71 #if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
73 .id
= LZMA_FILTER_POWERPC
,
74 .options_size
= sizeof(lzma_options_bcj
),
77 .changes_size
= false,
80 #if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
82 .id
= LZMA_FILTER_IA64
,
83 .options_size
= sizeof(lzma_options_bcj
),
86 .changes_size
= false,
89 #if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
91 .id
= LZMA_FILTER_ARM
,
92 .options_size
= sizeof(lzma_options_bcj
),
95 .changes_size
= false,
98 #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
100 .id
= LZMA_FILTER_ARMTHUMB
,
101 .options_size
= sizeof(lzma_options_bcj
),
104 .changes_size
= false,
107 #if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
109 .id
= LZMA_FILTER_ARM64
,
110 .options_size
= sizeof(lzma_options_bcj
),
113 .changes_size
= false,
116 #if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
118 .id
= LZMA_FILTER_SPARC
,
119 .options_size
= sizeof(lzma_options_bcj
),
122 .changes_size
= false,
125 #if defined(HAVE_ENCODER_RISCV) || defined(HAVE_DECODER_RISCV)
127 .id
= LZMA_FILTER_RISCV
,
128 .options_size
= sizeof(lzma_options_bcj
),
131 .changes_size
= false,
134 #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
136 .id
= LZMA_FILTER_DELTA
,
137 .options_size
= sizeof(lzma_options_delta
),
140 .changes_size
= false,
144 .id
= LZMA_VLI_UNKNOWN
149 extern LZMA_API(lzma_ret
)
150 lzma_filters_copy(const lzma_filter
*src
, lzma_filter
*real_dest
,
151 const lzma_allocator
*allocator
)
153 if (src
== NULL
|| real_dest
== NULL
)
154 return LZMA_PROG_ERROR
;
156 // Use a temporary destination so that the real destination
157 // will never be modied if an error occurs.
158 lzma_filter dest
[LZMA_FILTERS_MAX
+ 1];
162 for (i
= 0; src
[i
].id
!= LZMA_VLI_UNKNOWN
; ++i
) {
163 // There must be a maximum of four filters plus
164 // the array terminator.
165 if (i
== LZMA_FILTERS_MAX
) {
166 ret
= LZMA_OPTIONS_ERROR
;
170 dest
[i
].id
= src
[i
].id
;
172 if (src
[i
].options
== NULL
) {
173 dest
[i
].options
= NULL
;
175 // See if the filter is supported only when the
176 // options is not NULL. This might be convenient
177 // sometimes if the app is actually copying only
178 // a partial filter chain with a place holder ID.
180 // When options is not NULL, the Filter ID must be
181 // supported by us, because otherwise we don't know
182 // how big the options are.
184 for (j
= 0; src
[i
].id
!= features
[j
].id
; ++j
) {
185 if (features
[j
].id
== LZMA_VLI_UNKNOWN
) {
186 ret
= LZMA_OPTIONS_ERROR
;
191 // Allocate and copy the options.
192 dest
[i
].options
= lzma_alloc(features
[j
].options_size
,
194 if (dest
[i
].options
== NULL
) {
195 ret
= LZMA_MEM_ERROR
;
199 memcpy(dest
[i
].options
, src
[i
].options
,
200 features
[j
].options_size
);
204 // Terminate the filter array.
205 assert(i
< LZMA_FILTERS_MAX
+ 1);
206 dest
[i
].id
= LZMA_VLI_UNKNOWN
;
207 dest
[i
].options
= NULL
;
209 // Copy it to the caller-supplied array now that we know that
210 // no errors occurred.
211 memcpy(real_dest
, dest
, (i
+ 1) * sizeof(lzma_filter
));
216 // Free the options which we have already allocated.
218 lzma_free(dest
[i
].options
, allocator
);
224 extern LZMA_API(void)
225 lzma_filters_free(lzma_filter
*filters
, const lzma_allocator
*allocator
)
230 for (size_t i
= 0; filters
[i
].id
!= LZMA_VLI_UNKNOWN
; ++i
) {
231 if (i
== LZMA_FILTERS_MAX
) {
232 // The API says that LZMA_FILTERS_MAX + 1 is the
233 // maximum allowed size including the terminating
234 // element. Thus, we should never get here but in
235 // case there is a bug and we do anyway, don't go
236 // past the (probable) end of the array.
241 lzma_free(filters
[i
].options
, allocator
);
242 filters
[i
].options
= NULL
;
243 filters
[i
].id
= LZMA_VLI_UNKNOWN
;
251 lzma_validate_chain(const lzma_filter
*filters
, size_t *count
)
253 // There must be at least one filter.
254 if (filters
== NULL
|| filters
[0].id
== LZMA_VLI_UNKNOWN
)
255 return LZMA_PROG_ERROR
;
257 // Number of non-last filters that may change the size of the data
258 // significantly (that is, more than 1-2 % or so).
259 size_t changes_size_count
= 0;
261 // True if it is OK to add a new filter after the current filter.
262 bool non_last_ok
= true;
264 // True if the last filter in the given chain is actually usable as
265 // the last filter. Only filters that support embedding End of Payload
266 // Marker can be used as the last filter in the chain.
267 bool last_ok
= false;
272 for (j
= 0; filters
[i
].id
!= features
[j
].id
; ++j
)
273 if (features
[j
].id
== LZMA_VLI_UNKNOWN
)
274 return LZMA_OPTIONS_ERROR
;
276 // If the previous filter in the chain cannot be a non-last
277 // filter, the chain is invalid.
279 return LZMA_OPTIONS_ERROR
;
281 non_last_ok
= features
[j
].non_last_ok
;
282 last_ok
= features
[j
].last_ok
;
283 changes_size_count
+= features
[j
].changes_size
;
285 } while (filters
[++i
].id
!= LZMA_VLI_UNKNOWN
);
287 // There must be 1-4 filters. The last filter must be usable as
288 // the last filter in the chain. A maximum of three filters are
289 // allowed to change the size of the data.
290 if (i
> LZMA_FILTERS_MAX
|| !last_ok
|| changes_size_count
> 3)
291 return LZMA_OPTIONS_ERROR
;
299 lzma_raw_coder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
300 const lzma_filter
*options
,
301 lzma_filter_find coder_find
, bool is_encoder
)
303 // Do some basic validation and get the number of filters.
305 return_if_error(lzma_validate_chain(options
, &count
));
307 // Set the filter functions and copy the options pointer.
308 lzma_filter_info filters
[LZMA_FILTERS_MAX
+ 1];
310 for (size_t i
= 0; i
< count
; ++i
) {
311 // The order of the filters is reversed in the
312 // encoder. It allows more efficient handling
313 // of the uncompressed data.
314 const size_t j
= count
- i
- 1;
316 const lzma_filter_coder
*const fc
317 = coder_find(options
[i
].id
);
318 if (fc
== NULL
|| fc
->init
== NULL
)
319 return LZMA_OPTIONS_ERROR
;
321 filters
[j
].id
= options
[i
].id
;
322 filters
[j
].init
= fc
->init
;
323 filters
[j
].options
= options
[i
].options
;
326 for (size_t i
= 0; i
< count
; ++i
) {
327 const lzma_filter_coder
*const fc
328 = coder_find(options
[i
].id
);
329 if (fc
== NULL
|| fc
->init
== NULL
)
330 return LZMA_OPTIONS_ERROR
;
332 filters
[i
].id
= options
[i
].id
;
333 filters
[i
].init
= fc
->init
;
334 filters
[i
].options
= options
[i
].options
;
338 // Terminate the array.
339 filters
[count
].id
= LZMA_VLI_UNKNOWN
;
340 filters
[count
].init
= NULL
;
342 // Initialize the filters.
343 const lzma_ret ret
= lzma_next_filter_init(next
, allocator
, filters
);
345 lzma_next_end(next
, allocator
);
352 lzma_raw_coder_memusage(lzma_filter_find coder_find
,
353 const lzma_filter
*filters
)
355 // The chain has to have at least one filter.
358 if (lzma_validate_chain(filters
, &tmp
) != LZMA_OK
)
366 const lzma_filter_coder
*const fc
367 = coder_find(filters
[i
].id
);
369 return UINT64_MAX
; // Unsupported Filter ID
371 if (fc
->memusage
== NULL
) {
372 // This filter doesn't have a function to calculate
373 // the memory usage and validate the options. Such
374 // filters need only little memory, so we use 1 KiB
375 // as a good estimate. They also accept all possible
376 // options, so there's no need to worry about lack
380 // Call the filter-specific memory usage calculation
383 = fc
->memusage(filters
[i
].options
);
384 if (usage
== UINT64_MAX
)
385 return UINT64_MAX
; // Invalid options
389 } while (filters
[++i
].id
!= LZMA_VLI_UNKNOWN
);
391 // Add some fixed amount of extra. It's to compensate memory usage
392 // of Stream, Block etc. coders, malloc() overhead, stack etc.
393 return total
+ LZMA_MEMUSAGE_BASE
;