aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/stream_flags_decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/liblzma/common/stream_flags_decoder.c')
-rw-r--r--src/liblzma/common/stream_flags_decoder.c260
1 files changed, 45 insertions, 215 deletions
diff --git a/src/liblzma/common/stream_flags_decoder.c b/src/liblzma/common/stream_flags_decoder.c
index d9c847ac..0270875a 100644
--- a/src/liblzma/common/stream_flags_decoder.c
+++ b/src/liblzma/common/stream_flags_decoder.c
@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file stream_flags_decoder.c
-/// \brief Decodes Stream Header and tail from .lzma files
+/// \brief Decodes Stream Header and Stream Footer from .lzma files
//
// Copyright (C) 2007 Lasse Collin
//
@@ -17,242 +17,72 @@
//
///////////////////////////////////////////////////////////////////////////////
-#include "stream_flags_decoder.h"
#include "stream_common.h"
-////////////
-// Common //
-////////////
-
-struct lzma_coder_s {
- enum {
- SEQ_HEADER_MAGIC,
- SEQ_HEADER_FLAGS,
- SEQ_HEADER_CRC32,
-
- SEQ_FOOTER_FLAGS,
- SEQ_FOOTER_MAGIC,
- } sequence;
-
- size_t pos;
- uint32_t crc32;
-
- lzma_stream_flags *options;
-};
-
-
-static void
-stream_header_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
-{
- lzma_free(coder, allocator);
- return;
-}
-
-
static bool
-stream_flags_decode(const uint8_t *in, lzma_stream_flags *options)
+stream_flags_decode(lzma_stream_flags *options, const uint8_t *in)
{
// Reserved bits must be unset.
- if (*in & 0xE0)
+ if (in[0] != 0x00 || (in[1] & 0xF0))
return true;
- options->check = *in & 0x07;
- options->has_crc32 = (*in & 0x08) != 0;
- options->is_multi = (*in & 0x10) != 0;
+ options->check = in[1] & 0x0F;
return false;
}
-////////////
-// Header //
-////////////
-
-static lzma_ret
-stream_header_decode(lzma_coder *coder,
- lzma_allocator *allocator lzma_attribute((unused)),
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
- size_t *restrict out_pos lzma_attribute((unused)),
- size_t out_size lzma_attribute((unused)),
- lzma_action action lzma_attribute((unused)))
-{
- while (*in_pos < in_size)
- switch (coder->sequence) {
- case SEQ_HEADER_MAGIC:
- if (in[*in_pos] != lzma_header_magic[coder->pos])
- return LZMA_DATA_ERROR;
-
- ++*in_pos;
-
- if (++coder->pos == sizeof(lzma_header_magic)) {
- coder->pos = 0;
- coder->sequence = SEQ_HEADER_FLAGS;
- }
-
- break;
-
- case SEQ_HEADER_FLAGS:
- if (stream_flags_decode(in + *in_pos, coder->options))
- return LZMA_HEADER_ERROR;
-
- coder->crc32 = lzma_crc32(in + *in_pos, 1, 0);
-
- ++*in_pos;
- coder->sequence = SEQ_HEADER_CRC32;
- break;
-
- case SEQ_HEADER_CRC32:
- if (in[*in_pos] != ((coder->crc32 >> (coder->pos * 8)) & 0xFF))
- return LZMA_DATA_ERROR;
-
- ++*in_pos;
-
- if (++coder->pos == 4)
- return LZMA_STREAM_END;
-
- break;
-
- default:
- return LZMA_PROG_ERROR;
- }
-
- return LZMA_OK;
-}
-
-
-static lzma_ret
-stream_header_decoder_init(lzma_next_coder *next,
- lzma_allocator *allocator, lzma_stream_flags *options)
-{
- if (options == NULL)
- return LZMA_PROG_ERROR;
-
- if (next->coder == NULL) {
- next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
- if (next->coder == NULL)
- return LZMA_MEM_ERROR;
- }
-
- // Set the function pointers unconditionally, because they may
- // have been pointing to footer decoder too.
- next->code = &stream_header_decode;
- next->end = &stream_header_decoder_end;
-
- next->coder->sequence = SEQ_HEADER_MAGIC;
- next->coder->pos = 0;
- next->coder->crc32 = 0;
- next->coder->options = options;
-
- return LZMA_OK;
-}
-
-
-extern lzma_ret
-lzma_stream_header_decoder_init(lzma_next_coder *next,
- lzma_allocator *allocator, lzma_stream_flags *options)
-{
- lzma_next_coder_init(
- stream_header_decoder_init, next, allocator, options);
-}
-
-
extern LZMA_API lzma_ret
-lzma_stream_header_decoder(lzma_stream *strm, lzma_stream_flags *options)
-{
- lzma_next_strm_init(strm, stream_header_decoder_init, options);
-
- strm->internal->supported_actions[LZMA_RUN] = true;
-
- return LZMA_OK;
-}
-
-
-//////////
-// Tail //
-//////////
-
-static lzma_ret
-stream_tail_decode(lzma_coder *coder,
- lzma_allocator *allocator lzma_attribute((unused)),
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
- size_t *restrict out_pos lzma_attribute((unused)),
- size_t out_size lzma_attribute((unused)),
- lzma_action action lzma_attribute((unused)))
-{
- while (*in_pos < in_size)
- switch (coder->sequence) {
- case SEQ_FOOTER_FLAGS:
- if (stream_flags_decode(in + *in_pos, coder->options))
- return LZMA_HEADER_ERROR;
-
- ++*in_pos;
- coder->sequence = SEQ_FOOTER_MAGIC;
- break;
-
- case SEQ_FOOTER_MAGIC:
- if (in[*in_pos] != lzma_footer_magic[coder->pos])
- return LZMA_DATA_ERROR;
-
- ++*in_pos;
-
- if (++coder->pos == sizeof(lzma_footer_magic))
- return LZMA_STREAM_END;
-
- break;
-
- default:
- return LZMA_PROG_ERROR;
- }
-
- return LZMA_OK;
-}
-
-
-static lzma_ret
-stream_tail_decoder_init(lzma_next_coder *next,
- lzma_allocator *allocator, lzma_stream_flags *options)
+lzma_stream_header_decode(lzma_stream_flags *options, const uint8_t *in)
{
- if (options == NULL)
- return LZMA_PROG_ERROR;
-
- if (next->coder == NULL) {
- next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
- if (next->coder == NULL)
- return LZMA_MEM_ERROR;
- }
-
- // Set the function pointers unconditionally, because they may
- // have been pointing to footer decoder too.
- next->code = &stream_tail_decode;
- next->end = &stream_header_decoder_end;
-
- next->coder->sequence = SEQ_FOOTER_FLAGS;
- next->coder->pos = 0;
- next->coder->options = options;
+ // Magic
+ if (memcmp(in, lzma_header_magic, sizeof(lzma_header_magic)) != 0)
+ return LZMA_FORMAT_ERROR;
+
+ // Verify the CRC32 so we can distinguish between corrupt
+ // and unsupported files.
+ const uint32_t crc = lzma_crc32(in + sizeof(lzma_header_magic),
+ LZMA_STREAM_FLAGS_SIZE, 0);
+ if (crc != integer_read_32(in + sizeof(lzma_header_magic)
+ + LZMA_STREAM_FLAGS_SIZE))
+ return LZMA_DATA_ERROR;
+
+ // Stream Flags
+ if (stream_flags_decode(options, in + sizeof(lzma_header_magic)))
+ return LZMA_HEADER_ERROR;
+
+ // Set Backward Size to indicate unknown value. That way
+ // lzma_stream_flags_equal can be used to compare Stream Header
+ // and Stream Footer while keeping it useful also for comparing
+ // two Stream Footers.
+ options->backward_size = LZMA_VLI_VALUE_UNKNOWN;
return LZMA_OK;
}
-extern lzma_ret
-lzma_stream_tail_decoder_init(lzma_next_coder *next,
- lzma_allocator *allocator, lzma_stream_flags *options)
-{
- lzma_next_coder_init2(next, allocator, stream_header_decoder_init,
- stream_tail_decoder_init, allocator, options);
-}
-
-
extern LZMA_API lzma_ret
-lzma_stream_tail_decoder(lzma_stream *strm, lzma_stream_flags *options)
+lzma_stream_footer_decode(lzma_stream_flags *options, const uint8_t *in)
{
- lzma_next_strm_init2(strm, stream_header_decoder_init,
- stream_tail_decoder_init, strm->allocator, options);
-
- strm->internal->supported_actions[LZMA_RUN] = true;
+ // Magic
+ if (memcmp(in + sizeof(uint32_t) * 2 + LZMA_STREAM_FLAGS_SIZE,
+ lzma_footer_magic, sizeof(lzma_footer_magic)) != 0)
+ return LZMA_FORMAT_ERROR;
+
+ // CRC32
+ const uint32_t crc = lzma_crc32(in + sizeof(uint32_t),
+ sizeof(uint32_t) + LZMA_STREAM_FLAGS_SIZE, 0);
+ if (crc != integer_read_32(in))
+ return LZMA_DATA_ERROR;
+
+ // Stream Flags
+ if (stream_flags_decode(options, in + sizeof(uint32_t) * 2))
+ return LZMA_HEADER_ERROR;
+
+ // Backward Size
+ options->backward_size = integer_read_32(in + sizeof(uint32_t));
+ options->backward_size = (options->backward_size + 1) * 4;
return LZMA_OK;
}