aboutsummaryrefslogblamecommitdiff
path: root/src/liblzma/common/raw_common.c
blob: d45bf4deeb908dd4105f1895281f94dcc3319996 (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"


/// \brief      Prepares the filter chain
///
/// Prepares the filter chain by setting uncompressed sizes for each filter,
/// and adding implicit Subblock filter when needed.
///
/// \return     true if error occurred, false on success.
///
static bool
prepare(lzma_vli *id, lzma_vli *uncompressed_size, bool allow_implicit)
{
	bool needs_end_of_input = false;

	switch (id[0]) {
	case LZMA_FILTER_COPY:
	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:
		uncompressed_size[1] = uncompressed_size[0];
		needs_end_of_input = true;
		break;

	case LZMA_FILTER_SUBBLOCK:
	case LZMA_FILTER_LZMA:
		// These change the size of the data unpredictably.
		uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
		break;

	case LZMA_FILTER_SUBBLOCK_HELPER:
		uncompressed_size[1] = uncompressed_size[0];
		break;

	default:
		// Unknown filter.
		return true;
	}

	// Is this the last filter in the chain?
	if (id[1] == LZMA_VLI_VALUE_UNKNOWN) {
		if (needs_end_of_input && allow_implicit
				&& uncompressed_size[0]
					== LZMA_VLI_VALUE_UNKNOWN) {
			// Add implicit Subblock filter.
			id[1] = LZMA_FILTER_SUBBLOCK;
			uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
			id[2] = LZMA_VLI_VALUE_UNKNOWN;
		}

		return false;
	}

	return prepare(id + 1, uncompressed_size + 1, allow_implicit);
}


extern lzma_ret
lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
		const lzma_options_filter *options, lzma_vli uncompressed_size,
		lzma_init_function (*get_function)(lzma_vli id),
		bool allow_implicit, bool is_encoder)
{
	if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
		return LZMA_PROG_ERROR;

	// Count the number of filters in the chain.
	size_t count = 0;
	while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
		++count;

	// Allocate enough space from the stack for IDs and uncompressed
	// sizes. We need two extra: possible implicit Subblock and end
	// of array indicator.
	lzma_vli ids[count + 2];
	lzma_vli uncompressed_sizes[count + 2];
	bool using_implicit = false;

	uncompressed_sizes[0] = uncompressed_size;

	if (count == 0) {
		if (!allow_implicit)
			return LZMA_PROG_ERROR;

		count = 1;
		using_implicit = true;

		// Special case: no filters were specified, so an implicit
		// Copy or Subblock filter is used.
		if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
			ids[0] = LZMA_FILTER_SUBBLOCK;
		else
			ids[0] = LZMA_FILTER_COPY;

		ids[1] = LZMA_VLI_VALUE_UNKNOWN;

	} else {
		// Prepare the ids[] and uncompressed_sizes[].
		for (size_t i = 0; i < count; ++i)
			ids[i] = options[i].id;

		ids[count] = LZMA_VLI_VALUE_UNKNOWN;

		if (prepare(ids, uncompressed_sizes, allow_implicit))
			return LZMA_HEADER_ERROR;

		// Check if implicit Subblock filter was added.
		if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
			assert(ids[count] == LZMA_FILTER_SUBBLOCK);
			++count;
			using_implicit = true;
		}
	}

	// Set the filter functions, and copy uncompressed sizes and options.
	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(ids[i]);
			if (filters[j].init == NULL)
				return LZMA_HEADER_ERROR;

			filters[j].options = options[i].options;
			filters[j].uncompressed_size = uncompressed_sizes[i];
		}

		if (using_implicit)
			filters[0].options = NULL;

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

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

		if (using_implicit)
			filters[count - 1].options = NULL;
	}

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

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