mirror of
https://git.tukaani.org/xz.git
synced 2025-02-10 10:45:46 +00:00
176 lines
4.8 KiB
C
176 lines
4.8 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/// \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 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 || !implicit || uncompressed_size[0]
|
|
!= LZMA_VLI_VALUE_UNKNOWN)
|
|
return false;
|
|
|
|
// Add implicit Subblock filter.
|
|
id[1] = LZMA_FILTER_SUBBLOCK;
|
|
uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
|
|
id[2] = LZMA_VLI_VALUE_UNKNOWN;
|
|
}
|
|
|
|
return prepare(id + 1, uncompressed_size + 1, 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);
|
|
}
|