Home | History | Annotate | Line # | Download | only in common
      1 // SPDX-License-Identifier: 0BSD
      2 
      3 ///////////////////////////////////////////////////////////////////////////////
      4 //
      5 /// \file       filter_decoder.c
      6 /// \brief      Filter ID mapping to filter-specific functions
      7 //
      8 //  Author:     Lasse Collin
      9 //
     10 ///////////////////////////////////////////////////////////////////////////////
     11 
     12 #include "filter_encoder.h"
     13 #include "filter_common.h"
     14 #include "lzma_encoder.h"
     15 #include "lzma2_encoder.h"
     16 #include "simple_encoder.h"
     17 #include "delta_encoder.h"
     18 
     19 
     20 typedef struct {
     21 	/// Filter ID
     22 	lzma_vli id;
     23 
     24 	/// Initializes the filter encoder and calls lzma_next_filter_init()
     25 	/// for filters + 1.
     26 	lzma_init_function init;
     27 
     28 	/// Calculates memory usage of the encoder. If the options are
     29 	/// invalid, UINT64_MAX is returned.
     30 	uint64_t (*memusage)(const void *options);
     31 
     32 	/// Calculates the recommended Uncompressed Size for .xz Blocks to
     33 	/// which the input data can be split to make multithreaded
     34 	/// encoding possible. If this is NULL, it is assumed that
     35 	/// the encoder is fast enough with single thread. If the options
     36 	/// are invalid, UINT64_MAX is returned.
     37 	uint64_t (*block_size)(const void *options);
     38 
     39 	/// Tells the size of the Filter Properties field. If options are
     40 	/// invalid, LZMA_OPTIONS_ERROR is returned and size is set to
     41 	/// UINT32_MAX.
     42 	lzma_ret (*props_size_get)(uint32_t *size, const void *options);
     43 
     44 	/// Some filters will always have the same size Filter Properties
     45 	/// field. If props_size_get is NULL, this value is used.
     46 	uint32_t props_size_fixed;
     47 
     48 	/// Encodes Filter Properties.
     49 	///
     50 	/// \return     - LZMA_OK: Properties encoded successfully.
     51 	///             - LZMA_OPTIONS_ERROR: Unsupported options
     52 	///             - LZMA_PROG_ERROR: Invalid options or not enough
     53 	///               output space
     54 	lzma_ret (*props_encode)(const void *options, uint8_t *out);
     55 
     56 } lzma_filter_encoder;
     57 
     58 
     59 static const lzma_filter_encoder encoders[] = {
     60 #ifdef HAVE_ENCODER_LZMA1
     61 	{
     62 		.id = LZMA_FILTER_LZMA1,
     63 		.init = &lzma_lzma_encoder_init,
     64 		.memusage = &lzma_lzma_encoder_memusage,
     65 		.block_size = NULL, // Not needed for LZMA1
     66 		.props_size_get = NULL,
     67 		.props_size_fixed = 5,
     68 		.props_encode = &lzma_lzma_props_encode,
     69 	},
     70 	{
     71 		.id = LZMA_FILTER_LZMA1EXT,
     72 		.init = &lzma_lzma_encoder_init,
     73 		.memusage = &lzma_lzma_encoder_memusage,
     74 		.block_size = NULL, // Not needed for LZMA1
     75 		.props_size_get = NULL,
     76 		.props_size_fixed = 5,
     77 		.props_encode = &lzma_lzma_props_encode,
     78 	},
     79 #endif
     80 #ifdef HAVE_ENCODER_LZMA2
     81 	{
     82 		.id = LZMA_FILTER_LZMA2,
     83 		.init = &lzma_lzma2_encoder_init,
     84 		.memusage = &lzma_lzma2_encoder_memusage,
     85 		.block_size = &lzma_lzma2_block_size,
     86 		.props_size_get = NULL,
     87 		.props_size_fixed = 1,
     88 		.props_encode = &lzma_lzma2_props_encode,
     89 	},
     90 #endif
     91 #ifdef HAVE_ENCODER_X86
     92 	{
     93 		.id = LZMA_FILTER_X86,
     94 		.init = &lzma_simple_x86_encoder_init,
     95 		.memusage = NULL,
     96 		.block_size = NULL,
     97 		.props_size_get = &lzma_simple_props_size,
     98 		.props_encode = &lzma_simple_props_encode,
     99 	},
    100 #endif
    101 #ifdef HAVE_ENCODER_POWERPC
    102 	{
    103 		.id = LZMA_FILTER_POWERPC,
    104 		.init = &lzma_simple_powerpc_encoder_init,
    105 		.memusage = NULL,
    106 		.block_size = NULL,
    107 		.props_size_get = &lzma_simple_props_size,
    108 		.props_encode = &lzma_simple_props_encode,
    109 	},
    110 #endif
    111 #ifdef HAVE_ENCODER_IA64
    112 	{
    113 		.id = LZMA_FILTER_IA64,
    114 		.init = &lzma_simple_ia64_encoder_init,
    115 		.memusage = NULL,
    116 		.block_size = NULL,
    117 		.props_size_get = &lzma_simple_props_size,
    118 		.props_encode = &lzma_simple_props_encode,
    119 	},
    120 #endif
    121 #ifdef HAVE_ENCODER_ARM
    122 	{
    123 		.id = LZMA_FILTER_ARM,
    124 		.init = &lzma_simple_arm_encoder_init,
    125 		.memusage = NULL,
    126 		.block_size = NULL,
    127 		.props_size_get = &lzma_simple_props_size,
    128 		.props_encode = &lzma_simple_props_encode,
    129 	},
    130 #endif
    131 #ifdef HAVE_ENCODER_ARMTHUMB
    132 	{
    133 		.id = LZMA_FILTER_ARMTHUMB,
    134 		.init = &lzma_simple_armthumb_encoder_init,
    135 		.memusage = NULL,
    136 		.block_size = NULL,
    137 		.props_size_get = &lzma_simple_props_size,
    138 		.props_encode = &lzma_simple_props_encode,
    139 	},
    140 #endif
    141 #ifdef HAVE_ENCODER_ARM64
    142 	{
    143 		.id = LZMA_FILTER_ARM64,
    144 		.init = &lzma_simple_arm64_encoder_init,
    145 		.memusage = NULL,
    146 		.block_size = NULL,
    147 		.props_size_get = &lzma_simple_props_size,
    148 		.props_encode = &lzma_simple_props_encode,
    149 	},
    150 #endif
    151 #ifdef HAVE_ENCODER_SPARC
    152 	{
    153 		.id = LZMA_FILTER_SPARC,
    154 		.init = &lzma_simple_sparc_encoder_init,
    155 		.memusage = NULL,
    156 		.block_size = NULL,
    157 		.props_size_get = &lzma_simple_props_size,
    158 		.props_encode = &lzma_simple_props_encode,
    159 	},
    160 #endif
    161 #ifdef HAVE_ENCODER_RISCV
    162 	{
    163 		.id = LZMA_FILTER_RISCV,
    164 		.init = &lzma_simple_riscv_encoder_init,
    165 		.memusage = NULL,
    166 		.block_size = NULL,
    167 		.props_size_get = &lzma_simple_props_size,
    168 		.props_encode = &lzma_simple_props_encode,
    169 	},
    170 #endif
    171 #ifdef HAVE_ENCODER_DELTA
    172 	{
    173 		.id = LZMA_FILTER_DELTA,
    174 		.init = &lzma_delta_encoder_init,
    175 		.memusage = &lzma_delta_coder_memusage,
    176 		.block_size = NULL,
    177 		.props_size_get = NULL,
    178 		.props_size_fixed = 1,
    179 		.props_encode = &lzma_delta_props_encode,
    180 	},
    181 #endif
    182 };
    183 
    184 
    185 static const lzma_filter_encoder *
    186 encoder_find(lzma_vli id)
    187 {
    188 	for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
    189 		if (encoders[i].id == id)
    190 			return encoders + i;
    191 
    192 	return NULL;
    193 }
    194 
    195 
    196 // lzma_filter_coder begins with the same members as lzma_filter_encoder.
    197 // This function is a wrapper with a type that is compatible with the
    198 // typedef of lzma_filter_find in filter_common.h.
    199 static const lzma_filter_coder *
    200 coder_find(lzma_vli id)
    201 {
    202 	return (const lzma_filter_coder *)encoder_find(id);
    203 }
    204 
    205 
    206 extern LZMA_API(lzma_bool)
    207 lzma_filter_encoder_is_supported(lzma_vli id)
    208 {
    209 	return encoder_find(id) != NULL;
    210 }
    211 
    212 
    213 extern LZMA_API(lzma_ret)
    214 lzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
    215 {
    216 	if (strm->internal->next.update == NULL)
    217 		return LZMA_PROG_ERROR;
    218 
    219 	// Validate the filter chain.
    220 	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
    221 		return LZMA_OPTIONS_ERROR;
    222 
    223 	// The actual filter chain in the encoder is reversed. Some things
    224 	// still want the normal order chain, so we provide both.
    225 	size_t count = 1;
    226 	while (filters[count].id != LZMA_VLI_UNKNOWN)
    227 		++count;
    228 
    229 	lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1];
    230 	for (size_t i = 0; i < count; ++i)
    231 		reversed_filters[count - i - 1] = filters[i];
    232 
    233 	reversed_filters[count].id = LZMA_VLI_UNKNOWN;
    234 
    235 	return strm->internal->next.update(strm->internal->next.coder,
    236 			strm->allocator, filters, reversed_filters);
    237 }
    238 
    239 
    240 extern lzma_ret
    241 lzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    242 		const lzma_filter *filters)
    243 {
    244 	return lzma_raw_coder_init(next, allocator,
    245 			filters, &coder_find, true);
    246 }
    247 
    248 
    249 extern LZMA_API(lzma_ret)
    250 lzma_raw_encoder(lzma_stream *strm, const lzma_filter *filters)
    251 {
    252 	lzma_next_strm_init(lzma_raw_coder_init, strm, filters,
    253 			&coder_find, true);
    254 
    255 	strm->internal->supported_actions[LZMA_RUN] = true;
    256 	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
    257 	strm->internal->supported_actions[LZMA_FINISH] = true;
    258 
    259 	return LZMA_OK;
    260 }
    261 
    262 
    263 extern LZMA_API(uint64_t)
    264 lzma_raw_encoder_memusage(const lzma_filter *filters)
    265 {
    266 	return lzma_raw_coder_memusage(&coder_find, filters);
    267 }
    268 
    269 
    270 extern LZMA_API(uint64_t)
    271 lzma_mt_block_size(const lzma_filter *filters)
    272 {
    273 	if (filters == NULL)
    274 		return UINT64_MAX;
    275 
    276 	uint64_t max = 0;
    277 
    278 	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
    279 		const lzma_filter_encoder *const fe
    280 				= encoder_find(filters[i].id);
    281 		if (fe == NULL)
    282 			return UINT64_MAX;
    283 
    284 		if (fe->block_size != NULL) {
    285 			const uint64_t size
    286 					= fe->block_size(filters[i].options);
    287 			if (size > max)
    288 				max = size;
    289 		}
    290 	}
    291 
    292 	return max == 0 ? UINT64_MAX : max;
    293 }
    294 
    295 
    296 extern LZMA_API(lzma_ret)
    297 lzma_properties_size(uint32_t *size, const lzma_filter *filter)
    298 {
    299 	const lzma_filter_encoder *const fe = encoder_find(filter->id);
    300 	if (fe == NULL) {
    301 		// Unknown filter - if the Filter ID is a proper VLI,
    302 		// return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
    303 		// because it's possible that we just don't have support
    304 		// compiled in for the requested filter.
    305 		return filter->id <= LZMA_VLI_MAX
    306 				? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
    307 	}
    308 
    309 	if (fe->props_size_get == NULL) {
    310 		// No props_size_get() function, use props_size_fixed.
    311 		*size = fe->props_size_fixed;
    312 		return LZMA_OK;
    313 	}
    314 
    315 	return fe->props_size_get(size, filter->options);
    316 }
    317 
    318 
    319 extern LZMA_API(lzma_ret)
    320 lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
    321 {
    322 	const lzma_filter_encoder *const fe = encoder_find(filter->id);
    323 	if (fe == NULL)
    324 		return LZMA_PROG_ERROR;
    325 
    326 	if (fe->props_encode == NULL)
    327 		return LZMA_OK;
    328 
    329 	return fe->props_encode(filter->options, props);
    330 }
    331