(root)/
xz-5.4.5/
src/
liblzma/
common/
filter_common.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       filter_common.c
       4  /// \brief      Filter-specific stuff common for both encoder and decoder
       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_common.h"
      14  
      15  
      16  static const struct {
      17  	/// Filter ID
      18  	lzma_vli id;
      19  
      20  	/// Size of the filter-specific options structure
      21  	size_t options_size;
      22  
      23  	/// True if it is OK to use this filter as non-last filter in
      24  	/// the chain.
      25  	bool non_last_ok;
      26  
      27  	/// True if it is OK to use this filter as the last filter in
      28  	/// the chain.
      29  	bool last_ok;
      30  
      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).
      34  	bool changes_size;
      35  
      36  } features[] = {
      37  #if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
      38  	{
      39  		.id = LZMA_FILTER_LZMA1,
      40  		.options_size = sizeof(lzma_options_lzma),
      41  		.non_last_ok = false,
      42  		.last_ok = true,
      43  		.changes_size = true,
      44  	},
      45  	{
      46  		.id = LZMA_FILTER_LZMA1EXT,
      47  		.options_size = sizeof(lzma_options_lzma),
      48  		.non_last_ok = false,
      49  		.last_ok = true,
      50  		.changes_size = true,
      51  	},
      52  #endif
      53  #if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
      54  	{
      55  		.id = LZMA_FILTER_LZMA2,
      56  		.options_size = sizeof(lzma_options_lzma),
      57  		.non_last_ok = false,
      58  		.last_ok = true,
      59  		.changes_size = true,
      60  	},
      61  #endif
      62  #if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
      63  	{
      64  		.id = LZMA_FILTER_X86,
      65  		.options_size = sizeof(lzma_options_bcj),
      66  		.non_last_ok = true,
      67  		.last_ok = false,
      68  		.changes_size = false,
      69  	},
      70  #endif
      71  #if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
      72  	{
      73  		.id = LZMA_FILTER_POWERPC,
      74  		.options_size = sizeof(lzma_options_bcj),
      75  		.non_last_ok = true,
      76  		.last_ok = false,
      77  		.changes_size = false,
      78  	},
      79  #endif
      80  #if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
      81  	{
      82  		.id = LZMA_FILTER_IA64,
      83  		.options_size = sizeof(lzma_options_bcj),
      84  		.non_last_ok = true,
      85  		.last_ok = false,
      86  		.changes_size = false,
      87  	},
      88  #endif
      89  #if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
      90  	{
      91  		.id = LZMA_FILTER_ARM,
      92  		.options_size = sizeof(lzma_options_bcj),
      93  		.non_last_ok = true,
      94  		.last_ok = false,
      95  		.changes_size = false,
      96  	},
      97  #endif
      98  #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
      99  	{
     100  		.id = LZMA_FILTER_ARMTHUMB,
     101  		.options_size = sizeof(lzma_options_bcj),
     102  		.non_last_ok = true,
     103  		.last_ok = false,
     104  		.changes_size = false,
     105  	},
     106  #endif
     107  #if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
     108  	{
     109  		.id = LZMA_FILTER_ARM64,
     110  		.options_size = sizeof(lzma_options_bcj),
     111  		.non_last_ok = true,
     112  		.last_ok = false,
     113  		.changes_size = false,
     114  	},
     115  #endif
     116  #if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
     117  	{
     118  		.id = LZMA_FILTER_SPARC,
     119  		.options_size = sizeof(lzma_options_bcj),
     120  		.non_last_ok = true,
     121  		.last_ok = false,
     122  		.changes_size = false,
     123  	},
     124  #endif
     125  #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
     126  	{
     127  		.id = LZMA_FILTER_DELTA,
     128  		.options_size = sizeof(lzma_options_delta),
     129  		.non_last_ok = true,
     130  		.last_ok = false,
     131  		.changes_size = false,
     132  	},
     133  #endif
     134  	{
     135  		.id = LZMA_VLI_UNKNOWN
     136  	}
     137  };
     138  
     139  
     140  extern LZMA_API(lzma_ret)
     141  lzma_filters_copy(const lzma_filter *src, lzma_filter *real_dest,
     142  		const lzma_allocator *allocator)
     143  {
     144  	if (src == NULL || real_dest == NULL)
     145  		return LZMA_PROG_ERROR;
     146  
     147  	// Use a temporary destination so that the real destination
     148  	// will never be modied if an error occurs.
     149  	lzma_filter dest[LZMA_FILTERS_MAX + 1];
     150  
     151  	lzma_ret ret;
     152  	size_t i;
     153  	for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
     154  		// There must be a maximum of four filters plus
     155  		// the array terminator.
     156  		if (i == LZMA_FILTERS_MAX) {
     157  			ret = LZMA_OPTIONS_ERROR;
     158  			goto error;
     159  		}
     160  
     161  		dest[i].id = src[i].id;
     162  
     163  		if (src[i].options == NULL) {
     164  			dest[i].options = NULL;
     165  		} else {
     166  			// See if the filter is supported only when the
     167  			// options is not NULL. This might be convenient
     168  			// sometimes if the app is actually copying only
     169  			// a partial filter chain with a place holder ID.
     170  			//
     171  			// When options is not NULL, the Filter ID must be
     172  			// supported by us, because otherwise we don't know
     173  			// how big the options are.
     174  			size_t j;
     175  			for (j = 0; src[i].id != features[j].id; ++j) {
     176  				if (features[j].id == LZMA_VLI_UNKNOWN) {
     177  					ret = LZMA_OPTIONS_ERROR;
     178  					goto error;
     179  				}
     180  			}
     181  
     182  			// Allocate and copy the options.
     183  			dest[i].options = lzma_alloc(features[j].options_size,
     184  					allocator);
     185  			if (dest[i].options == NULL) {
     186  				ret = LZMA_MEM_ERROR;
     187  				goto error;
     188  			}
     189  
     190  			memcpy(dest[i].options, src[i].options,
     191  					features[j].options_size);
     192  		}
     193  	}
     194  
     195  	// Terminate the filter array.
     196  	assert(i < LZMA_FILTERS_MAX + 1);
     197  	dest[i].id = LZMA_VLI_UNKNOWN;
     198  	dest[i].options = NULL;
     199  
     200  	// Copy it to the caller-supplied array now that we know that
     201  	// no errors occurred.
     202  	memcpy(real_dest, dest, (i + 1) * sizeof(lzma_filter));
     203  
     204  	return LZMA_OK;
     205  
     206  error:
     207  	// Free the options which we have already allocated.
     208  	while (i-- > 0)
     209  		lzma_free(dest[i].options, allocator);
     210  
     211  	return ret;
     212  }
     213  
     214  
     215  extern LZMA_API(void)
     216  lzma_filters_free(lzma_filter *filters, const lzma_allocator *allocator)
     217  {
     218  	if (filters == NULL)
     219  		return;
     220  
     221  	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
     222  		if (i == LZMA_FILTERS_MAX) {
     223  			// The API says that LZMA_FILTERS_MAX + 1 is the
     224  			// maximum allowed size including the terminating
     225  			// element. Thus, we should never get here but in
     226  			// case there is a bug and we do anyway, don't go
     227  			// past the (probable) end of the array.
     228  			assert(0);
     229  			break;
     230  		}
     231  
     232  		lzma_free(filters[i].options, allocator);
     233  		filters[i].options = NULL;
     234  		filters[i].id = LZMA_VLI_UNKNOWN;
     235  	}
     236  
     237  	return;
     238  }
     239  
     240  
     241  extern lzma_ret
     242  lzma_validate_chain(const lzma_filter *filters, size_t *count)
     243  {
     244  	// There must be at least one filter.
     245  	if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
     246  		return LZMA_PROG_ERROR;
     247  
     248  	// Number of non-last filters that may change the size of the data
     249  	// significantly (that is, more than 1-2 % or so).
     250  	size_t changes_size_count = 0;
     251  
     252  	// True if it is OK to add a new filter after the current filter.
     253  	bool non_last_ok = true;
     254  
     255  	// True if the last filter in the given chain is actually usable as
     256  	// the last filter. Only filters that support embedding End of Payload
     257  	// Marker can be used as the last filter in the chain.
     258  	bool last_ok = false;
     259  
     260  	size_t i = 0;
     261  	do {
     262  		size_t j;
     263  		for (j = 0; filters[i].id != features[j].id; ++j)
     264  			if (features[j].id == LZMA_VLI_UNKNOWN)
     265  				return LZMA_OPTIONS_ERROR;
     266  
     267  		// If the previous filter in the chain cannot be a non-last
     268  		// filter, the chain is invalid.
     269  		if (!non_last_ok)
     270  			return LZMA_OPTIONS_ERROR;
     271  
     272  		non_last_ok = features[j].non_last_ok;
     273  		last_ok = features[j].last_ok;
     274  		changes_size_count += features[j].changes_size;
     275  
     276  	} while (filters[++i].id != LZMA_VLI_UNKNOWN);
     277  
     278  	// There must be 1-4 filters. The last filter must be usable as
     279  	// the last filter in the chain. A maximum of three filters are
     280  	// allowed to change the size of the data.
     281  	if (i > LZMA_FILTERS_MAX || !last_ok || changes_size_count > 3)
     282  		return LZMA_OPTIONS_ERROR;
     283  
     284  	*count = i;
     285  	return LZMA_OK;
     286  }
     287  
     288  
     289  extern lzma_ret
     290  lzma_raw_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     291  		const lzma_filter *options,
     292  		lzma_filter_find coder_find, bool is_encoder)
     293  {
     294  	// Do some basic validation and get the number of filters.
     295  	size_t count;
     296  	return_if_error(lzma_validate_chain(options, &count));
     297  
     298  	// Set the filter functions and copy the options pointer.
     299  	lzma_filter_info filters[LZMA_FILTERS_MAX + 1];
     300  	if (is_encoder) {
     301  		for (size_t i = 0; i < count; ++i) {
     302  			// The order of the filters is reversed in the
     303  			// encoder. It allows more efficient handling
     304  			// of the uncompressed data.
     305  			const size_t j = count - i - 1;
     306  
     307  			const lzma_filter_coder *const fc
     308  					= coder_find(options[i].id);
     309  			if (fc == NULL || fc->init == NULL)
     310  				return LZMA_OPTIONS_ERROR;
     311  
     312  			filters[j].id = options[i].id;
     313  			filters[j].init = fc->init;
     314  			filters[j].options = options[i].options;
     315  		}
     316  	} else {
     317  		for (size_t i = 0; i < count; ++i) {
     318  			const lzma_filter_coder *const fc
     319  					= coder_find(options[i].id);
     320  			if (fc == NULL || fc->init == NULL)
     321  				return LZMA_OPTIONS_ERROR;
     322  
     323  			filters[i].id = options[i].id;
     324  			filters[i].init = fc->init;
     325  			filters[i].options = options[i].options;
     326  		}
     327  	}
     328  
     329  	// Terminate the array.
     330  	filters[count].id = LZMA_VLI_UNKNOWN;
     331  	filters[count].init = NULL;
     332  
     333  	// Initialize the filters.
     334  	const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
     335  	if (ret != LZMA_OK)
     336  		lzma_next_end(next, allocator);
     337  
     338  	return ret;
     339  }
     340  
     341  
     342  extern uint64_t
     343  lzma_raw_coder_memusage(lzma_filter_find coder_find,
     344  		const lzma_filter *filters)
     345  {
     346  	// The chain has to have at least one filter.
     347  	{
     348  		size_t tmp;
     349  		if (lzma_validate_chain(filters, &tmp) != LZMA_OK)
     350  			return UINT64_MAX;
     351  	}
     352  
     353  	uint64_t total = 0;
     354  	size_t i = 0;
     355  
     356  	do {
     357  		const lzma_filter_coder *const fc
     358  				 = coder_find(filters[i].id);
     359  		if (fc == NULL)
     360  			return UINT64_MAX; // Unsupported Filter ID
     361  
     362  		if (fc->memusage == NULL) {
     363  			// This filter doesn't have a function to calculate
     364  			// the memory usage and validate the options. Such
     365  			// filters need only little memory, so we use 1 KiB
     366  			// as a good estimate. They also accept all possible
     367  			// options, so there's no need to worry about lack
     368  			// of validation.
     369  			total += 1024;
     370  		} else {
     371  			// Call the filter-specific memory usage calculation
     372  			// function.
     373  			const uint64_t usage
     374  					= fc->memusage(filters[i].options);
     375  			if (usage == UINT64_MAX)
     376  				return UINT64_MAX; // Invalid options
     377  
     378  			total += usage;
     379  		}
     380  	} while (filters[++i].id != LZMA_VLI_UNKNOWN);
     381  
     382  	// Add some fixed amount of extra. It's to compensate memory usage
     383  	// of Stream, Block etc. coders, malloc() overhead, stack etc.
     384  	return total + LZMA_MEMUSAGE_BASE;
     385  }