xz/src/liblzma/common/filter_flags_encoder.c

284 lines
6.5 KiB
C
Raw Normal View History

2007-12-08 22:42:33 +00:00
///////////////////////////////////////////////////////////////////////////////
//
/// \file filter_flags_encoder.c
/// \brief Decodes a Filter Flags field
//
// 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 "common.h"
#include "lzma_encoder.h"
#include "fastpos.h"
2007-12-08 22:42:33 +00:00
/// Calculate the size of the Filter Properties field
2007-12-08 22:42:33 +00:00
static lzma_ret
get_properties_size(uint32_t *size, const lzma_options_filter *options)
{
lzma_ret ret = LZMA_OK;
switch (options->id) {
#ifdef HAVE_FILTER_SUBBLOCK
case LZMA_FILTER_SUBBLOCK:
*size = 0;
break;
#endif
#ifdef HAVE_FILTER_SIMPLE
# ifdef HAVE_FILTER_X86
case LZMA_FILTER_X86:
# endif
# ifdef HAVE_FILTER_POWERPC
case LZMA_FILTER_POWERPC:
# endif
# ifdef HAVE_FILTER_IA64
case LZMA_FILTER_IA64:
# endif
# ifdef HAVE_FILTER_ARM
case LZMA_FILTER_ARM:
# endif
# ifdef HAVE_FILTER_ARMTHUMB
case LZMA_FILTER_ARMTHUMB:
# endif
# ifdef HAVE_FILTER_SPARC
case LZMA_FILTER_SPARC:
# endif
if (options->options == NULL || ((const lzma_options_simple *)(
options->options))->start_offset == 0)
*size = 0;
else
*size = 4;
break;
#endif
#ifdef HAVE_FILTER_DELTA
case LZMA_FILTER_DELTA:
*size = 1;
break;
#endif
#ifdef HAVE_FILTER_LZMA
case LZMA_FILTER_LZMA:
*size = 2;
break;
#endif
default:
// Unknown filter - if the Filter ID is a proper VLI,
// return LZMA_HEADER_ERROR instead of LZMA_PROG_ERROR,
// because it's possible that we just don't have support
// compiled in for the requested filter.
ret = options->id <= LZMA_VLI_VALUE_MAX
? LZMA_HEADER_ERROR : LZMA_PROG_ERROR;
break;
}
return ret;
}
extern LZMA_API lzma_ret
lzma_filter_flags_size(uint32_t *size, const lzma_options_filter *options)
{
// Get size of Filter Properties. This also validates the Filter ID.
2007-12-08 22:42:33 +00:00
uint32_t prop_size;
return_if_error(get_properties_size(&prop_size, options));
2007-12-08 22:42:33 +00:00
// Calculate the size of the Filter ID and Size of Properties fields.
// These cannot fail since get_properties_size() already succeeded.
*size = lzma_vli_size(options->id) + lzma_vli_size(prop_size)
+ prop_size;
2007-12-08 22:42:33 +00:00
return LZMA_OK;
}
#ifdef HAVE_FILTER_SIMPLE
/// Encodes Filter Properties of the so called simple filters
static lzma_ret
properties_simple(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_simple *options)
{
if (options == NULL || options->start_offset == 0)
return LZMA_OK;
if (out_size - *out_pos < 4)
return LZMA_PROG_ERROR;
2007-12-08 22:42:33 +00:00
integer_write_32(out + *out_pos, options->start_offset);
*out_pos += 4;
2007-12-08 22:42:33 +00:00
return LZMA_OK;
}
#endif
#ifdef HAVE_FILTER_DELTA
/// Encodes Filter Properties of the Delta filter
static lzma_ret
properties_delta(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_delta *options)
{
if (options == NULL)
return LZMA_PROG_ERROR;
// It's possible that newer liblzma versions will support larger
// distance values.
if (options->distance < LZMA_DELTA_DISTANCE_MIN
|| options->distance > LZMA_DELTA_DISTANCE_MAX)
return LZMA_HEADER_ERROR;
if (out_size - *out_pos < 1)
return LZMA_PROG_ERROR;
2007-12-08 22:42:33 +00:00
out[*out_pos] = options->distance - LZMA_DELTA_DISTANCE_MIN;
++*out_pos;
return LZMA_OK;
}
#endif
#ifdef HAVE_FILTER_LZMA
/// Encodes LZMA Properties and Dictionary Flags (two bytes)
static lzma_ret
properties_lzma(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_lzma *options)
{
if (options == NULL)
return LZMA_PROG_ERROR;
if (out_size - *out_pos < 2)
return LZMA_PROG_ERROR;
2007-12-08 22:42:33 +00:00
// LZMA Properties
if (lzma_lzma_encode_properties(options, out + *out_pos))
return LZMA_HEADER_ERROR;
++*out_pos;
// Dictionary flags
//
// Dictionary size is encoded using similar encoding that is used
// internally by LZMA.
2007-12-08 22:42:33 +00:00
//
// This won't work if dictionary size can be zero:
2007-12-08 22:42:33 +00:00
# if LZMA_DICTIONARY_SIZE_MIN < 1
# error LZMA_DICTIONARY_SIZE_MIN cannot be zero.
# endif
uint32_t d = options->dictionary_size;
2007-12-08 22:42:33 +00:00
// Validate it:
if (d < LZMA_DICTIONARY_SIZE_MIN || d > LZMA_DICTIONARY_SIZE_MAX)
2007-12-08 22:42:33 +00:00
return LZMA_HEADER_ERROR;
// Round up to to the next 2^n or 2^n + 2^(n - 1) depending on which
// one is the next:
--d;
d |= d >> 2;
d |= d >> 3;
d |= d >> 4;
d |= d >> 8;
d |= d >> 16;
++d;
// Get the highest two bits using the proper encoding:
out[*out_pos] = get_pos_slot(d) - 24;
2007-12-08 22:42:33 +00:00
++*out_pos;
return LZMA_OK;
}
#endif
extern LZMA_API lzma_ret
lzma_filter_flags_encode(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_filter *options)
{
// Minimum output is one byte (everything fits into Misc).
// The caller should have checked that there is enough output space,
// so we return LZMA_PROG_ERROR instead of LZMA_BUF_ERROR.
if (*out_pos >= out_size)
return LZMA_PROG_ERROR;
// Get size of Filter Properties.
uint32_t prop_size;
return_if_error(get_properties_size(&prop_size, options));
// Filter ID
return_if_error(lzma_vli_encode(options->id, NULL,
out, out_pos, out_size));
// Size of Properties
return_if_error(lzma_vli_encode(prop_size, NULL,
out, out_pos, out_size));
2007-12-08 22:42:33 +00:00
// Filter Properties
lzma_ret ret;
2007-12-08 22:42:33 +00:00
switch (options->id) {
#ifdef HAVE_FILTER_SUBBLOCK
case LZMA_FILTER_SUBBLOCK:
assert(prop_size == 0);
ret = LZMA_OK;
break;
#endif
#ifdef HAVE_FILTER_SIMPLE
# ifdef HAVE_FILTER_X86
case LZMA_FILTER_X86:
# endif
# ifdef HAVE_FILTER_POWERPC
case LZMA_FILTER_POWERPC:
# endif
# ifdef HAVE_FILTER_IA64
case LZMA_FILTER_IA64:
# endif
# ifdef HAVE_FILTER_ARM
case LZMA_FILTER_ARM:
# endif
# ifdef HAVE_FILTER_ARMTHUMB
case LZMA_FILTER_ARMTHUMB:
# endif
# ifdef HAVE_FILTER_SPARC
case LZMA_FILTER_SPARC:
# endif
ret = properties_simple(out, out_pos, out_size,
options->options);
break;
#endif
#ifdef HAVE_FILTER_DELTA
case LZMA_FILTER_DELTA:
ret = properties_delta(out, out_pos, out_size,
options->options);
break;
#endif
#ifdef HAVE_FILTER_LZMA
case LZMA_FILTER_LZMA:
ret = properties_lzma(out, out_pos, out_size,
options->options);
break;
#endif
default:
assert(0);
ret = LZMA_PROG_ERROR;
break;
}
return ret;
}