mirror of
https://git.tukaani.org/xz.git
synced 2024-04-04 12:36:23 +02:00
Improved the Stream Flags handling API.
This commit is contained in:
parent
ec490da522
commit
320601b2c7
8 changed files with 129 additions and 20 deletions
|
@ -35,9 +35,38 @@
|
||||||
* Options for encoding and decoding Stream Header and Stream Footer
|
* Options for encoding and decoding Stream Header and Stream Footer
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Stream Flags format version
|
||||||
|
*
|
||||||
|
* To prevent API and ABI breakages if new features are needed in
|
||||||
|
* Stream Header or Stream Footer, a version number is used to
|
||||||
|
* indicate which fields in this structure are in use. For now,
|
||||||
|
* version must always be zero. With non-zero version, the
|
||||||
|
* lzma_stream_header_encode() and lzma_stream_footer_encode()
|
||||||
|
* will return LZMA_HEADER_ERROR.
|
||||||
|
*
|
||||||
|
* lzma_stream_header_decode() and lzma_stream_footer_decode()
|
||||||
|
* will always set this to the lowest value that supports all the
|
||||||
|
* features indicated by the Stream Flags field. The application
|
||||||
|
* must check that the version number set by the decoding functions
|
||||||
|
* is supported by the application. Otherwise it is possible that
|
||||||
|
* the application will decode the Stream incorrectly.
|
||||||
|
*/
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backward Size must be a multiple of four bytes. In this Stream
|
* Backward Size must be a multiple of four bytes. In this Stream
|
||||||
* format version Backward Size is the size of the Index field.
|
* format version Backward Size is the size of the Index field.
|
||||||
|
*
|
||||||
|
* Backward Size isn't actually part of the Stream Flags field, but
|
||||||
|
* it is convenient to include in this structure anyway. Backward
|
||||||
|
* Size is present only in the Stream Footer. There is no need to
|
||||||
|
* initialize backward_size when encoding Stream Header.
|
||||||
|
*
|
||||||
|
* lzma_stream_header_decode() always sets backward_size to
|
||||||
|
* LZMA_VLI_VALUE_UNKNOWN so that it is convenient to use
|
||||||
|
* lzma_stream_flags_compare() when both Stream Header and Stream
|
||||||
|
* Footer have been decoded.
|
||||||
*/
|
*/
|
||||||
lzma_vli backward_size;
|
lzma_vli backward_size;
|
||||||
# define LZMA_BACKWARD_SIZE_MIN 4
|
# define LZMA_BACKWARD_SIZE_MIN 4
|
||||||
|
@ -48,6 +77,34 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
lzma_check check;
|
lzma_check check;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. You should not touch these, because the
|
||||||
|
* names of these variables may change.
|
||||||
|
*
|
||||||
|
* (We will never be able to use all of these since Stream Flags
|
||||||
|
* is just two bytes plus Backward Size of four bytes. But it's
|
||||||
|
* nice to have the proper types when they are needed.)
|
||||||
|
*/
|
||||||
|
lzma_reserved_enum reserved_enum1;
|
||||||
|
lzma_reserved_enum reserved_enum2;
|
||||||
|
lzma_reserved_enum reserved_enum3;
|
||||||
|
lzma_reserved_enum reserved_enum4;
|
||||||
|
lzma_reserved_enum reserved_enum5;
|
||||||
|
lzma_reserved_enum reserved_enum6;
|
||||||
|
lzma_bool reserved_bool1;
|
||||||
|
lzma_bool reserved_bool2;
|
||||||
|
lzma_bool reserved_bool3;
|
||||||
|
lzma_bool reserved_bool4;
|
||||||
|
lzma_bool reserved_bool5;
|
||||||
|
lzma_bool reserved_bool6;
|
||||||
|
lzma_bool reserved_bool7;
|
||||||
|
lzma_bool reserved_bool8;
|
||||||
|
uint32_t reserved_int1;
|
||||||
|
uint32_t reserved_int2;
|
||||||
|
uint32_t reserved_int3;
|
||||||
|
uint32_t reserved_int4;
|
||||||
|
|
||||||
} lzma_stream_flags;
|
} lzma_stream_flags;
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,6 +118,8 @@ typedef struct {
|
||||||
* need to be initialized.
|
* need to be initialized.
|
||||||
*
|
*
|
||||||
* \return - LZMA_OK: Encoding was successful.
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_HEADER_ERROR: options->version is not supported by
|
||||||
|
* this liblzma version.
|
||||||
* - LZMA_PROG_ERROR: Invalid options.
|
* - LZMA_PROG_ERROR: Invalid options.
|
||||||
*/
|
*/
|
||||||
extern lzma_ret lzma_stream_header_encode(
|
extern lzma_ret lzma_stream_header_encode(
|
||||||
|
@ -76,6 +135,8 @@ extern lzma_ret lzma_stream_header_encode(
|
||||||
* \param options Stream Footer options to be encoded.
|
* \param options Stream Footer options to be encoded.
|
||||||
*
|
*
|
||||||
* \return - LZMA_OK: Encoding was successful.
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_HEADER_ERROR: options->version is not supported by
|
||||||
|
* this liblzma version.
|
||||||
* - LZMA_PROG_ERROR: Invalid options.
|
* - LZMA_PROG_ERROR: Invalid options.
|
||||||
*/
|
*/
|
||||||
extern lzma_ret lzma_stream_footer_encode(
|
extern lzma_ret lzma_stream_footer_encode(
|
||||||
|
@ -92,7 +153,7 @@ extern lzma_ret lzma_stream_footer_encode(
|
||||||
*
|
*
|
||||||
* options->index_size is always set to LZMA_VLI_VALUE_UNKNOWN. This is to
|
* options->index_size is always set to LZMA_VLI_VALUE_UNKNOWN. This is to
|
||||||
* help comparing Stream Flags from Stream Header and Stream Footer with
|
* help comparing Stream Flags from Stream Header and Stream Footer with
|
||||||
* lzma_stream_flags_equal().
|
* lzma_stream_flags_compare().
|
||||||
*
|
*
|
||||||
* \return - LZMA_OK: Decoding was successful.
|
* \return - LZMA_OK: Decoding was successful.
|
||||||
* - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
|
* - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
|
||||||
|
@ -121,6 +182,13 @@ extern lzma_ret lzma_stream_header_decode(
|
||||||
* is corrupt.
|
* is corrupt.
|
||||||
* - LZMA_HEADER_ERROR: Unsupported options are present
|
* - LZMA_HEADER_ERROR: Unsupported options are present
|
||||||
* in the footer.
|
* in the footer.
|
||||||
|
*
|
||||||
|
* \note If Stream Header was already decoded successfully, but
|
||||||
|
* decoding Stream Footer returns LZMA_FORMAT_ERROR, the
|
||||||
|
* application should probably report some other error message
|
||||||
|
* than "unsupported file format", since the file more likely is
|
||||||
|
* corrupt (possibly truncated). Stream decoder in liblzma uses
|
||||||
|
* LZMA_DATA_ERROR in this situation.
|
||||||
*/
|
*/
|
||||||
extern lzma_ret lzma_stream_footer_decode(
|
extern lzma_ret lzma_stream_footer_decode(
|
||||||
lzma_stream_flags *options, const uint8_t *in)
|
lzma_stream_flags *options, const uint8_t *in)
|
||||||
|
@ -130,10 +198,18 @@ extern lzma_ret lzma_stream_footer_decode(
|
||||||
/**
|
/**
|
||||||
* \brief Compare two lzma_stream_flags structures
|
* \brief Compare two lzma_stream_flags structures
|
||||||
*
|
*
|
||||||
* index_size values are compared only if both are not LZMA_VLI_VALUE_UNKNOWN.
|
* backward_size values are compared only if both are not
|
||||||
|
* LZMA_VLI_VALUE_UNKNOWN.
|
||||||
*
|
*
|
||||||
* \return true if both structures are considered equal; false otherwise.
|
* \return - LZMA_OK: Both are equal. If either had backward_size set
|
||||||
|
* to LZMA_VLI_VALUE_UNKNOWN, backward_size values were not
|
||||||
|
* compared or validated.
|
||||||
|
* - LZMA_DATA_ERROR: The structures differ.
|
||||||
|
* - LZMA_HEADER_ERROR: version in either structure is greater
|
||||||
|
* than the maximum supported version (currently zero).
|
||||||
|
* - LZMA_PROG_ERROR: Invalid value, e.g. invalid check or
|
||||||
|
* backward_size.
|
||||||
*/
|
*/
|
||||||
extern lzma_bool lzma_stream_flags_equal(
|
extern lzma_ret lzma_stream_flags_compare(
|
||||||
const lzma_stream_flags *a, const lzma_stream_flags *b)
|
const lzma_stream_flags *a, const lzma_stream_flags *b)
|
||||||
lzma_attr_pure;
|
lzma_attr_pure;
|
||||||
|
|
|
@ -294,9 +294,8 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator,
|
||||||
|
|
||||||
// Compare that the Stream Flags fields are identical in
|
// Compare that the Stream Flags fields are identical in
|
||||||
// both Stream Header and Stream Footer.
|
// both Stream Header and Stream Footer.
|
||||||
if (!lzma_stream_flags_equal(&coder->stream_flags,
|
return_if_error(lzma_stream_flags_compare(
|
||||||
&footer_flags))
|
&coder->stream_flags, &footer_flags));
|
||||||
return LZMA_DATA_ERROR;
|
|
||||||
|
|
||||||
if (!coder->concatenated)
|
if (!coder->concatenated)
|
||||||
return LZMA_STREAM_END;
|
return LZMA_STREAM_END;
|
||||||
|
|
|
@ -180,6 +180,7 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator,
|
||||||
|
|
||||||
// Encode the Stream Footer into coder->buffer.
|
// Encode the Stream Footer into coder->buffer.
|
||||||
const lzma_stream_flags stream_flags = {
|
const lzma_stream_flags stream_flags = {
|
||||||
|
.version = 0,
|
||||||
.backward_size = lzma_index_size(coder->index),
|
.backward_size = lzma_index_size(coder->index),
|
||||||
.check = coder->block_options.check,
|
.check = coder->block_options.check,
|
||||||
};
|
};
|
||||||
|
@ -247,6 +248,7 @@ lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
|
|
||||||
// Encode the Stream Header
|
// Encode the Stream Header
|
||||||
lzma_stream_flags stream_flags = {
|
lzma_stream_flags stream_flags = {
|
||||||
|
.version = 0,
|
||||||
.check = check,
|
.check = check,
|
||||||
};
|
};
|
||||||
return_if_error(lzma_stream_header_encode(
|
return_if_error(lzma_stream_header_encode(
|
||||||
|
|
|
@ -24,17 +24,31 @@ const uint8_t lzma_header_magic[6] = { 0xFF, 0x4C, 0x5A, 0x4D, 0x41, 0x00 };
|
||||||
const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A };
|
const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A };
|
||||||
|
|
||||||
|
|
||||||
extern LZMA_API lzma_bool
|
extern LZMA_API lzma_ret
|
||||||
lzma_stream_flags_equal(const lzma_stream_flags *a, const lzma_stream_flags *b)
|
lzma_stream_flags_compare(
|
||||||
|
const lzma_stream_flags *a, const lzma_stream_flags *b)
|
||||||
{
|
{
|
||||||
|
// We can compare only version 0 structures.
|
||||||
|
if (a->version != 0 || b->version != 0)
|
||||||
|
return LZMA_HEADER_ERROR;
|
||||||
|
|
||||||
|
// Check type
|
||||||
|
if ((unsigned int)(a->check) > LZMA_CHECK_ID_MAX
|
||||||
|
|| (unsigned int)(b->check) > LZMA_CHECK_ID_MAX)
|
||||||
|
return LZMA_PROG_ERROR;
|
||||||
|
|
||||||
if (a->check != b->check)
|
if (a->check != b->check)
|
||||||
return false;
|
return LZMA_DATA_ERROR;
|
||||||
|
|
||||||
// Backward Sizes are compared only if they are known in both.
|
// Backward Sizes are compared only if they are known in both.
|
||||||
if (a->backward_size != LZMA_VLI_VALUE_UNKNOWN
|
if (a->backward_size != LZMA_VLI_VALUE_UNKNOWN
|
||||||
&& b->backward_size != LZMA_VLI_VALUE_UNKNOWN
|
&& b->backward_size != LZMA_VLI_VALUE_UNKNOWN) {
|
||||||
&& a->backward_size != b->backward_size)
|
if (!is_backward_size_valid(a) || !is_backward_size_valid(b))
|
||||||
return false;
|
return LZMA_PROG_ERROR;
|
||||||
|
|
||||||
return true;
|
if (a->backward_size != b->backward_size)
|
||||||
|
return LZMA_DATA_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LZMA_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,4 +28,13 @@
|
||||||
extern const uint8_t lzma_header_magic[6];
|
extern const uint8_t lzma_header_magic[6];
|
||||||
extern const uint8_t lzma_footer_magic[2];
|
extern const uint8_t lzma_footer_magic[2];
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_backward_size_valid(const lzma_stream_flags *options)
|
||||||
|
{
|
||||||
|
return options->backward_size >= LZMA_BACKWARD_SIZE_MIN
|
||||||
|
&& options->backward_size <= LZMA_BACKWARD_SIZE_MAX
|
||||||
|
&& (options->backward_size & 3) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,6 +27,7 @@ stream_flags_decode(lzma_stream_flags *options, const uint8_t *in)
|
||||||
if (in[0] != 0x00 || (in[1] & 0xF0))
|
if (in[0] != 0x00 || (in[1] & 0xF0))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
options->version = 0;
|
||||||
options->check = in[1] & 0x0F;
|
options->check = in[1] & 0x0F;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -53,7 +54,7 @@ lzma_stream_header_decode(lzma_stream_flags *options, const uint8_t *in)
|
||||||
return LZMA_HEADER_ERROR;
|
return LZMA_HEADER_ERROR;
|
||||||
|
|
||||||
// Set Backward Size to indicate unknown value. That way
|
// Set Backward Size to indicate unknown value. That way
|
||||||
// lzma_stream_flags_equal can be used to compare Stream Header
|
// lzma_stream_flags_compare() can be used to compare Stream Header
|
||||||
// and Stream Footer while keeping it useful also for comparing
|
// and Stream Footer while keeping it useful also for comparing
|
||||||
// two Stream Footers.
|
// two Stream Footers.
|
||||||
options->backward_size = LZMA_VLI_VALUE_UNKNOWN;
|
options->backward_size = LZMA_VLI_VALUE_UNKNOWN;
|
||||||
|
|
|
@ -39,6 +39,9 @@ lzma_stream_header_encode(const lzma_stream_flags *options, uint8_t *out)
|
||||||
assert(sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE
|
assert(sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE
|
||||||
+ 4 == LZMA_STREAM_HEADER_SIZE);
|
+ 4 == LZMA_STREAM_HEADER_SIZE);
|
||||||
|
|
||||||
|
if (options->version != 0)
|
||||||
|
return LZMA_HEADER_ERROR;
|
||||||
|
|
||||||
// Magic
|
// Magic
|
||||||
memcpy(out, lzma_header_magic, sizeof(lzma_header_magic));
|
memcpy(out, lzma_header_magic, sizeof(lzma_header_magic));
|
||||||
|
|
||||||
|
@ -63,10 +66,11 @@ lzma_stream_footer_encode(const lzma_stream_flags *options, uint8_t *out)
|
||||||
assert(2 * 4 + LZMA_STREAM_FLAGS_SIZE + sizeof(lzma_footer_magic)
|
assert(2 * 4 + LZMA_STREAM_FLAGS_SIZE + sizeof(lzma_footer_magic)
|
||||||
== LZMA_STREAM_HEADER_SIZE);
|
== LZMA_STREAM_HEADER_SIZE);
|
||||||
|
|
||||||
|
if (options->version != 0)
|
||||||
|
return LZMA_HEADER_ERROR;
|
||||||
|
|
||||||
// Backward Size
|
// Backward Size
|
||||||
if (options->backward_size < LZMA_BACKWARD_SIZE_MIN
|
if (!is_backward_size_valid(options))
|
||||||
|| options->backward_size > LZMA_BACKWARD_SIZE_MAX
|
|
||||||
|| (options->backward_size & 3))
|
|
||||||
return LZMA_PROG_ERROR;
|
return LZMA_PROG_ERROR;
|
||||||
|
|
||||||
integer_write_32(out + 4, options->backward_size / 4 - 1);
|
integer_write_32(out + 4, options->backward_size / 4 - 1);
|
||||||
|
|
|
@ -28,7 +28,11 @@ static uint8_t buffer[LZMA_STREAM_HEADER_SIZE];
|
||||||
static bool
|
static bool
|
||||||
validate(void)
|
validate(void)
|
||||||
{
|
{
|
||||||
return !lzma_stream_flags_equal(&known_flags, &decoded_flags);
|
// TODO: This could require the specific error type as an argument.
|
||||||
|
// We could also test that lzma_stream_flags_compare() gives
|
||||||
|
// the correct return values in different situations.
|
||||||
|
return lzma_stream_flags_compare(&known_flags, &decoded_flags)
|
||||||
|
!= LZMA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ test_header_decoder(lzma_ret expected_ret)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Header doesn't have Backward Size, so make
|
// Header doesn't have Backward Size, so make
|
||||||
// lzma_stream_flags_equal() ignore it.
|
// lzma_stream_flags_compare() ignore it.
|
||||||
decoded_flags.backward_size = LZMA_VLI_VALUE_UNKNOWN;
|
decoded_flags.backward_size = LZMA_VLI_VALUE_UNKNOWN;
|
||||||
return validate();
|
return validate();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue