aboutsummaryrefslogblamecommitdiff
path: root/src/liblzma/common/raw_common.c
blob: 35252fc2b7fae0309f8ed1e5eaae15fc689f4046 (plain) (tree)





















                                                                               

                                                                   
 

                                       
 







































                                                                              
                 

         











                                                                          




                                                                     
                                                   
                                                                
                                
 


                                                                  
 
                                                                 







                                                                      
                                                                      



                                                                
                 

                                                    
                                                                      



                                                                
                 







                                                               
///////////////////////////////////////////////////////////////////////////////
//
/// \file       raw_common.c
/// \brief      Stuff shared between raw encoder and raw decoder
//
//  Copyright (C) 2007 Lasse Collin
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////

#include "raw_common.h"


static lzma_ret
validate_options(const lzma_options_filter *options, size_t *count)
{
	if (options == NULL)
		return LZMA_PROG_ERROR;

	// Number of non-last filters that may change the size of the data
	// significantly (that is, more than 1-2 % or so).
	size_t change = 0;

	// True if the last filter in the given chain is actually usable as
	// the last filter. Only filters that support embedding End of Payload
	// Marker can be used as the last filter in the chain.
	bool last_ok = false;

	size_t i;
	for (i = 0; options[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
		switch (options[i].id) {
		// Not #ifdeffing these for simplicity.
		case LZMA_FILTER_X86:
		case LZMA_FILTER_POWERPC:
		case LZMA_FILTER_IA64:
		case LZMA_FILTER_ARM:
		case LZMA_FILTER_ARMTHUMB:
		case LZMA_FILTER_SPARC:
		case LZMA_FILTER_DELTA:
			// These don't change the size of the data and cannot
			// be used as the last filter in the chain.
			last_ok = false;
			break;

#ifdef HAVE_FILTER_SUBBLOCK
		case LZMA_FILTER_SUBBLOCK:
			last_ok = true;
			++change;
			break;
#endif

#ifdef HAVE_FILTER_LZMA
		case LZMA_FILTER_LZMA:
			last_ok = true;
			break;
#endif

		default:
			return LZMA_HEADER_ERROR;
		}
	}

	// There must be 1-4 filters and the last filter must be usable as
	// the last filter in the chain.
	if (i == 0 || i > 4 || !last_ok)
		return LZMA_HEADER_ERROR;

	// At maximum of two non-last filters are allowed to change the
	// size of the data.
	if (change > 2)
		return LZMA_HEADER_ERROR;

	*count = i;
	return LZMA_OK;
}


extern lzma_ret
lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
		const lzma_options_filter *options,
		lzma_init_function (*get_function)(lzma_vli id),
		bool is_encoder)
{
	// Do some basic validation and get the number of filters.
	size_t count;
	return_if_error(validate_options(options, &count));

	// Set the filter functions and copy the options pointer.
	lzma_filter_info filters[count + 1];
	if (is_encoder) {
		for (size_t i = 0; i < count; ++i) {
			// The order of the filters is reversed in the
			// encoder. It allows more efficient handling
			// of the uncompressed data.
			const size_t j = count - i - 1;

			filters[j].init = get_function(options[i].id);
			if (filters[j].init == NULL)
				return LZMA_HEADER_ERROR;

			filters[j].options = options[i].options;
		}
	} else {
		for (size_t i = 0; i < count; ++i) {
			filters[i].init = get_function(options[i].id);
			if (filters[i].init == NULL)
				return LZMA_HEADER_ERROR;

			filters[i].options = options[i].options;
		}
	}

	// Terminate the array.
	filters[count].init = NULL;

	// Initialize the filters.
	return lzma_next_filter_init(next, allocator, filters);
}