mirror of
https://git.tukaani.org/xz.git
synced 2025-02-09 18:25:46 +00:00
specification. Simplify things by removing most of the support for known uncompressed size in most places. There are some miscellaneous changes here and there too. The API of liblzma has got many changes and still some more will be done soon. While most of the code has been updated, some things are not fixed (the command line tool will choke with invalid filter chain, if nothing else). Subblock filter is somewhat broken for now. It will be updated once the encoded format of the Subblock filter has been decided.
225 lines
6.2 KiB
C
225 lines
6.2 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/// \file block_decoder.c
|
|
/// \brief Decodes .lzma Blocks
|
|
//
|
|
// 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 "block_decoder.h"
|
|
#include "block_private.h"
|
|
#include "raw_decoder.h"
|
|
#include "check.h"
|
|
|
|
|
|
struct lzma_coder_s {
|
|
enum {
|
|
SEQ_CODE,
|
|
SEQ_PADDING,
|
|
SEQ_CHECK,
|
|
} sequence;
|
|
|
|
/// The filters in the chain; initialized with lzma_raw_decoder_init().
|
|
lzma_next_coder next;
|
|
|
|
/// Decoding options; we also write Compressed Size and Uncompressed
|
|
/// Size back to this structure when the encoding has been finished.
|
|
lzma_options_block *options;
|
|
|
|
/// Compressed Size calculated while encoding
|
|
lzma_vli compressed_size;
|
|
|
|
/// Uncompressed Size calculated while encoding
|
|
lzma_vli uncompressed_size;
|
|
|
|
/// Maximum allowed Compressed Size; this takes into account the
|
|
/// size of the Block Header and Check fields when Compressed Size
|
|
/// is unknown.
|
|
lzma_vli compressed_limit;
|
|
|
|
/// Position when reading the Check field
|
|
size_t check_pos;
|
|
|
|
/// Check of the uncompressed data
|
|
lzma_check check;
|
|
};
|
|
|
|
|
|
static lzma_ret
|
|
block_decode(lzma_coder *coder, lzma_allocator *allocator,
|
|
const uint8_t *restrict in, size_t *restrict in_pos,
|
|
size_t in_size, uint8_t *restrict out,
|
|
size_t *restrict out_pos, size_t out_size, lzma_action action)
|
|
{
|
|
switch (coder->sequence) {
|
|
case SEQ_CODE: {
|
|
if (*out_pos >= out_size)
|
|
return LZMA_OK;
|
|
|
|
const size_t in_start = *in_pos;
|
|
const size_t out_start = *out_pos;
|
|
|
|
const lzma_ret ret = coder->next.code(coder->next.coder,
|
|
allocator, in, in_pos, in_size,
|
|
out, out_pos, out_size, action);
|
|
|
|
const size_t in_used = *in_pos - in_start;
|
|
const size_t out_used = *out_pos - out_start;
|
|
|
|
// NOTE: We compare to compressed_limit here, which prevents
|
|
// the total size of the Block growing past LZMA_VLI_VALUE_MAX.
|
|
if (update_size(&coder->compressed_size, in_used,
|
|
coder->compressed_limit)
|
|
|| update_size(&coder->uncompressed_size,
|
|
out_used,
|
|
coder->options->uncompressed_size))
|
|
return LZMA_DATA_ERROR;
|
|
|
|
lzma_check_update(&coder->check, coder->options->check,
|
|
out + out_start, out_used);
|
|
|
|
if (ret != LZMA_STREAM_END)
|
|
return ret;
|
|
|
|
coder->sequence = SEQ_PADDING;
|
|
}
|
|
|
|
// Fall through
|
|
|
|
case SEQ_PADDING:
|
|
// If Compressed Data is padded to a multiple of four bytes.
|
|
while (coder->compressed_size & 3) {
|
|
if (*in_pos >= in_size)
|
|
return LZMA_OK;
|
|
|
|
if (in[(*in_pos)++] != 0x00)
|
|
return LZMA_DATA_ERROR;
|
|
|
|
if (update_size(&coder->compressed_size, 1,
|
|
coder->compressed_limit))
|
|
return LZMA_DATA_ERROR;
|
|
}
|
|
|
|
// Compressed and Uncompressed Sizes are now at their final
|
|
// values. Verify that they match the values given to us.
|
|
if (!is_size_valid(coder->compressed_size,
|
|
coder->options->compressed_size)
|
|
|| !is_size_valid(coder->uncompressed_size,
|
|
coder->options->uncompressed_size))
|
|
return LZMA_DATA_ERROR;
|
|
|
|
// Copy the values into coder->options. The caller
|
|
// may use this information to construct Index.
|
|
coder->options->compressed_size = coder->compressed_size;
|
|
coder->options->uncompressed_size = coder->uncompressed_size;
|
|
|
|
if (coder->options->check == LZMA_CHECK_NONE)
|
|
return LZMA_STREAM_END;
|
|
|
|
lzma_check_finish(&coder->check, coder->options->check);
|
|
coder->sequence = SEQ_CHECK;
|
|
|
|
// Fall through
|
|
|
|
case SEQ_CHECK:
|
|
while (*in_pos < in_size) {
|
|
if (in[(*in_pos)++] != coder->check.buffer[
|
|
coder->check_pos])
|
|
return LZMA_DATA_ERROR;
|
|
|
|
if (++coder->check_pos == lzma_check_sizes[
|
|
coder->options->check])
|
|
return LZMA_STREAM_END;
|
|
}
|
|
|
|
return LZMA_OK;
|
|
}
|
|
|
|
return LZMA_PROG_ERROR;
|
|
}
|
|
|
|
|
|
static void
|
|
block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
|
|
{
|
|
lzma_next_coder_end(&coder->next, allocator);
|
|
lzma_free(coder, allocator);
|
|
return;
|
|
}
|
|
|
|
|
|
static lzma_ret
|
|
block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
|
lzma_options_block *options)
|
|
{
|
|
// While lzma_block_total_size_get() is meant to calculate the Total
|
|
// Size, it also validates the options excluding the filters.
|
|
if (lzma_block_total_size_get(options) == 0)
|
|
return LZMA_PROG_ERROR;
|
|
|
|
// Allocate and initialize *next->coder if needed.
|
|
if (next->coder == NULL) {
|
|
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
|
|
if (next->coder == NULL)
|
|
return LZMA_MEM_ERROR;
|
|
|
|
next->code = &block_decode;
|
|
next->end = &block_decoder_end;
|
|
next->coder->next = LZMA_NEXT_CODER_INIT;
|
|
}
|
|
|
|
// Basic initializations
|
|
next->coder->sequence = SEQ_CODE;
|
|
next->coder->options = options;
|
|
next->coder->compressed_size = 0;
|
|
next->coder->uncompressed_size = 0;
|
|
|
|
// If Compressed Size is not known, we calculate the maximum allowed
|
|
// value so that Total Size of the Block still is a valid VLI and
|
|
// a multiple of four.
|
|
next->coder->compressed_limit
|
|
= options->compressed_size == LZMA_VLI_VALUE_UNKNOWN
|
|
? (LZMA_VLI_VALUE_MAX & ~LZMA_VLI_C(3))
|
|
- options->header_size
|
|
- lzma_check_sizes[options->check]
|
|
: options->compressed_size;
|
|
|
|
// Initialize the check
|
|
next->coder->check_pos = 0;
|
|
return_if_error(lzma_check_init(&next->coder->check, options->check));
|
|
|
|
return lzma_raw_decoder_init(&next->coder->next, allocator,
|
|
options->filters);
|
|
}
|
|
|
|
|
|
extern lzma_ret
|
|
lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
|
lzma_options_block *options)
|
|
{
|
|
lzma_next_coder_init(block_decoder_init, next, allocator, options);
|
|
}
|
|
|
|
|
|
extern LZMA_API lzma_ret
|
|
lzma_block_decoder(lzma_stream *strm, lzma_options_block *options)
|
|
{
|
|
lzma_next_strm_init(strm, block_decoder_init, options);
|
|
|
|
strm->internal->supported_actions[LZMA_RUN] = true;
|
|
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
|
|
|
|
return LZMA_OK;
|
|
}
|