1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       filter_decoder.c
4207753Smm/// \brief      Filter ID mapping to filter-specific functions
5207753Smm//
6207753Smm//  Author:     Lasse Collin
7207753Smm//
8207753Smm//  This file has been put into the public domain.
9207753Smm//  You can do whatever you want with this file.
10207753Smm//
11207753Smm///////////////////////////////////////////////////////////////////////////////
12207753Smm
13207753Smm#include "filter_encoder.h"
14207753Smm#include "filter_common.h"
15207753Smm#include "lzma_encoder.h"
16207753Smm#include "lzma2_encoder.h"
17207753Smm#include "simple_encoder.h"
18207753Smm#include "delta_encoder.h"
19207753Smm
20207753Smm
21207753Smmtypedef struct {
22207753Smm	/// Filter ID
23207753Smm	lzma_vli id;
24207753Smm
25207753Smm	/// Initializes the filter encoder and calls lzma_next_filter_init()
26207753Smm	/// for filters + 1.
27207753Smm	lzma_init_function init;
28207753Smm
29207753Smm	/// Calculates memory usage of the encoder. If the options are
30207753Smm	/// invalid, UINT64_MAX is returned.
31207753Smm	uint64_t (*memusage)(const void *options);
32207753Smm
33292588Sdelphij	/// Calculates the recommended Uncompressed Size for .xz Blocks to
34292588Sdelphij	/// which the input data can be split to make multithreaded
35292588Sdelphij	/// encoding possible. If this is NULL, it is assumed that
36292588Sdelphij	/// the encoder is fast enough with single thread.
37292588Sdelphij	uint64_t (*block_size)(const void *options);
38207753Smm
39207753Smm	/// Tells the size of the Filter Properties field. If options are
40207753Smm	/// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed
41207753Smm	/// is used.
42207753Smm	lzma_ret (*props_size_get)(uint32_t *size, const void *options);
43207753Smm	uint32_t props_size_fixed;
44207753Smm
45207753Smm	/// Encodes Filter Properties.
46207753Smm	///
47207753Smm	/// \return     - LZMA_OK: Properties encoded successfully.
48207753Smm	///             - LZMA_OPTIONS_ERROR: Unsupported options
49207753Smm	///             - LZMA_PROG_ERROR: Invalid options or not enough
50207753Smm	///               output space
51207753Smm	lzma_ret (*props_encode)(const void *options, uint8_t *out);
52207753Smm
53207753Smm} lzma_filter_encoder;
54207753Smm
55207753Smm
56207753Smmstatic const lzma_filter_encoder encoders[] = {
57207753Smm#ifdef HAVE_ENCODER_LZMA1
58207753Smm	{
59207753Smm		.id = LZMA_FILTER_LZMA1,
60207753Smm		.init = &lzma_lzma_encoder_init,
61207753Smm		.memusage = &lzma_lzma_encoder_memusage,
62292588Sdelphij		.block_size = NULL, // FIXME
63207753Smm		.props_size_get = NULL,
64207753Smm		.props_size_fixed = 5,
65207753Smm		.props_encode = &lzma_lzma_props_encode,
66207753Smm	},
67207753Smm#endif
68207753Smm#ifdef HAVE_ENCODER_LZMA2
69207753Smm	{
70207753Smm		.id = LZMA_FILTER_LZMA2,
71207753Smm		.init = &lzma_lzma2_encoder_init,
72207753Smm		.memusage = &lzma_lzma2_encoder_memusage,
73292588Sdelphij		.block_size = &lzma_lzma2_block_size, // FIXME
74207753Smm		.props_size_get = NULL,
75207753Smm		.props_size_fixed = 1,
76207753Smm		.props_encode = &lzma_lzma2_props_encode,
77207753Smm	},
78207753Smm#endif
79207753Smm#ifdef HAVE_ENCODER_X86
80207753Smm	{
81207753Smm		.id = LZMA_FILTER_X86,
82207753Smm		.init = &lzma_simple_x86_encoder_init,
83207753Smm		.memusage = NULL,
84292588Sdelphij		.block_size = NULL,
85207753Smm		.props_size_get = &lzma_simple_props_size,
86207753Smm		.props_encode = &lzma_simple_props_encode,
87207753Smm	},
88207753Smm#endif
89207753Smm#ifdef HAVE_ENCODER_POWERPC
90207753Smm	{
91207753Smm		.id = LZMA_FILTER_POWERPC,
92207753Smm		.init = &lzma_simple_powerpc_encoder_init,
93207753Smm		.memusage = NULL,
94292588Sdelphij		.block_size = NULL,
95207753Smm		.props_size_get = &lzma_simple_props_size,
96207753Smm		.props_encode = &lzma_simple_props_encode,
97207753Smm	},
98207753Smm#endif
99207753Smm#ifdef HAVE_ENCODER_IA64
100207753Smm	{
101207753Smm		.id = LZMA_FILTER_IA64,
102207753Smm		.init = &lzma_simple_ia64_encoder_init,
103207753Smm		.memusage = NULL,
104292588Sdelphij		.block_size = NULL,
105207753Smm		.props_size_get = &lzma_simple_props_size,
106207753Smm		.props_encode = &lzma_simple_props_encode,
107207753Smm	},
108207753Smm#endif
109207753Smm#ifdef HAVE_ENCODER_ARM
110207753Smm	{
111207753Smm		.id = LZMA_FILTER_ARM,
112207753Smm		.init = &lzma_simple_arm_encoder_init,
113207753Smm		.memusage = NULL,
114292588Sdelphij		.block_size = NULL,
115207753Smm		.props_size_get = &lzma_simple_props_size,
116207753Smm		.props_encode = &lzma_simple_props_encode,
117207753Smm	},
118207753Smm#endif
119207753Smm#ifdef HAVE_ENCODER_ARMTHUMB
120207753Smm	{
121207753Smm		.id = LZMA_FILTER_ARMTHUMB,
122207753Smm		.init = &lzma_simple_armthumb_encoder_init,
123207753Smm		.memusage = NULL,
124292588Sdelphij		.block_size = NULL,
125207753Smm		.props_size_get = &lzma_simple_props_size,
126207753Smm		.props_encode = &lzma_simple_props_encode,
127207753Smm	},
128207753Smm#endif
129207753Smm#ifdef HAVE_ENCODER_SPARC
130207753Smm	{
131207753Smm		.id = LZMA_FILTER_SPARC,
132207753Smm		.init = &lzma_simple_sparc_encoder_init,
133207753Smm		.memusage = NULL,
134292588Sdelphij		.block_size = NULL,
135207753Smm		.props_size_get = &lzma_simple_props_size,
136207753Smm		.props_encode = &lzma_simple_props_encode,
137207753Smm	},
138207753Smm#endif
139207753Smm#ifdef HAVE_ENCODER_DELTA
140207753Smm	{
141207753Smm		.id = LZMA_FILTER_DELTA,
142207753Smm		.init = &lzma_delta_encoder_init,
143207753Smm		.memusage = &lzma_delta_coder_memusage,
144292588Sdelphij		.block_size = NULL,
145207753Smm		.props_size_get = NULL,
146207753Smm		.props_size_fixed = 1,
147207753Smm		.props_encode = &lzma_delta_props_encode,
148207753Smm	},
149207753Smm#endif
150207753Smm};
151207753Smm
152207753Smm
153207753Smmstatic const lzma_filter_encoder *
154207753Smmencoder_find(lzma_vli id)
155207753Smm{
156207753Smm	for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
157207753Smm		if (encoders[i].id == id)
158207753Smm			return encoders + i;
159207753Smm
160207753Smm	return NULL;
161207753Smm}
162207753Smm
163207753Smm
164207753Smmextern LZMA_API(lzma_bool)
165207753Smmlzma_filter_encoder_is_supported(lzma_vli id)
166207753Smm{
167207753Smm	return encoder_find(id) != NULL;
168207753Smm}
169207753Smm
170207753Smm
171207753Smmextern LZMA_API(lzma_ret)
172207753Smmlzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
173207753Smm{
174207753Smm	if (strm->internal->next.update == NULL)
175207753Smm		return LZMA_PROG_ERROR;
176207753Smm
177207753Smm	// Validate the filter chain.
178207753Smm	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
179207753Smm		return LZMA_OPTIONS_ERROR;
180207753Smm
181207753Smm	// The actual filter chain in the encoder is reversed. Some things
182207753Smm	// still want the normal order chain, so we provide both.
183207753Smm	size_t count = 1;
184207753Smm	while (filters[count].id != LZMA_VLI_UNKNOWN)
185207753Smm		++count;
186207753Smm
187207753Smm	lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1];
188207753Smm	for (size_t i = 0; i < count; ++i)
189207753Smm		reversed_filters[count - i - 1] = filters[i];
190207753Smm
191207753Smm	reversed_filters[count].id = LZMA_VLI_UNKNOWN;
192207753Smm
193207753Smm	return strm->internal->next.update(strm->internal->next.coder,
194207753Smm			strm->allocator, filters, reversed_filters);
195207753Smm}
196207753Smm
197207753Smm
198207753Smmextern lzma_ret
199292588Sdelphijlzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
200207753Smm		const lzma_filter *options)
201207753Smm{
202207753Smm	return lzma_raw_coder_init(next, allocator,
203207753Smm			options, (lzma_filter_find)(&encoder_find), true);
204207753Smm}
205207753Smm
206207753Smm
207207753Smmextern LZMA_API(lzma_ret)
208207753Smmlzma_raw_encoder(lzma_stream *strm, const lzma_filter *options)
209207753Smm{
210207753Smm	lzma_next_strm_init(lzma_raw_coder_init, strm, options,
211207753Smm			(lzma_filter_find)(&encoder_find), true);
212207753Smm
213207753Smm	strm->internal->supported_actions[LZMA_RUN] = true;
214207753Smm	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
215207753Smm	strm->internal->supported_actions[LZMA_FINISH] = true;
216207753Smm
217207753Smm	return LZMA_OK;
218207753Smm}
219207753Smm
220207753Smm
221207753Smmextern LZMA_API(uint64_t)
222207753Smmlzma_raw_encoder_memusage(const lzma_filter *filters)
223207753Smm{
224207753Smm	return lzma_raw_coder_memusage(
225207753Smm			(lzma_filter_find)(&encoder_find), filters);
226207753Smm}
227207753Smm
228207753Smm
229292588Sdelphijextern uint64_t
230292588Sdelphijlzma_mt_block_size(const lzma_filter *filters)
231207753Smm{
232292588Sdelphij	uint64_t max = 0;
233207753Smm
234207753Smm	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
235207753Smm		const lzma_filter_encoder *const fe
236207753Smm				= encoder_find(filters[i].id);
237292588Sdelphij		if (fe->block_size != NULL) {
238292588Sdelphij			const uint64_t size
239292588Sdelphij					= fe->block_size(filters[i].options);
240292588Sdelphij			if (size == 0)
241292588Sdelphij				return 0;
242207753Smm
243207753Smm			if (size > max)
244207753Smm				max = size;
245207753Smm		}
246207753Smm	}
247207753Smm
248207753Smm	return max;
249207753Smm}
250207753Smm
251207753Smm
252207753Smmextern LZMA_API(lzma_ret)
253207753Smmlzma_properties_size(uint32_t *size, const lzma_filter *filter)
254207753Smm{
255207753Smm	const lzma_filter_encoder *const fe = encoder_find(filter->id);
256207753Smm	if (fe == NULL) {
257207753Smm		// Unknown filter - if the Filter ID is a proper VLI,
258207753Smm		// return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
259207753Smm		// because it's possible that we just don't have support
260207753Smm		// compiled in for the requested filter.
261207753Smm		return filter->id <= LZMA_VLI_MAX
262207753Smm				? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
263207753Smm	}
264207753Smm
265207753Smm	if (fe->props_size_get == NULL) {
266207753Smm		// No props_size_get() function, use props_size_fixed.
267207753Smm		*size = fe->props_size_fixed;
268207753Smm		return LZMA_OK;
269207753Smm	}
270207753Smm
271207753Smm	return fe->props_size_get(size, filter->options);
272207753Smm}
273207753Smm
274207753Smm
275207753Smmextern LZMA_API(lzma_ret)
276207753Smmlzma_properties_encode(const lzma_filter *filter, uint8_t *props)
277207753Smm{
278207753Smm	const lzma_filter_encoder *const fe = encoder_find(filter->id);
279207753Smm	if (fe == NULL)
280207753Smm		return LZMA_PROG_ERROR;
281207753Smm
282207753Smm	if (fe->props_encode == NULL)
283207753Smm		return LZMA_OK;
284207753Smm
285207753Smm	return fe->props_encode(filter->options, props);
286207753Smm}
287