(root)/
xz-5.4.5/
src/
liblzma/
common/
filter_encoder.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       filter_decoder.c
       4  /// \brief      Filter ID mapping to filter-specific functions
       5  //
       6  //  Author:     Lasse Collin
       7  //
       8  //  This file has been put into the public domain.
       9  //  You can do whatever you want with this file.
      10  //
      11  ///////////////////////////////////////////////////////////////////////////////
      12  
      13  #include "filter_encoder.h"
      14  #include "filter_common.h"
      15  #include "lzma_encoder.h"
      16  #include "lzma2_encoder.h"
      17  #include "simple_encoder.h"
      18  #include "delta_encoder.h"
      19  
      20  
      21  typedef struct {
      22  	/// Filter ID
      23  	lzma_vli id;
      24  
      25  	/// Initializes the filter encoder and calls lzma_next_filter_init()
      26  	/// for filters + 1.
      27  	lzma_init_function init;
      28  
      29  	/// Calculates memory usage of the encoder. If the options are
      30  	/// invalid, UINT64_MAX is returned.
      31  	uint64_t (*memusage)(const void *options);
      32  
      33  	/// Calculates the recommended Uncompressed Size for .xz Blocks to
      34  	/// which the input data can be split to make multithreaded
      35  	/// encoding possible. If this is NULL, it is assumed that
      36  	/// the encoder is fast enough with single thread.
      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_DELTA
     162  	{
     163  		.id = LZMA_FILTER_DELTA,
     164  		.init = &lzma_delta_encoder_init,
     165  		.memusage = &lzma_delta_coder_memusage,
     166  		.block_size = NULL,
     167  		.props_size_get = NULL,
     168  		.props_size_fixed = 1,
     169  		.props_encode = &lzma_delta_props_encode,
     170  	},
     171  #endif
     172  };
     173  
     174  
     175  static const lzma_filter_encoder *
     176  encoder_find(lzma_vli id)
     177  {
     178  	for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
     179  		if (encoders[i].id == id)
     180  			return encoders + i;
     181  
     182  	return NULL;
     183  }
     184  
     185  
     186  extern LZMA_API(lzma_bool)
     187  lzma_filter_encoder_is_supported(lzma_vli id)
     188  {
     189  	return encoder_find(id) != NULL;
     190  }
     191  
     192  
     193  extern LZMA_API(lzma_ret)
     194  lzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
     195  {
     196  	if (strm->internal->next.update == NULL)
     197  		return LZMA_PROG_ERROR;
     198  
     199  	// Validate the filter chain.
     200  	if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
     201  		return LZMA_OPTIONS_ERROR;
     202  
     203  	// The actual filter chain in the encoder is reversed. Some things
     204  	// still want the normal order chain, so we provide both.
     205  	size_t count = 1;
     206  	while (filters[count].id != LZMA_VLI_UNKNOWN)
     207  		++count;
     208  
     209  	lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1];
     210  	for (size_t i = 0; i < count; ++i)
     211  		reversed_filters[count - i - 1] = filters[i];
     212  
     213  	reversed_filters[count].id = LZMA_VLI_UNKNOWN;
     214  
     215  	return strm->internal->next.update(strm->internal->next.coder,
     216  			strm->allocator, filters, reversed_filters);
     217  }
     218  
     219  
     220  extern lzma_ret
     221  lzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     222  		const lzma_filter *options)
     223  {
     224  	return lzma_raw_coder_init(next, allocator,
     225  			options, (lzma_filter_find)(&encoder_find), true);
     226  }
     227  
     228  
     229  extern LZMA_API(lzma_ret)
     230  lzma_raw_encoder(lzma_stream *strm, const lzma_filter *options)
     231  {
     232  	lzma_next_strm_init(lzma_raw_coder_init, strm, options,
     233  			(lzma_filter_find)(&encoder_find), true);
     234  
     235  	strm->internal->supported_actions[LZMA_RUN] = true;
     236  	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
     237  	strm->internal->supported_actions[LZMA_FINISH] = true;
     238  
     239  	return LZMA_OK;
     240  }
     241  
     242  
     243  extern LZMA_API(uint64_t)
     244  lzma_raw_encoder_memusage(const lzma_filter *filters)
     245  {
     246  	return lzma_raw_coder_memusage(
     247  			(lzma_filter_find)(&encoder_find), filters);
     248  }
     249  
     250  
     251  extern uint64_t
     252  lzma_mt_block_size(const lzma_filter *filters)
     253  {
     254  	uint64_t max = 0;
     255  
     256  	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
     257  		const lzma_filter_encoder *const fe
     258  				= encoder_find(filters[i].id);
     259  		if (fe->block_size != NULL) {
     260  			const uint64_t size
     261  					= fe->block_size(filters[i].options);
     262  			if (size == 0)
     263  				return 0;
     264  
     265  			if (size > max)
     266  				max = size;
     267  		}
     268  	}
     269  
     270  	return max;
     271  }
     272  
     273  
     274  extern LZMA_API(lzma_ret)
     275  lzma_properties_size(uint32_t *size, const lzma_filter *filter)
     276  {
     277  	const lzma_filter_encoder *const fe = encoder_find(filter->id);
     278  	if (fe == NULL) {
     279  		// Unknown filter - if the Filter ID is a proper VLI,
     280  		// return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
     281  		// because it's possible that we just don't have support
     282  		// compiled in for the requested filter.
     283  		return filter->id <= LZMA_VLI_MAX
     284  				? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
     285  	}
     286  
     287  	if (fe->props_size_get == NULL) {
     288  		// No props_size_get() function, use props_size_fixed.
     289  		*size = fe->props_size_fixed;
     290  		return LZMA_OK;
     291  	}
     292  
     293  	return fe->props_size_get(size, filter->options);
     294  }
     295  
     296  
     297  extern LZMA_API(lzma_ret)
     298  lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
     299  {
     300  	const lzma_filter_encoder *const fe = encoder_find(filter->id);
     301  	if (fe == NULL)
     302  		return LZMA_PROG_ERROR;
     303  
     304  	if (fe->props_encode == NULL)
     305  		return LZMA_OK;
     306  
     307  	return fe->props_encode(filter->options, props);
     308  }