Improved the Stream Flags handling API.

This commit is contained in:
Lasse Collin 2008-09-12 22:41:40 +03:00
parent ec490da522
commit 320601b2c7
8 changed files with 129 additions and 20 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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(

View File

@ -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;
} }

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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();
} }