aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/block_header_encoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/liblzma/common/block_header_encoder.c')
-rw-r--r--src/liblzma/common/block_header_encoder.c207
1 files changed, 74 insertions, 133 deletions
diff --git a/src/liblzma/common/block_header_encoder.c b/src/liblzma/common/block_header_encoder.c
index 594b4fc0..ed0c88ba 100644
--- a/src/liblzma/common/block_header_encoder.c
+++ b/src/liblzma/common/block_header_encoder.c
@@ -24,188 +24,129 @@
extern LZMA_API lzma_ret
lzma_block_header_size(lzma_options_block *options)
{
- // Block Flags take two bytes.
- size_t size = 2;
+ // Block Header Size + Block Flags + CRC32.
+ size_t size = 1 + 1 + 4;
// Compressed Size
- if (!lzma_vli_is_valid(options->compressed_size)) {
- return LZMA_PROG_ERROR;
-
- } else if (options->compressed_reserve != 0) {
- // Make sure that the known Compressed Size fits into the
- // reserved space. Note that lzma_vli_size() will return zero
- // if options->compressed_size is LZMA_VLI_VALUE_UNKNOWN, so
- // we don't need to handle that special case separately.
- if (options->compressed_reserve > LZMA_VLI_BYTES_MAX
- || lzma_vli_size(options->compressed_size)
- > (size_t)(options->compressed_reserve))
+ if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ if (options->compressed_size > LZMA_VLI_VALUE_MAX / 4 - 1
+ || options->compressed_size == 0
+ || (options->compressed_size & 3))
return LZMA_PROG_ERROR;
- size += options->compressed_reserve;
-
- } else if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
- // Compressed Size is known. We have already checked
- // that is is a valid VLI, and since it isn't
- // LZMA_VLI_VALUE_UNKNOWN, we can be sure that
- // lzma_vli_size() will succeed.
- size += lzma_vli_size(options->compressed_size);
+ size += lzma_vli_size(options->compressed_size / 4 - 1);
}
// Uncompressed Size
- if (!lzma_vli_is_valid(options->uncompressed_size)) {
- return LZMA_PROG_ERROR;
-
- } else if (options->uncompressed_reserve != 0) {
- if (options->uncompressed_reserve > LZMA_VLI_BYTES_MAX
- || lzma_vli_size(options->uncompressed_size)
- > (size_t)(options->uncompressed_reserve))
+ if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ const size_t add = lzma_vli_size(options->uncompressed_size);
+ if (add == 0)
return LZMA_PROG_ERROR;
- size += options->uncompressed_reserve;
-
- } else if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
- size += lzma_vli_size(options->uncompressed_size);
+ size += add;
}
// List of Filter Flags
+ if (options->filters == NULL
+ || options->filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
+ return LZMA_PROG_ERROR;
+
for (size_t i = 0; options->filters[i].id != LZMA_VLI_VALUE_UNKNOWN;
++i) {
// Don't allow too many filters.
- if (i == 7)
+ if (i == 4)
return LZMA_PROG_ERROR;
- uint32_t tmp;
- const lzma_ret ret = lzma_filter_flags_size(&tmp,
- options->filters + i);
- if (ret != LZMA_OK)
- return ret;
+ uint32_t add;
+ return_if_error(lzma_filter_flags_size(&add,
+ options->filters + i));
- size += tmp;
+ size += add;
}
- // CRC32
- if (options->has_crc32)
- size += 4;
-
- // Padding
- int32_t padding;
- if (options->padding == LZMA_BLOCK_HEADER_PADDING_AUTO) {
- const uint32_t preferred = lzma_alignment_output(
- options->filters, 1);
- const uint32_t unaligned = size + options->alignment;
- padding = (int32_t)(unaligned % preferred);
- if (padding != 0)
- padding = preferred - padding;
- } else if (options->padding >= LZMA_BLOCK_HEADER_PADDING_MIN
- && options->padding <= LZMA_BLOCK_HEADER_PADDING_MAX) {
- padding = options->padding;
- } else {
- return LZMA_PROG_ERROR;
- }
+ // Pad to a multiple of four bytes.
+ options->header_size = (size + 3) & ~(size_t)(3);
- // All success. Copy the calculated values to the options structure.
- options->padding = padding;
- options->header_size = size + (size_t)(padding);
+ // NOTE: We don't verify that Total Size of the Block stays within
+ // limits. This is because it is possible that we are called with
+ // exaggerated values to reserve space for Block Header, and later
+ // called again with lower, real values.
return LZMA_OK;
}
extern LZMA_API lzma_ret
-lzma_block_header_encode(uint8_t *out, const lzma_options_block *options)
+lzma_block_header_encode(const lzma_options_block *options, uint8_t *out)
{
- // We write the Block Flags later.
- if (options->header_size < 2)
+ if ((options->header_size & 3)
+ || options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
+ || options->header_size > LZMA_BLOCK_HEADER_SIZE_MAX)
return LZMA_PROG_ERROR;
- const size_t out_size = options->header_size;
+ // Indicate the size of the buffer _excluding_ the CRC32 field.
+ const size_t out_size = options->header_size - 4;
+
+ // Store the Block Header Size.
+ out[0] = out_size / 4;
+
+ // We write Block Flags a little later.
size_t out_pos = 2;
// Compressed Size
- if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
- || options->compressed_reserve != 0) {
- const lzma_vli size = options->compressed_size
- != LZMA_VLI_VALUE_UNKNOWN
- ? options->compressed_size : 0;
- size_t vli_pos = 0;
- if (lzma_vli_encode(
- size, &vli_pos, options->compressed_reserve,
- out, &out_pos, out_size) != LZMA_STREAM_END)
+ if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ // Compressed Size must be non-zero, fit into a 63-bit
+ // integer and be a multiple of four. Also the Total Size
+ // of the Block must fit into 63-bit integer.
+ if (options->compressed_size == 0
+ || (options->compressed_size & 3)
+ || options->compressed_size
+ > LZMA_VLI_VALUE_MAX
+ || lzma_block_total_size_get(options) == 0)
return LZMA_PROG_ERROR;
+ return_if_error(lzma_vli_encode(
+ options->compressed_size / 4 - 1, NULL,
+ out, &out_pos, out_size));
}
// Uncompressed Size
- if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
- || options->uncompressed_reserve != 0) {
- const lzma_vli size = options->uncompressed_size
- != LZMA_VLI_VALUE_UNKNOWN
- ? options->uncompressed_size : 0;
- size_t vli_pos = 0;
- if (lzma_vli_encode(
- size, &vli_pos, options->uncompressed_reserve,
- out, &out_pos, out_size) != LZMA_STREAM_END)
- return LZMA_PROG_ERROR;
-
- }
+ if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
+ return_if_error(lzma_vli_encode(
+ options->uncompressed_size, NULL,
+ out, &out_pos, out_size));
// Filter Flags
- size_t filter_count;
- for (filter_count = 0; options->filters[filter_count].id
- != LZMA_VLI_VALUE_UNKNOWN; ++filter_count) {
- // There can be at maximum of seven filters.
- if (filter_count == 7)
- return LZMA_PROG_ERROR;
-
- const lzma_ret ret = lzma_filter_flags_encode(out, &out_pos,
- out_size, options->filters + filter_count);
- // FIXME: Don't return LZMA_BUF_ERROR.
- if (ret != LZMA_OK)
- return ret;
- }
-
- // Block Flags 1
- out[0] = filter_count;
-
- if (options->has_eopm)
- out[0] |= 0x08;
- else if (options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
+ if (options->filters == NULL
+ || options->filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_PROG_ERROR;
- if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
- || options->compressed_reserve != 0)
- out[0] |= 0x10;
-
- if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
- || options->uncompressed_reserve != 0)
- out[0] |= 0x20;
+ size_t filter_count = 0;
+ do {
+ // There can be at maximum of four filters.
+ if (filter_count == 4)
+ return LZMA_PROG_ERROR;
- if (options->is_metadata)
- out[0] |= 0x80;
+ return_if_error(lzma_filter_flags_encode(out, &out_pos,
+ out_size, options->filters + filter_count));
- // Block Flags 2
- if (options->padding < LZMA_BLOCK_HEADER_PADDING_MIN
- || options->padding > LZMA_BLOCK_HEADER_PADDING_MAX)
- return LZMA_PROG_ERROR;
+ } while (options->filters[++filter_count].id
+ != LZMA_VLI_VALUE_UNKNOWN);
- out[1] = (uint8_t)(options->padding);
+ // Block Flags
+ out[1] = filter_count - 1;
- // CRC32
- if (options->has_crc32) {
- if (out_size - out_pos < 4)
- return LZMA_PROG_ERROR;
+ if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN)
+ out[1] |= 0x40;
- const uint32_t crc = lzma_crc32(out, out_pos, 0);
- for (size_t i = 0; i < 4; ++i)
- out[out_pos++] = crc >> (i * 8);
- }
+ if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
+ out[1] |= 0x80;
- // Padding - the amount of available space must now match with
- // the size of the Padding field.
- if (out_size - out_pos != (size_t)(options->padding))
- return LZMA_PROG_ERROR;
+ // Padding
+ memzero(out + out_pos, out_size - out_pos);
- memzero(out + out_pos, (size_t)(options->padding));
+ // CRC32
+ integer_write_32(out + out_size, lzma_crc32(out, out_size, 0));
return LZMA_OK;
}