diff options
author | Lasse Collin <lasse.collin@tukaani.org> | 2008-08-28 22:53:15 +0300 |
---|---|---|
committer | Lasse Collin <lasse.collin@tukaani.org> | 2008-08-28 22:53:15 +0300 |
commit | 3b34851de1eaf358cf9268922fa0eeed8278d680 (patch) | |
tree | 7bab212af647541df64227a8d350d17a2e789f6b /src/liblzma/common | |
parent | Fix test_filter_flags to match the new restriction of lc+lp. (diff) | |
download | xz-3b34851de1eaf358cf9268922fa0eeed8278d680.tar.xz |
Sort of garbage collection commit. :-| Many things are still
broken. API has changed a lot and it will still change a
little more here and there. The command line tool doesn't
have all the required changes to reflect the API changes, so
it's easy to get "internal error" or trigger assertions.
Diffstat (limited to 'src/liblzma/common')
54 files changed, 1583 insertions, 1900 deletions
diff --git a/src/liblzma/common/Makefile.am b/src/liblzma/common/Makefile.am index 40b42250..3ec2e270 100644 --- a/src/liblzma/common/Makefile.am +++ b/src/liblzma/common/Makefile.am @@ -16,62 +16,43 @@ noinst_LTLIBRARIES = libcommon.la libcommon_la_CPPFLAGS = \ -I@top_srcdir@/src/liblzma/api \ -I@top_srcdir@/src/liblzma/check \ + -I@top_srcdir@/src/liblzma/rangecoder \ -I@top_srcdir@/src/liblzma/lz \ -I@top_srcdir@/src/liblzma/lzma \ - -I@top_srcdir@/src/liblzma/simple \ -I@top_srcdir@/src/liblzma/subblock \ - -I@top_srcdir@/src/liblzma/rangecoder + -I@top_srcdir@/src/liblzma/delta \ + -I@top_srcdir@/src/liblzma/simple + libcommon_la_SOURCES = \ + common.c \ common.h \ bsr.h \ - allocator.c \ block_util.c \ block_private.h \ - features.c \ + filter_common.c \ + filter_common.h \ index.c \ + index.h \ init.c \ memory_limiter.c \ - memory_usage.c \ - next_coder.c \ - raw_common.c \ - raw_common.h \ - stream_flags_equal.c \ - code.c \ - version.c - -if COND_FILTER_DELTA -libcommon_la_SOURCES += \ - delta_common.c \ - delta_common.h -if COND_MAIN_ENCODER -libcommon_la_SOURCES += \ - delta_encoder.c \ - delta_encoder.h -endif -if COND_MAIN_DECODER -libcommon_la_SOURCES += \ - delta_decoder.c \ - delta_decoder.h -endif -endif + stream_flags_common.c \ + stream_flags_common.h \ + vli_size.c if COND_MAIN_ENCODER libcommon_la_SOURCES += \ alignment.c \ - auto_decoder.c \ alone_encoder.c \ block_encoder.c \ block_encoder.h \ block_header_encoder.c \ easy.c \ + filter_encoder.c \ + filter_encoder.h \ filter_flags_encoder.c \ index_encoder.c \ index_encoder.h \ init_encoder.c \ - raw_encoder.c \ - raw_encoder.h \ - stream_common.c \ - stream_common.h \ stream_encoder.c \ stream_encoder.h \ stream_flags_encoder.c \ @@ -82,16 +63,18 @@ if COND_MAIN_DECODER libcommon_la_SOURCES += \ alone_decoder.c \ alone_decoder.h \ + auto_decoder.c \ block_decoder.c \ block_decoder.h \ block_header_decoder.c \ + filter_decoder.c \ + filter_decoder.h \ filter_flags_decoder.c \ index_decoder.c \ index_hash.c \ init_decoder.c \ - raw_decoder.c \ - raw_decoder.h \ stream_decoder.c \ + stream_decoder.h \ stream_flags_decoder.c \ stream_flags_decoder.h \ vli_decoder.c diff --git a/src/liblzma/common/alignment.c b/src/liblzma/common/alignment.c index c80e5fab..ba9ecb03 100644 --- a/src/liblzma/common/alignment.c +++ b/src/liblzma/common/alignment.c @@ -21,7 +21,7 @@ extern LZMA_API uint32_t -lzma_alignment_input(const lzma_options_filter *filters, uint32_t guess) +lzma_alignment_input(const lzma_filter *filters, uint32_t guess) { for (size_t i = 0; filters[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) { switch (filters[i].id) { @@ -66,7 +66,7 @@ lzma_alignment_input(const lzma_options_filter *filters, uint32_t guess) extern LZMA_API uint32_t -lzma_alignment_output(const lzma_options_filter *filters, uint32_t guess) +lzma_alignment_output(const lzma_filter *filters, uint32_t guess) { if (filters[0].id == LZMA_VLI_VALUE_UNKNOWN) return UINT32_MAX; diff --git a/src/liblzma/common/allocator.c b/src/liblzma/common/allocator.c deleted file mode 100644 index 5ced9d16..00000000 --- a/src/liblzma/common/allocator.c +++ /dev/null @@ -1,58 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file allocator.c -/// \brief Allocating and freeing memory -// -// 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" - -#undef lzma_free - -extern void * lzma_attribute((malloc)) -lzma_alloc(size_t size, lzma_allocator *allocator) -{ - // Some malloc() variants return NULL if called with size == 0. - if (size == 0) - size = 1; - - void *ptr; - - if (allocator != NULL && allocator->alloc != NULL) - ptr = allocator->alloc(allocator->opaque, 1, size); - else - ptr = malloc(size); - -#ifndef NDEBUG - // This helps to catch some stupid mistakes, but also hides them from - // Valgrind. Uncomment when useful. -// if (ptr != NULL) -// memset(ptr, 0xFD, size); -#endif - - return ptr; -} - - -extern void -lzma_free(void *ptr, lzma_allocator *allocator) -{ - if (allocator != NULL && allocator->free != NULL) - allocator->free(allocator->opaque, ptr); - else - free(ptr); - - return; -} diff --git a/src/liblzma/common/alone_decoder.c b/src/liblzma/common/alone_decoder.c index 062f6fab..006740f4 100644 --- a/src/liblzma/common/alone_decoder.c +++ b/src/liblzma/common/alone_decoder.c @@ -19,6 +19,7 @@ #include "alone_decoder.h" #include "lzma_decoder.h" +#include "lz_decoder.h" struct lzma_coder_s { @@ -38,6 +39,9 @@ struct lzma_coder_s { /// Uncompressed size decoded from the header lzma_vli uncompressed_size; + /// Memory usage limit + uint64_t memlimit; + /// Options decoded from the header needed to initialize /// the LZMA decoder lzma_options_lzma options; @@ -56,7 +60,7 @@ alone_decode(lzma_coder *coder, && (coder->sequence == SEQ_CODE || *in_pos < in_size)) switch (coder->sequence) { case SEQ_PROPERTIES: - if (lzma_lzma_decode_properties(&coder->options, in[*in_pos])) + if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos])) return LZMA_FORMAT_ERROR; coder->sequence = SEQ_DICTIONARY_SIZE; @@ -69,8 +73,6 @@ alone_decode(lzma_coder *coder, if (++coder->pos == 4) { if (coder->options.dictionary_size - < LZMA_DICTIONARY_SIZE_MIN - || coder->options.dictionary_size > LZMA_DICTIONARY_SIZE_MAX) return LZMA_FORMAT_ERROR; @@ -119,7 +121,20 @@ alone_decode(lzma_coder *coder, break; case SEQ_CODER_INIT: { - // Two is enough because there won't be implicit filters. + // FIXME It is unfair that this doesn't add a fixed amount + // like lzma_memusage_common() does. + const uint64_t memusage + = lzma_lzma_decoder_memusage(&coder->options); + + // Use LZMA_PROG_ERROR since LZMA_Alone decoder cannot be + // built without LZMA support. + // FIXME TODO Make the above comment true. + if (memusage == UINT64_MAX) + return LZMA_PROG_ERROR; + + if (memusage > coder->memlimit) + return LZMA_MEMLIMIT_ERROR; + lzma_filter_info filters[2] = { { .init = &lzma_lzma_decoder_init, @@ -135,7 +150,7 @@ alone_decode(lzma_coder *coder, return ret; // Use a hack to set the uncompressed size. - lzma_lzma_decoder_uncompressed_size(&coder->next, + lzma_lz_decoder_uncompressed(coder->next.coder, coder->uncompressed_size); coder->sequence = SEQ_CODE; @@ -160,15 +175,18 @@ alone_decode(lzma_coder *coder, static void alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->next, allocator); + lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); return; } -static lzma_ret -alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) +extern lzma_ret +lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, + uint64_t memlimit) { + lzma_next_coder_init(lzma_alone_decoder_init, next, allocator); + if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); if (next->coder == NULL) @@ -183,25 +201,20 @@ alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) next->coder->pos = 0; next->coder->options.dictionary_size = 0; next->coder->uncompressed_size = 0; + next->coder->memlimit = memlimit; return LZMA_OK; } -extern lzma_ret -lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) -{ - lzma_next_coder_init0(alone_decoder_init, next, allocator); -} - - extern LZMA_API lzma_ret -lzma_alone_decoder(lzma_stream *strm) +lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit) { - lzma_next_strm_init0(strm, alone_decoder_init); + lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit); strm->internal->supported_actions[LZMA_RUN] = true; - strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; +// strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; FIXME + strm->internal->supported_actions[LZMA_FINISH] = true; return LZMA_OK; } diff --git a/src/liblzma/common/alone_decoder.h b/src/liblzma/common/alone_decoder.h index a9b7e84b..13284043 100644 --- a/src/liblzma/common/alone_decoder.h +++ b/src/liblzma/common/alone_decoder.h @@ -17,8 +17,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifndef LZMA_ALONE_DECODER_H +#define LZMA_ALONE_DECODER_H + #include "common.h" -extern lzma_ret lzma_alone_decoder_init( - lzma_next_coder *next, lzma_allocator *allocator); +extern lzma_ret lzma_alone_decoder_init(lzma_next_coder *next, + lzma_allocator *allocator, uint64_t memlimit); + +#endif diff --git a/src/liblzma/common/alone_encoder.c b/src/liblzma/common/alone_encoder.c index f94a21c1..7fb11570 100644 --- a/src/liblzma/common/alone_encoder.c +++ b/src/liblzma/common/alone_encoder.c @@ -48,7 +48,7 @@ alone_encode(lzma_coder *coder, while (*out_pos < out_size) switch (coder->sequence) { case SEQ_HEADER: - bufcpy(coder->header, &coder->header_pos, + lzma_bufcpy(coder->header, &coder->header_pos, ALONE_HEADER_SIZE, out, out_pos, out_size); if (coder->header_pos < ALONE_HEADER_SIZE) @@ -74,7 +74,7 @@ alone_encode(lzma_coder *coder, static void alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->next, allocator); + lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); return; } @@ -85,6 +85,8 @@ static lzma_ret alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, const lzma_options_lzma *options) { + lzma_next_coder_init(alone_encoder_init, next, allocator); + if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); if (next->coder == NULL) @@ -101,7 +103,7 @@ alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, // Encode the header: // - Properties (1 byte) - if (lzma_lzma_encode_properties(options, next->coder->header)) + if (lzma_lzma_lclppb_encode(options, next->coder->header)) return LZMA_PROG_ERROR; // - Dictionary size (4 bytes) @@ -113,6 +115,9 @@ alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, // one is the next. While the header would allow any 32-bit integer, // we do this to keep the decoder of liblzma accepting the resulting // files. + // + // FIXME Maybe LZMA_Alone needs some lower limit for maximum + // dictionary size? Must check decoders from old LZMA SDK version. uint32_t d = options->dictionary_size - 1; d |= d >> 2; d |= d >> 3; @@ -153,7 +158,7 @@ lzma_alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, extern LZMA_API lzma_ret lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options) { - lzma_next_strm_init(strm, alone_encoder_init, options); + lzma_next_strm_init(alone_encoder_init, strm, options); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_FINISH] = true; diff --git a/src/liblzma/common/auto_decoder.c b/src/liblzma/common/auto_decoder.c index 765a27b1..5fcdf168 100644 --- a/src/liblzma/common/auto_decoder.c +++ b/src/liblzma/common/auto_decoder.c @@ -23,6 +23,8 @@ struct lzma_coder_s { lzma_next_coder next; + uint64_t memlimit; + uint32_t flags; bool initialized; }; @@ -41,9 +43,11 @@ auto_decode(lzma_coder *coder, lzma_allocator *allocator, if (in[*in_pos] == 0xFF) ret = lzma_stream_decoder_init( - &coder->next, allocator); + &coder->next, allocator, + coder->memlimit, coder->flags); else - ret = lzma_alone_decoder_init(&coder->next, allocator); + ret = lzma_alone_decoder_init(&coder->next, + allocator, coder->memlimit); if (ret != LZMA_OK) return ret; @@ -59,15 +63,21 @@ auto_decode(lzma_coder *coder, lzma_allocator *allocator, static void auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->next, allocator); + lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); return; } static lzma_ret -auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) +auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, + uint64_t memlimit, uint32_t flags) { + lzma_next_coder_init(auto_decoder_init, next, allocator); + + if (flags & ~LZMA_SUPPORTED_FLAGS) + return LZMA_HEADER_ERROR; + if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); if (next->coder == NULL) @@ -78,30 +88,22 @@ auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) next->coder->next = LZMA_NEXT_CODER_INIT; } + next->coder->memlimit = memlimit; + next->coder->flags = flags; next->coder->initialized = false; return LZMA_OK; } -/* -extern lzma_ret -lzma_auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_extra **header, lzma_extra **footer) -{ - lzma_next_coder_init( - auto_decoder_init, next, allocator, header, footer); -} -*/ - - extern LZMA_API lzma_ret -lzma_auto_decoder(lzma_stream *strm) +lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags) { - lzma_next_strm_init0(strm, auto_decoder_init); + lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags); strm->internal->supported_actions[LZMA_RUN] = true; - strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; +// strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; FIXME + strm->internal->supported_actions[LZMA_FINISH] = true; return LZMA_OK; } diff --git a/src/liblzma/common/block_decoder.c b/src/liblzma/common/block_decoder.c index f07c4e06..2c16a204 100644 --- a/src/liblzma/common/block_decoder.c +++ b/src/liblzma/common/block_decoder.c @@ -19,7 +19,7 @@ #include "block_decoder.h" #include "block_private.h" -#include "raw_decoder.h" +#include "filter_decoder.h" #include "check.h" @@ -35,7 +35,7 @@ struct lzma_coder_s { /// Decoding options; we also write Compressed Size and Uncompressed /// Size back to this structure when the encoding has been finished. - lzma_options_block *options; + lzma_block *options; /// Compressed Size calculated while encoding lzma_vli compressed_size; @@ -52,7 +52,7 @@ struct lzma_coder_s { size_t check_pos; /// Check of the uncompressed data - lzma_check check; + lzma_check_state check; }; @@ -64,9 +64,6 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, { switch (coder->sequence) { case SEQ_CODE: { - if (*out_pos >= out_size) - return LZMA_OK; - const size_t in_start = *in_pos; const size_t out_start = *out_pos; @@ -98,7 +95,7 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, // Fall through case SEQ_PADDING: - // If Compressed Data is padded to a multiple of four bytes. + // Compressed Data is padded to a multiple of four bytes. while (coder->compressed_size & 3) { if (*in_pos >= in_size) return LZMA_OK; @@ -132,19 +129,29 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, // Fall through - case SEQ_CHECK: + case SEQ_CHECK: { + const bool chksup = lzma_check_is_supported( + coder->options->check); + while (*in_pos < in_size) { - if (in[(*in_pos)++] != coder->check.buffer[ - coder->check_pos]) + // coder->check.buffer[] may be uninitialized when + // the Check ID is not supported. + if (chksup && coder->check.buffer.u8[coder->check_pos] + != in[*in_pos]) { + ++*in_pos; return LZMA_DATA_ERROR; + } - if (++coder->check_pos == lzma_check_sizes[ - coder->options->check]) + ++*in_pos; + + if (++coder->check_pos == lzma_check_size( + coder->options->check)) return LZMA_STREAM_END; } return LZMA_OK; } + } return LZMA_PROG_ERROR; } @@ -153,21 +160,28 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator, static void block_decoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->next, allocator); + lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); return; } -static lzma_ret -block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_options_block *options) +extern lzma_ret +lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, + lzma_block *options) { + lzma_next_coder_init(lzma_block_decoder_init, next, allocator); + // While lzma_block_total_size_get() is meant to calculate the Total // Size, it also validates the options excluding the filters. if (lzma_block_total_size_get(options) == 0) return LZMA_PROG_ERROR; + // options->check is used for array indexing so we need to know that + // it is in the valid range. + if ((unsigned)(options->check) > LZMA_CHECK_ID_MAX) + return LZMA_PROG_ERROR; + // Allocate and initialize *next->coder if needed. if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); @@ -192,30 +206,25 @@ block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, = options->compressed_size == LZMA_VLI_VALUE_UNKNOWN ? (LZMA_VLI_VALUE_MAX & ~LZMA_VLI_C(3)) - options->header_size - - lzma_check_sizes[options->check] + - lzma_check_size(options->check) : options->compressed_size; - // Initialize the check + // Initialize the check. It's caller's problem if the Check ID is not + // supported, and the Block decoder cannot verify the Check field. + // Caller can test lzma_checks[options->check]. next->coder->check_pos = 0; - return_if_error(lzma_check_init(&next->coder->check, options->check)); + lzma_check_init(&next->coder->check, options->check); + // Initialize the filter chain. return lzma_raw_decoder_init(&next->coder->next, allocator, options->filters); } -extern lzma_ret -lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_options_block *options) -{ - lzma_next_coder_init(block_decoder_init, next, allocator, options); -} - - extern LZMA_API lzma_ret -lzma_block_decoder(lzma_stream *strm, lzma_options_block *options) +lzma_block_decoder(lzma_stream *strm, lzma_block *options) { - lzma_next_strm_init(strm, block_decoder_init, options); + lzma_next_strm_init(lzma_block_decoder_init, strm, options); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; diff --git a/src/liblzma/common/block_decoder.h b/src/liblzma/common/block_decoder.h index af71128d..999aa748 100644 --- a/src/liblzma/common/block_decoder.h +++ b/src/liblzma/common/block_decoder.h @@ -24,6 +24,6 @@ extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, lzma_options_block *options); + lzma_allocator *allocator, lzma_block *options); #endif diff --git a/src/liblzma/common/block_encoder.c b/src/liblzma/common/block_encoder.c index 3add45a9..5aa3626b 100644 --- a/src/liblzma/common/block_encoder.c +++ b/src/liblzma/common/block_encoder.c @@ -19,7 +19,7 @@ #include "block_encoder.h" #include "block_private.h" -#include "raw_encoder.h" +#include "filter_encoder.h" #include "check.h" @@ -30,7 +30,7 @@ struct lzma_coder_s { /// Encoding options; we also write Total Size, Compressed Size, and /// Uncompressed Size back to this structure when the encoding has /// been finished. - lzma_options_block *options; + lzma_block *options; enum { SEQ_CODE, @@ -48,7 +48,7 @@ struct lzma_coder_s { size_t check_pos; /// Check of the uncompressed data - lzma_check check; + lzma_check_state check; }; @@ -147,11 +147,11 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator, // Fall through case SEQ_CHECK: - out[*out_pos] = coder->check.buffer[coder->check_pos]; + out[*out_pos] = coder->check.buffer.u8[coder->check_pos]; ++*out_pos; if (++coder->check_pos - == lzma_check_sizes[coder->options->check]) + == lzma_check_size(coder->options->check)) return LZMA_STREAM_END; break; @@ -167,21 +167,31 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator, static void block_encoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->next, allocator); + lzma_next_end(&coder->next, allocator); lzma_free(coder, allocator); return; } -static lzma_ret -block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_options_block *options) +extern lzma_ret +lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, + lzma_block *options) { + lzma_next_coder_init(lzma_block_encoder_init, next, allocator); + // While lzma_block_total_size_get() is meant to calculate the Total // Size, it also validates the options excluding the filters. if (lzma_block_total_size_get(options) == 0) return LZMA_PROG_ERROR; + // If the Check ID is not supported, we cannot calculate the check and + // thus not create a proper Block. + if ((unsigned)(options->check) > LZMA_CHECK_ID_MAX) + return LZMA_PROG_ERROR; + + if (!lzma_check_is_supported(options->check)) + return LZMA_UNSUPPORTED_CHECK; + // Allocate and initialize *next->coder if needed. if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); @@ -201,7 +211,7 @@ block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, // Initialize the check next->coder->check_pos = 0; - return_if_error(lzma_check_init(&next->coder->check, options->check)); + lzma_check_init(&next->coder->check, options->check); // Initialize the requested filters. return lzma_raw_encoder_init(&next->coder->next, allocator, @@ -209,18 +219,10 @@ block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, } -extern lzma_ret -lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_options_block *options) -{ - lzma_next_coder_init(block_encoder_init, next, allocator, options); -} - - extern LZMA_API lzma_ret -lzma_block_encoder(lzma_stream *strm, lzma_options_block *options) +lzma_block_encoder(lzma_stream *strm, lzma_block *options) { - lzma_next_strm_init(strm, block_encoder_init, options); + lzma_next_strm_init(lzma_block_encoder_init, strm, options); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_FINISH] = true; diff --git a/src/liblzma/common/block_encoder.h b/src/liblzma/common/block_encoder.h index eafcc618..7bc40139 100644 --- a/src/liblzma/common/block_encoder.h +++ b/src/liblzma/common/block_encoder.h @@ -24,6 +24,6 @@ extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, lzma_options_block *options); + lzma_allocator *allocator, lzma_block *options); #endif diff --git a/src/liblzma/common/block_header_decoder.c b/src/liblzma/common/block_header_decoder.c index b9e072e0..1d75f335 100644 --- a/src/liblzma/common/block_header_decoder.c +++ b/src/liblzma/common/block_header_decoder.c @@ -22,7 +22,7 @@ static void -free_properties(lzma_options_block *options, lzma_allocator *allocator) +free_properties(lzma_block *options, lzma_allocator *allocator) { // Free allocated filter options. The last array member is not // touched after the initialization in the beginning of @@ -38,12 +38,12 @@ free_properties(lzma_options_block *options, lzma_allocator *allocator) extern LZMA_API lzma_ret -lzma_block_header_decode(lzma_options_block *options, +lzma_block_header_decode(lzma_block *options, lzma_allocator *allocator, const uint8_t *in) { // NOTE: We consider the header to be corrupt not only when the // CRC32 doesn't match, but also when variable-length integers - // are invalid or not over 63 bits, or if the header is too small + // are invalid or over 63 bits, or if the header is too small // to contain the claimed information. // Initialize the filter options array. This way the caller can diff --git a/src/liblzma/common/block_header_encoder.c b/src/liblzma/common/block_header_encoder.c index ed0c88ba..3a16e6c3 100644 --- a/src/liblzma/common/block_header_encoder.c +++ b/src/liblzma/common/block_header_encoder.c @@ -22,7 +22,7 @@ extern LZMA_API lzma_ret -lzma_block_header_size(lzma_options_block *options) +lzma_block_header_size(lzma_block *options) { // Block Header Size + Block Flags + CRC32. size_t size = 1 + 1 + 4; @@ -77,7 +77,7 @@ lzma_block_header_size(lzma_options_block *options) extern LZMA_API lzma_ret -lzma_block_header_encode(const lzma_options_block *options, uint8_t *out) +lzma_block_header_encode(const lzma_block *options, uint8_t *out) { if ((options->header_size & 3) || options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN @@ -127,8 +127,9 @@ lzma_block_header_encode(const lzma_options_block *options, uint8_t *out) if (filter_count == 4) return LZMA_PROG_ERROR; - return_if_error(lzma_filter_flags_encode(out, &out_pos, - out_size, options->filters + filter_count)); + return_if_error(lzma_filter_flags_encode( + options->filters + filter_count, + out, &out_pos, out_size)); } while (options->filters[++filter_count].id != LZMA_VLI_VALUE_UNKNOWN); diff --git a/src/liblzma/common/block_util.c b/src/liblzma/common/block_util.c index 6bffc2f1..798163bb 100644 --- a/src/liblzma/common/block_util.c +++ b/src/liblzma/common/block_util.c @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // /// \file block_header.c -/// \brief Utility functions to handle lzma_options_block +/// \brief Utility functions to handle lzma_block // // Copyright (C) 2008 Lasse Collin // @@ -21,7 +21,7 @@ extern LZMA_API lzma_ret -lzma_block_total_size_set(lzma_options_block *options, lzma_vli total_size) +lzma_block_total_size_set(lzma_block *options, lzma_vli total_size) { // Validate. if (options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN @@ -32,7 +32,7 @@ lzma_block_total_size_set(lzma_options_block *options, lzma_vli total_size) return LZMA_PROG_ERROR; const uint32_t container_size = options->header_size - + lzma_check_sizes[options->check]; + + lzma_check_size(options->check); // Validate that Compressed Size will be greater than zero. if (container_size <= total_size) @@ -45,7 +45,7 @@ lzma_block_total_size_set(lzma_options_block *options, lzma_vli total_size) extern LZMA_API lzma_vli -lzma_block_total_size_get(const lzma_options_block *options) +lzma_block_total_size_get(const lzma_block *options) { // Validate the values that we are interested in. if (options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN @@ -61,7 +61,7 @@ lzma_block_total_size_get(const lzma_options_block *options) const lzma_vli total_size = options->compressed_size + options->header_size - + lzma_check_sizes[options->check]; + + lzma_check_size(options->check); // Validate the calculated Total Size. if (options->compressed_size > LZMA_VLI_VALUE_MAX diff --git a/src/liblzma/common/code.c b/src/liblzma/common/common.c index 0e3929b6..feac9cbf 100644 --- a/src/liblzma/common/code.c +++ b/src/liblzma/common/common.c @@ -1,9 +1,9 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file code.c -/// \brief zlib-like API wrapper for liblzma's internal API +/// \file common.h +/// \brief Common functions needed in many places in liblzma // -// Copyright (C) 2007 Lasse Collin +// Copyright (C) 2007-2008 Lasse Collin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,19 +20,117 @@ #include "common.h" -LZMA_API const lzma_stream LZMA_STREAM_INIT_VAR = { - .next_in = NULL, - .avail_in = 0, - .total_in = 0, - .next_out = NULL, - .avail_out = 0, - .total_out = 0, - .allocator = NULL, - .internal = NULL, -}; +///////////// +// Version // +///////////// + +extern LZMA_API uint32_t +lzma_version_number(void) +{ + return LZMA_VERSION; +} + + +extern LZMA_API const char * +lzma_version_string(void) +{ + return PACKAGE_VERSION; +} + + +/////////////////////// +// Memory allocation // +/////////////////////// + +extern void * lzma_attribute((malloc)) +lzma_alloc(size_t size, lzma_allocator *allocator) +{ + // Some malloc() variants return NULL if called with size == 0. + if (size == 0) + size = 1; + + void *ptr; + + if (allocator != NULL && allocator->alloc != NULL) + ptr = allocator->alloc(allocator->opaque, 1, size); + else + ptr = malloc(size); + + return ptr; +} + + +extern void +lzma_free(void *ptr, lzma_allocator *allocator) +{ + if (allocator != NULL && allocator->free != NULL) + allocator->free(allocator->opaque, ptr); + else + free(ptr); + + return; +} + + +////////// +// Misc // +////////// + +extern size_t +lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, + size_t in_size, uint8_t *restrict out, + size_t *restrict out_pos, size_t out_size) +{ + const size_t in_avail = in_size - *in_pos; + const size_t out_avail = out_size - *out_pos; + const size_t copy_size = MIN(in_avail, out_avail); + + memcpy(out + *out_pos, in + *in_pos, copy_size); + + *in_pos += copy_size; + *out_pos += copy_size; + + return copy_size; +} extern lzma_ret +lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter_info *filters) +{ + lzma_next_coder_init(filters[0].init, next, allocator); + + return filters[0].init == NULL + ? LZMA_OK : filters[0].init(next, allocator, filters); +} + + +extern void +lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator) +{ + if (next->init != (uintptr_t)(NULL)) { + // To avoid tiny end functions that simply call + // lzma_free(coder, allocator), we allow leaving next->end + // NULL and call lzma_free() here. + if (next->end != NULL) + next->end(next->coder, allocator); + else + lzma_free(next->coder, allocator); + + // Reset the variables so the we don't accidentally think + // that it is an already initialized coder. + *next = LZMA_NEXT_CODER_INIT; + } + + return; +} + + +////////////////////////////////////// +// External to internal API wrapper // +////////////////////////////////////// + +extern lzma_ret lzma_strm_init(lzma_stream *strm) { if (strm == NULL) @@ -191,10 +289,7 @@ extern LZMA_API void lzma_end(lzma_stream *strm) { if (strm != NULL && strm->internal != NULL) { - if (strm->internal->next.end != NULL) - strm->internal->next.end(strm->internal->next.coder, - strm->allocator); - + lzma_next_end(&strm->internal->next, strm->allocator); lzma_free(strm->internal, strm->allocator); strm->internal = NULL; } diff --git a/src/liblzma/common/common.h b/src/liblzma/common/common.h index 4f30427d..81f2a9a4 100644 --- a/src/liblzma/common/common.h +++ b/src/liblzma/common/common.h @@ -3,7 +3,7 @@ /// \file common.h /// \brief Definitions common to the whole liblzma library // -// Copyright (C) 2007 Lasse Collin +// Copyright (C) 2007-2008 Lasse Collin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -46,16 +46,32 @@ #define LZMA_BUFFER_SIZE 4096 +/// Start of internal Filter ID space. These IDs must never be used +/// in Streams. +#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62) + + /// Internal helper filter used by Subblock decoder. It is mapped to an /// otherwise invalid Filter ID, which is impossible to get from any input /// file (even if malicious file). -#define LZMA_FILTER_SUBBLOCK_HELPER (UINT64_MAX - 2) +#define LZMA_FILTER_SUBBLOCK_HELPER (LZMA_FILTER_RESERVED_START + 1) + + +/// Supported flags that can be passed to lzma_stream_decoder() +/// or lzma_auto_decoder(). +#define LZMA_SUPPORTED_FLAGS \ + (LZMA_WARN_NO_CHECK \ + | LZMA_WARN_UNSUPPORTED_CHECK \ + | LZMA_TELL_CHECK \ + | LZMA_CONCATENATED) /////////// // Types // /////////// +/// Type of encoder/decoder specific data; the actual structure is defined +/// differently in different coders. typedef struct lzma_coder_s lzma_coder; typedef struct lzma_next_coder_s lzma_next_coder; @@ -63,10 +79,15 @@ typedef struct lzma_next_coder_s lzma_next_coder; typedef struct lzma_filter_info_s lzma_filter_info; +/// Type of a function used to initialize a filter encoder or decoder typedef lzma_ret (*lzma_init_function)( lzma_next_coder *next, lzma_allocator *allocator, const lzma_filter_info *filters); +/// Type of a function to do some kind of coding work (filters, Stream, +/// Block encoders/decoders etc.). Some special coders use don't use both +/// input and output buffers, but for simplicity they still use this same +/// function prototype. typedef lzma_ret (*lzma_code_function)( lzma_coder *coder, lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, @@ -74,10 +95,24 @@ typedef lzma_ret (*lzma_code_function)( size_t *restrict out_pos, size_t out_size, lzma_action action); +/// Type of a function to free the memory allocated for the coder typedef void (*lzma_end_function)( lzma_coder *coder, lzma_allocator *allocator); +/// Raw coder validates and converts an array of lzma_filter structures to +/// an array of lzma_filter_info structures. This array is used with +/// lzma_next_filter_init to initialize the filter chain. +struct lzma_filter_info_s { + /// Pointer to function used to initialize the filter. + /// This is NULL to indicate end of array. + lzma_init_function init; + + /// Pointer to filter's options structure + void *options; +}; + + /// Hold data and function pointers of the next filter in the chain. struct lzma_next_coder_s { /// Pointer to coder-specific data @@ -85,28 +120,48 @@ struct lzma_next_coder_s { /// "Pointer" to init function. This is never called here. /// We need only to detect if we are initializing a coder - /// that was allocated earlier. See code.c and next_coder.c. + /// that was allocated earlier. See lzma_next_coder_init and + /// lzma_next_strm_init macros in this file. uintptr_t init; /// Pointer to function to do the actual coding lzma_code_function code; - /// Pointer to function to free lzma_next_coder.coder + /// Pointer to function to free lzma_next_coder.coder. This can + /// be NULL; in that case, lzma_free is called to free + /// lzma_next_coder.coder. lzma_end_function end; + + /// Pointer to function to return the type of the integrity check. + /// Most coders won't support this. + lzma_check (*see_check)(const lzma_coder *coder); + +// uint64_t (*memconfig)( +// lzma_coder *coder, uint64_t memlimit, bool change); }; + +/// Macro to initialize lzma_next_coder structure #define LZMA_NEXT_CODER_INIT \ (lzma_next_coder){ \ .coder = NULL, \ - .init = 0, \ + .init = (uintptr_t)(NULL), \ .code = NULL, \ .end = NULL, \ + .see_check = NULL, \ } +/// Internal data for lzma_strm_init, lzma_code, and lzma_end. A pointer to +/// this is stored in lzma_stream. struct lzma_internal_s { + /// The actual coder that should do something useful lzma_next_coder next; + /// Track the state of the coder. This is used to validate arguments + /// so that the actual coders can rely on e.g. that LZMA_SYNC_FLUSH + /// is used on every call to lzma_code until next.code has returned + /// LZMA_STREAM_END. enum { ISEQ_RUN, ISEQ_SYNC_FLUSH, @@ -116,33 +171,20 @@ struct lzma_internal_s { ISEQ_ERROR, } sequence; - bool supported_actions[4]; - bool allow_buf_error; + /// A copy of lzma_stream avail_in. This is used to verify that the + /// amount of input doesn't change once e.g. LZMA_FINISH has been + /// used. size_t avail_in; -}; - -struct lzma_filter_info_s { - /// Pointer to function used to initialize the filter. - /// This is NULL to indicate end of array. - lzma_init_function init; + /// Indicates which lzma_action values are allowed by next.code. + bool supported_actions[4]; - /// Pointer to filter's options structure - void *options; + /// If true, lzma_code will return LZMA_BUF_ERROR if no progress was + /// made (no input consumed and no output produced by next.code). + bool allow_buf_error; }; -/* -typedef struct { - lzma_init_function init; - uint32_t (*input_alignment)(lzma_vli id, const void *options); - uint32_t (*output_alignment)(lzma_vli id, const void *options); - bool changes_uncompressed_size; - bool supports_eopm; -} lzma_filter_hook; -*/ - - /////////////// // Functions // /////////////// @@ -154,126 +196,69 @@ extern void *lzma_alloc(size_t size, lzma_allocator *allocator) /// Frees memory extern void lzma_free(void *ptr, lzma_allocator *allocator); -/// Initializes lzma_stream FIXME desc + +/// Allocates strm->internal if it is NULL, and initializes *strm and +/// strm->internal. This function is only called via lzma_next_strm_init macro. extern lzma_ret lzma_strm_init(lzma_stream *strm); -/// +/// Initializes the next filter in the chain, if any. This takes care of +/// freeing the memory of previously initialized filter if it is different +/// than the filter being initialized now. This way the actual filter +/// initialization functions don't need to use lzma_next_coder_init macro. extern lzma_ret lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator, const lzma_filter_info *filters); -/// -extern void lzma_next_coder_end(lzma_next_coder *next, - lzma_allocator *allocator); +/// Frees the memory allocated for next->coder either using next->end or, +/// if next->end is NULL, using lzma_free. +extern void lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator); -/// \brief Wrapper for memcpy() -/// -/// This function copies as much data as possible from in[] to out[] and -/// updates *in_pos and *out_pos accordingly. -/// -static inline size_t -bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, - uint8_t *restrict out, size_t *restrict out_pos, - size_t out_size) -{ - const size_t in_avail = in_size - *in_pos; - const size_t out_avail = out_size - *out_pos; - const size_t copy_size = MIN(in_avail, out_avail); - - memcpy(out + *out_pos, in + *in_pos, copy_size); - - *in_pos += copy_size; - *out_pos += copy_size; - - return copy_size; -} +/// Copy as much data as possible from in[] to out[] and update *in_pos +/// and *out_pos accordingly. Returns the number of bytes copied. +extern size_t lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, + size_t in_size, uint8_t *restrict out, + size_t *restrict out_pos, size_t out_size); -/// \brief Initializing the next coder -/// -/// lzma_next_coder can point to different types of coders. The existing -/// coder may be different than what we are initializing now. In that case -/// we must git rid of the old coder first. Otherwise we reuse the existing -/// coder structure. +/// \brief Return if expression doesn't evaluate to LZMA_OK /// -#define lzma_next_coder_init2(next, allocator, cmpfunc, func, ...) \ +/// There are several situations where we want to return immediatelly +/// with the value of expr if it isn't LZMA_OK. This macro shortens +/// the code a little. +#define return_if_error(expr) \ do { \ - if ((uintptr_t)(&cmpfunc) != (next)->init) \ - lzma_next_coder_end(next, allocator); \ - const lzma_ret ret = func(next, __VA_ARGS__); \ - if (ret == LZMA_OK) { \ - (next)->init = (uintptr_t)(&cmpfunc); \ - assert((next)->code != NULL); \ - assert((next)->end != NULL); \ - } else { \ - lzma_next_coder_end(next, allocator); \ - } \ - return ret; \ + const lzma_ret ret_ = (expr); \ + if (ret_ != LZMA_OK) \ + return ret_; \ } while (0) -/// \brief Initializing lzma_next_coder -/// -/// Call the initialization function, which must take at least one -/// argument in addition to lzma_next_coder and lzma_allocator. -#define lzma_next_coder_init(func, next, allocator, ...) \ - lzma_next_coder_init2(next, allocator, \ - func, func, allocator, __VA_ARGS__) - -/// \brief Initializing lzma_next_coder -/// -/// Call the initialization function, which takes no other arguments than -/// lzma_next_coder and lzma_allocator. -#define lzma_next_coder_init0(func, next, allocator) \ - lzma_next_coder_init2(next, allocator, func, func, allocator) - -/// \brief Initializing lzma_stream -/// -/// lzma_strm initialization with more detailed options. -#define lzma_next_strm_init2(strm, cmpfunc, func, ...) \ +/// If next isn't already initialized, free the previous coder. Then mark +/// that next is _possibly_ initialized for the coder using this macro. +/// "Possibly" means that if e.g. allocation of next->coder fails, the +/// structure isn't actually initialized for this coder, but leaving +/// next->init to func is still OK. +#define lzma_next_coder_init(func, next, allocator) \ do { \ - lzma_ret ret = lzma_strm_init(strm); \ - if (ret != LZMA_OK) \ - return ret; \ - if ((uintptr_t)(&cmpfunc) != (strm)->internal->next.init) \ - lzma_next_coder_end(\ - &(strm)->internal->next, (strm)->allocator); \ - ret = func(&(strm)->internal->next, __VA_ARGS__); \ - if (ret != LZMA_OK) { \ - lzma_end(strm); \ - return ret; \ - } \ - (strm)->internal->next.init = (uintptr_t)(&cmpfunc); \ - assert((strm)->internal->next.code != NULL); \ - assert((strm)->internal->next.end != NULL); \ + if ((uintptr_t)(&func) != (next)->init) \ + lzma_next_end(next, allocator); \ + (next)->init = (uintptr_t)(&func); \ } while (0) -/// \brief Initializing lzma_stream -/// -/// Call the initialization function, which must take at least one -/// argument in addition to lzma_next_coder and lzma_allocator. -#define lzma_next_strm_init(strm, func, ...) \ - lzma_next_strm_init2(strm, func, func, (strm)->allocator, __VA_ARGS__) -/// \brief Initializing lzma_stream -/// -/// Call the initialization function, which takes no other arguments than -/// lzma_next_coder and lzma_allocator. -#define lzma_next_strm_init0(strm, func) \ - lzma_next_strm_init2(strm, func, func, (strm)->allocator) - - -/// \brief Return if expression doesn't evaluate to LZMA_OK -/// -/// There are several situations where we want to return immediatelly -/// with the value of expr if it isn't LZMA_OK. This macro shortens -/// the code a bit. -/// -#define return_if_error(expr) \ +/// Initializes lzma_strm and calls func() to initialize strm->internal->next. +/// (The function being called will use lzma_next_coder_init()). If +/// initialization fails, memory that wasn't freed by func() is freed +/// along strm->internal. +#define lzma_next_strm_init(func, strm, ...) \ do { \ - const lzma_ret ret_ = expr; \ - if (ret_ != LZMA_OK) \ + return_if_error(lzma_strm_init(strm)); \ + const lzma_ret ret_ = func(&(strm)->internal->next, \ + (strm)->allocator, __VA_ARGS__); \ + if (ret_ != LZMA_OK) { \ + lzma_end(strm); \ return ret_; \ + } \ } while (0) #endif diff --git a/src/liblzma/common/delta_common.c b/src/liblzma/common/delta_common.c deleted file mode 100644 index acd31e14..00000000 --- a/src/liblzma/common/delta_common.c +++ /dev/null @@ -1,66 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file delta_common.c -/// \brief Common stuff for Delta encoder and decoder -// -// 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 "delta_common.h" - - -static void -delta_coder_end(lzma_coder *coder, lzma_allocator *allocator) -{ - lzma_next_coder_end(&coder->next, allocator); - lzma_free(coder, allocator); - return; -} - - -extern lzma_ret -lzma_delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_filter_info *filters, lzma_code_function code) -{ - // Allocate memory for the decoder if needed. - if (next->coder == NULL) { - next->coder = lzma_alloc(sizeof(lzma_coder), allocator); - if (next->coder == NULL) - return LZMA_MEM_ERROR; - - // End function is the same for encoder and decoder. - next->end = &delta_coder_end; - next->coder->next = LZMA_NEXT_CODER_INIT; - } - - // Coding function is different for encoder and decoder. - next->code = code; - - // Set the delta distance. - if (filters[0].options == NULL) - return LZMA_PROG_ERROR; - next->coder->distance = ((lzma_options_delta *)(filters[0].options)) - ->distance; - if (next->coder->distance < LZMA_DELTA_DISTANCE_MIN - || next->coder->distance > LZMA_DELTA_DISTANCE_MAX) - return LZMA_HEADER_ERROR; - - // Initialize the rest of the variables. - next->coder->pos = 0; - memzero(next->coder->history, LZMA_DELTA_DISTANCE_MAX); - - // Initialize the next decoder in the chain, if any. - return lzma_next_filter_init(&next->coder->next, - allocator, filters + 1); -} diff --git a/src/liblzma/common/delta_decoder.c b/src/liblzma/common/delta_decoder.c deleted file mode 100644 index 8f5a4cbf..00000000 --- a/src/liblzma/common/delta_decoder.c +++ /dev/null @@ -1,61 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file delta_decoder.c -/// \brief Delta filter decoder -// -// Copyright (C) 2007, 2008 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 "delta_decoder.h" -#include "delta_common.h" - - -static void -decode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size) -{ - const size_t distance = coder->distance; - - for (size_t i = 0; i < size; ++i) { - buffer[i] += coder->history[(distance + coder->pos) & 0xFF]; - coder->history[coder->pos-- & 0xFF] = buffer[i]; - } -} - - -static lzma_ret -delta_decode(lzma_coder *coder, lzma_allocator *allocator, - const uint8_t *restrict in, size_t *restrict in_pos, - size_t in_size, uint8_t *restrict out, - size_t *restrict out_pos, size_t out_size, lzma_action action) -{ - assert(coder->next.code != NULL); - - const size_t out_start = *out_pos; - - const lzma_ret ret = coder->next.code(coder->next.coder, allocator, - in, in_pos, in_size, out, out_pos, out_size, - action); - - decode_buffer(coder, out + out_start, *out_pos - out_start); - - return ret; -} - - -extern lzma_ret -lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_filter_info *filters) -{ - return lzma_delta_coder_init(next, allocator, filters, &delta_decode); -} diff --git a/src/liblzma/common/delta_decoder.h b/src/liblzma/common/delta_decoder.h deleted file mode 100644 index bef9f58a..00000000 --- a/src/liblzma/common/delta_decoder.h +++ /dev/null @@ -1,28 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file delta_decoder.h -/// \brief Delta filter decoder -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef LZMA_DELTA_DECODER_H -#define LZMA_DELTA_DECODER_H - -#include "common.h" - -extern lzma_ret lzma_delta_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); - -#endif diff --git a/src/liblzma/common/delta_encoder.c b/src/liblzma/common/delta_encoder.c deleted file mode 100644 index a8bb9341..00000000 --- a/src/liblzma/common/delta_encoder.c +++ /dev/null @@ -1,98 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file delta_encoder.c -/// \brief Delta filter encoder -// -// Copyright (C) 2007, 2008 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 "delta_encoder.h" -#include "delta_common.h" - - -/// Copies and encodes the data at the same time. This is used when Delta -/// is the first filter in the chain (and thus the last filter in the -/// encoder's filter stack). -static void -copy_and_encode(lzma_coder *coder, - const uint8_t *restrict in, uint8_t *restrict out, size_t size) -{ - const size_t distance = coder->distance; - - for (size_t i = 0; i < size; ++i) { - const uint8_t tmp = coder->history[ - (distance + coder->pos) & 0xFF]; - coder->history[coder->pos-- & 0xFF] = in[i]; - out[i] = in[i] - tmp; - } -} - - -/// Encodes the data in place. This is used when we are the last filter -/// in the chain (and thus non-last filter in the encoder's filter stack). -static void -encode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size) -{ - const size_t distance = coder->distance; - - for (size_t i = 0; i < size; ++i) { - const uint8_t tmp = coder->history[ - (distance + coder->pos) & 0xFF]; - coder->history[coder->pos-- & 0xFF] = buffer[i]; - buffer[i] -= tmp; - } -} - - -static lzma_ret -delta_encode(lzma_coder *coder, lzma_allocator *allocator, - const uint8_t *restrict in, size_t *restrict in_pos, - size_t in_size, uint8_t *restrict out, - size_t *restrict out_pos, size_t out_size, lzma_action action) -{ - lzma_ret ret; - - if (coder->next.code == NULL) { - const size_t in_avail = in_size - *in_pos; - const size_t out_avail = out_size - *out_pos; - const size_t size = MIN(in_avail, out_avail); - - copy_and_encode(coder, in + *in_pos, out + *out_pos, size); - - *in_pos += size; - *out_pos += size; - - ret = action != LZMA_RUN && *in_pos == in_size - ? LZMA_STREAM_END : LZMA_OK; - - } else { - const size_t out_start = *out_pos; - - ret = coder->next.code(coder->next.coder, allocator, - in, in_pos, in_size, out, out_pos, out_size, - action); - - encode_in_place(coder, out + out_start, *out_pos - out_start); - } - - return ret; -} - - -extern lzma_ret -lzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_filter_info *filters) -{ - return lzma_delta_coder_init(next, allocator, filters, &delta_encode); -} diff --git a/src/liblzma/common/easy.c b/src/liblzma/common/easy.c index 6c258204..ae0e4f74 100644 --- a/src/liblzma/common/easy.c +++ b/src/liblzma/common/easy.c @@ -25,12 +25,12 @@ struct lzma_coder_s { /// We need to keep the filters array available in case /// LZMA_FULL_FLUSH is used. - lzma_options_filter filters[5]; + lzma_filter filters[5]; }; static bool -easy_set_filters(lzma_options_filter *filters, uint32_t level) +easy_set_filters(lzma_filter *filters, uint32_t level) { bool error = false; @@ -38,9 +38,9 @@ easy_set_filters(lzma_options_filter *filters, uint32_t level) // TODO FIXME Use Subblock or LZMA2 with no compression. error = true; -#ifdef HAVE_FILTER_LZMA +#ifdef HAVE_ENCODER_LZMA2 } else if (level <= 9) { - filters[0].id = LZMA_FILTER_LZMA; + filters[0].id = LZMA_FILTER_LZMA2; filters[0].options = (void *)(&lzma_preset_lzma[level - 1]); filters[1].id = LZMA_VLI_VALUE_UNKNOWN; #endif @@ -68,7 +68,7 @@ easy_encode(lzma_coder *coder, lzma_allocator *allocator, static void easy_encoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->stream_encoder, allocator); + lzma_next_end(&coder->stream_encoder, allocator); lzma_free(coder, allocator); return; } @@ -78,6 +78,8 @@ static lzma_ret easy_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, lzma_easy_level level) { + lzma_next_coder_init(easy_encoder_init, next, allocator); + if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); if (next->coder == NULL) @@ -100,7 +102,7 @@ easy_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, extern LZMA_API lzma_ret lzma_easy_encoder(lzma_stream *strm, lzma_easy_level level) { - lzma_next_strm_init(strm, easy_encoder_init, level); + lzma_next_strm_init(easy_encoder_init, strm, level); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; @@ -114,9 +116,9 @@ lzma_easy_encoder(lzma_stream *strm, lzma_easy_level level) extern LZMA_API uint32_t lzma_easy_memory_usage(lzma_easy_level level) { - lzma_options_filter filters[5]; + lzma_filter filters[5]; if (easy_set_filters(filters, level)) return UINT32_MAX; - return lzma_memory_usage(filters, true); + return lzma_memusage_encoder(filters); } diff --git a/src/liblzma/common/features.c b/src/liblzma/common/features.c deleted file mode 100644 index a02949d9..00000000 --- a/src/liblzma/common/features.c +++ /dev/null @@ -1,66 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file features.c -/// \brief Information about features enabled at compile time -// -// 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" - - -static const lzma_vli filters[] = { -#ifdef HAVE_FILTER_SUBBLOCK - LZMA_FILTER_SUBBLOCK, -#endif - -#ifdef HAVE_FILTER_X86 - LZMA_FILTER_X86, -#endif - -#ifdef HAVE_FILTER_POWERPC - LZMA_FILTER_POWERPC, -#endif - -#ifdef HAVE_FILTER_IA64 - LZMA_FILTER_IA64, -#endif - -#ifdef HAVE_FILTER_ARM - LZMA_FILTER_ARM, -#endif - -#ifdef HAVE_FILTER_ARMTHUMB - LZMA_FILTER_ARMTHUMB, -#endif - -#ifdef HAVE_FILTER_SPARC - LZMA_FILTER_SPARC, -#endif - -#ifdef HAVE_FILTER_DELTA - LZMA_FILTER_DELTA, -#endif - -#ifdef HAVE_FILTER_LZMA - LZMA_FILTER_LZMA, -#endif - - LZMA_VLI_VALUE_UNKNOWN -}; - - -LZMA_API const lzma_vli *const lzma_available_filter_encoders = filters; - -LZMA_API const lzma_vli *const lzma_available_filter_decoders = filters; diff --git a/src/liblzma/common/filter_common.c b/src/liblzma/common/filter_common.c new file mode 100644 index 00000000..886ddb53 --- /dev/null +++ b/src/liblzma/common/filter_common.c @@ -0,0 +1,262 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file filter_common.c +/// \brief Filter-specific stuff common for both encoder and decoder +// +// Copyright (C) 2008 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 "filter_common.h" + + +static const struct { + /// Filter ID + lzma_vli id; + + /// True if it is OK to use this filter as non-last filter in + /// the chain. + bool non_last_ok; + + /// True if it is OK to use this filter as the last filter in + /// the chain. + bool last_ok; + + /// True if the filter may change the size of the data (that is, the + /// amount of encoded output can be different than the amount of + /// uncompressed input). + bool changes_size; + +} features[] = { +#if defined (HAVE_ENCODER_LZMA) || defined(HAVE_DECODER_LZMA) + { + .id = LZMA_FILTER_LZMA, + .non_last_ok = false, + .last_ok = true, + .changes_size = true, + }, +#endif +#ifdef HAVE_DECODER_LZMA2 + { + .id = LZMA_FILTER_LZMA2, + .non_last_ok = false, + .last_ok = true, + .changes_size = true, + }, +#endif +#if defined(HAVE_ENCODER_SUBBLOCK) || defined(HAVE_DECODER_SUBBLOCK) + { + .id = LZMA_FILTER_SUBBLOCK, + .non_last_ok = true, + .last_ok = true, + .changes_size = true, + }, +#endif +#ifdef HAVE_DECODER_X86 + { + .id = LZMA_FILTER_X86, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif +#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC) + { + .id = LZMA_FILTER_POWERPC, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif +#ifdef HAVE_DECODER_IA64 + { + .id = LZMA_FILTER_IA64, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif +#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM) + { + .id = LZMA_FILTER_ARM, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif +#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB) + { + .id = LZMA_FILTER_ARMTHUMB, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif +#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC) + { + .id = LZMA_FILTER_SPARC, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif +#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA) + { + .id = LZMA_FILTER_DELTA, + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif + { + .id = LZMA_VLI_VALUE_UNKNOWN + } +}; + + +static lzma_ret +validate_chain(const lzma_filter *filters, size_t *count) +{ + // There must be at least one filter. + if (filters == NULL || filters[0].id == LZMA_VLI_VALUE_UNKNOWN) + return LZMA_PROG_ERROR; + + // Number of non-last filters that may change the size of the data + // significantly (that is, more than 1-2 % or so). + size_t changes_size_count = 0; + + // True if it is OK to add a new filter after the current filter. + bool non_last_ok = true; + + // True if the last filter in the given chain is actually usable as + // the last filter. Only filters that support embedding End of Payload + // Marker can be used as the last filter in the chain. + bool last_ok = false; + + size_t i = 0; + do { + size_t j; + for (j = 0; filters[i].id != features[j].id; ++j) + if (features[j].id == LZMA_VLI_VALUE_UNKNOWN) + return LZMA_HEADER_ERROR; + + // If the previous filter in the chain cannot be a non-last + // filter, the chain is invalid. + if (!non_last_ok) + return LZMA_HEADER_ERROR; + + non_last_ok = features[j].non_last_ok; + last_ok = features[j].last_ok; + changes_size_count += features[j].changes_size; + + } while (filters[++i].id != LZMA_VLI_VALUE_UNKNOWN); + + // There must be 1-4 filters. The last filter must be usable as + // the last filter in the chain. At maximum of three filters are + // allowed to change the size of the data. + if (i > LZMA_BLOCK_FILTERS_MAX || !last_ok || changes_size_count > 3) + return LZMA_HEADER_ERROR; + + *count = i; + return LZMA_OK; +} + + +extern lzma_ret +lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter *options, + lzma_filter_find coder_find, bool is_encoder) +{ + // Do some basic validation and get the number of filters. + size_t count; + return_if_error(validate_chain(options, &count)); + + // Set the filter functions and copy the options pointer. + lzma_filter_info filters[LZMA_BLOCK_FILTERS_MAX + 1]; + if (is_encoder) { + for (size_t i = 0; i < count; ++i) { + // The order of the filters is reversed in the + // encoder. It allows more efficient handling + // of the uncompressed data. + const size_t j = count - i - 1; + + const lzma_filter_coder *const fc + = coder_find(options[i].id); + if (fc == NULL || fc->init == NULL) + return LZMA_HEADER_ERROR; + + filters[j].init = fc->init; + filters[j].options = options[i].options; + } + } else { + for (size_t i = 0; i < count; ++i) { + const lzma_filter_coder *const fc + = coder_find(options[i].id); + if (fc == NULL || fc->init == NULL) + return LZMA_HEADER_ERROR; + + filters[i].init = fc->init; + filters[i].options = options[i].options; + } + } + + // Terminate the array. + filters[count].init = NULL; + + // Initialize the filters. + const lzma_ret ret = lzma_next_filter_init(next, allocator, filters); + if (ret != LZMA_OK) + lzma_next_end(next, allocator); + + return ret; +} + + +extern uint64_t +lzma_memusage_coder(lzma_filter_find coder_find, + const lzma_filter *filters) +{ + // The chain has to have at least one filter. + if (filters[0].id == LZMA_VLI_VALUE_UNKNOWN) + return UINT64_MAX; + + uint64_t total = 0; + size_t i = 0; + + do { + const lzma_filter_coder *const fc + = coder_find(filters[i].id); + if (fc == NULL) + return UINT64_MAX; // Unsupported Filter ID + + if (fc->memusage == NULL) { + // This filter doesn't have a function to calculate + // the memory usage. Such filters need only little + // memory, so we use 1 KiB as a good estimate. + total += 1024; + } else { + // Call the filter-specific memory usage calculation + // function. + const uint64_t usage + = fc->memusage(filters[i].options); + if (usage == UINT64_MAX) + return UINT64_MAX; // Invalid options + + total += usage; + } + } while (filters[++i].id != LZMA_VLI_VALUE_UNKNOWN); + + // Add some fixed amount of extra. It's to compensate memory usage + // of Stream, Block etc. coders, malloc() overhead, stack etc. + return total + (1U << 15); +} diff --git a/src/liblzma/common/filter_common.h b/src/liblzma/common/filter_common.h new file mode 100644 index 00000000..9def50b9 --- /dev/null +++ b/src/liblzma/common/filter_common.h @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file filter_common.c +/// \brief Filter-specific stuff common for both encoder and decoder +// +// Copyright (C) 2008 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef LZMA_FILTER_COMMON_H +#define LZMA_FILTER_COMMON_H + +#include "common.h" + + +/// Both lzma_filter_encoder and lzma_filter_decoder begin with these members. +typedef struct { + /// Initializes the filter encoder and calls lzma_next_filter_init() + /// for filters + 1. + lzma_init_function init; + + /// Calculates memory usage of the encoder. If the options are + /// invalid, UINT64_MAX is returned. + uint64_t (*memusage)(const void *options); + +} lzma_filter_coder; + + +typedef const lzma_filter_coder *(*lzma_filter_find)(lzma_vli id); + + +extern lzma_ret lzma_raw_coder_init( + lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter *filters, + lzma_filter_find coder_find, bool is_encoder); + + +extern uint64_t lzma_memusage_coder(lzma_filter_find coder_find, + const lzma_filter *filters); + + +#endif diff --git a/src/liblzma/common/filter_decoder.c b/src/liblzma/common/filter_decoder.c new file mode 100644 index 00000000..9fe94f7b --- /dev/null +++ b/src/liblzma/common/filter_decoder.c @@ -0,0 +1,236 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file filter_decoder.c +/// \brief Filter ID mapping to filter-specific functions +// +// Copyright (C) 2008 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 "filter_decoder.h" +#include "filter_common.h" +#include "lzma_decoder.h" +#include "lzma2_decoder.h" +#include "subblock_decoder.h" +#include "subblock_decoder_helper.h" +#include "simple_decoder.h" +#include "delta_decoder.h" + + +typedef struct { + /// Initializes the filter encoder and calls lzma_next_filter_init() + /// for filters + 1. + lzma_init_function init; + + /// Calculates memory usage of the encoder. If the options are + /// invalid, UINT64_MAX is returned. + uint64_t (*memusage)(const void *options); + + /// Decodes Filter Properties. + /// + /// \return - LZMA_OK: Properties decoded successfully. + /// - LZMA_HEADER_ERROR: Unsupported properties + /// - LZMA_MEM_ERROR: Memory allocation failed. + lzma_ret (*props_decode)(void **options, lzma_allocator *allocator, + const uint8_t *props, size_t props_size); + +} lzma_filter_decoder; + + +static const lzma_vli ids[] = { +#ifdef HAVE_DECODER_LZMA + LZMA_FILTER_LZMA, +#endif + +#ifdef HAVE_DECODER_LZMA2 + LZMA_FILTER_LZMA2, +#endif + +#ifdef HAVE_DECODER_SUBBLOCK + LZMA_FILTER_SUBBLOCK, + LZMA_FILTER_SUBBLOCK_HELPER, +#endif + +#ifdef HAVE_DECODER_X86 + LZMA_FILTER_X86, +#endif + +#ifdef HAVE_DECODER_POWERPC + LZMA_FILTER_POWERPC, +#endif + +#ifdef HAVE_DECODER_IA64 + LZMA_FILTER_IA64, +#endif + +#ifdef HAVE_DECODER_ARM + LZMA_FILTER_ARM, +#endif + +#ifdef HAVE_DECODER_ARMTHUMB + LZMA_FILTER_ARMTHUMB, +#endif + +#ifdef HAVE_DECODER_SPARC + LZMA_FILTER_SPARC, +#endif + +#ifdef HAVE_DECODER_DELTA + LZMA_FILTER_DELTA, +#endif + + LZMA_VLI_VALUE_UNKNOWN +}; + + +// Using a pointer to avoid putting the size of the array to API/ABI. +LZMA_API const lzma_vli *const lzma_filter_decoders = ids; + + +// These must be in the same order as ids[]. +static const lzma_filter_decoder funcs[] = { +#ifdef HAVE_DECODER_LZMA + { + .init = &lzma_lzma_decoder_init, + .memusage = &lzma_lzma_decoder_memusage, + .props_decode = &lzma_lzma_props_decode, + }, +#endif +#ifdef HAVE_DECODER_LZMA2 + { + .init = &lzma_lzma2_decoder_init, + .memusage = &lzma_lzma2_decoder_memusage, + .props_decode = &lzma_lzma2_props_decode, + }, +#endif +#ifdef HAVE_DECODER_SUBBLOCK + { + .init = &lzma_subblock_decoder_init, +// .memusage = &lzma_subblock_decoder_memusage, + .props_decode = NULL, + }, + { + .init = &lzma_subblock_decoder_helper_init, + .memusage = NULL, + .props_decode = NULL, + }, +#endif +#ifdef HAVE_DECODER_X86 + { + .init = &lzma_simple_x86_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif +#ifdef HAVE_DECODER_POWERPC + { + .init = &lzma_simple_powerpc_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif +#ifdef HAVE_DECODER_IA64 + { + .init = &lzma_simple_ia64_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif +#ifdef HAVE_DECODER_ARM + { + .init = &lzma_simple_arm_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif +#ifdef HAVE_DECODER_ARMTHUMB + { + .init = &lzma_simple_armthumb_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif +#ifdef HAVE_DECODER_SPARC + { + .init = &lzma_simple_sparc_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif +#ifdef HAVE_DECODER_DELTA + { + .init = &lzma_delta_decoder_init, + .memusage = NULL, + .props_decode = &lzma_delta_props_decode, + }, +#endif +}; + + +static const lzma_filter_decoder * +decoder_find(lzma_vli id) +{ + for (size_t i = 0; ids[i] != LZMA_VLI_VALUE_UNKNOWN; ++i) + if (ids[i] == id) + return funcs + i; + + return NULL; +} + + +extern lzma_ret +lzma_raw_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter *options) +{ + return lzma_raw_coder_init(next, allocator, + options, (lzma_filter_find)(&decoder_find), false); +} + + +extern LZMA_API lzma_ret +lzma_raw_decoder(lzma_stream *strm, const lzma_filter *options) +{ + lzma_next_strm_init(lzma_raw_decoder_init, strm, options); + + strm->internal->supported_actions[LZMA_RUN] = true; + strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; + + return LZMA_OK; +} + + +extern LZMA_API uint64_t +lzma_memusage_decoder(const lzma_filter *filters) +{ + return lzma_memusage_coder( + (lzma_filter_find)(&decoder_find), filters); +} + + +extern LZMA_API lzma_ret +lzma_properties_decode(lzma_filter *filter, lzma_allocator *allocator, + const uint8_t *props, size_t props_size) +{ + // Make it always NULL so that the caller can always safely free() it. + filter->options = NULL; + + const lzma_filter_decoder *const fd = decoder_find(filter->id); + if (fd == NULL) + return LZMA_HEADER_ERROR; + + if (fd->props_decode == NULL) + return props_size == 0 ? LZMA_OK : LZMA_HEADER_ERROR; + + return fd->props_decode( + &filter->options, allocator, props, props_size); +} diff --git a/src/liblzma/common/raw_common.h b/src/liblzma/common/filter_decoder.h index 0a27f3dc..33e491d1 100644 --- a/src/liblzma/common/raw_common.h +++ b/src/liblzma/common/filter_decoder.h @@ -1,9 +1,9 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file raw_common.h -/// \brief Stuff shared between raw encoder and raw decoder +/// \file filter_decoder.c +/// \brief Filter ID mapping to filter-specific functions // -// Copyright (C) 2007 Lasse Collin +// Copyright (C) 2008 Lasse Collin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -17,14 +17,19 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifndef LZMA_RAW_COMMON_H -#define LZMA_RAW_COMMON_H +#ifndef LZMA_FILTER_DECODER_H +#define LZMA_FILTER_DECODER_H #include "common.h" -extern lzma_ret lzma_raw_coder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_options_filter *options, - lzma_init_function (*get_function)(lzma_vli id), - bool is_encoder); +// FIXME !!! Public API +extern lzma_ret lzma_properties_decode( + lzma_filter *filter, lzma_allocator *allocator, + const uint8_t *props, size_t props_size); + + +extern lzma_ret lzma_raw_decoder_init( + lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter *options); #endif diff --git a/src/liblzma/common/filter_encoder.c b/src/liblzma/common/filter_encoder.c new file mode 100644 index 00000000..55862e18 --- /dev/null +++ b/src/liblzma/common/filter_encoder.c @@ -0,0 +1,308 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file filter_decoder.c +/// \brief Filter ID mapping to filter-specific functions +// +// Copyright (C) 2008 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 "filter_encoder.h" +#include "filter_common.h" +#include "lzma_encoder.h" +#include "lzma2_encoder.h" +#include "subblock_encoder.h" +#include "simple_encoder.h" +#include "delta_encoder.h" + + +typedef struct { + /// Initializes the filter encoder and calls lzma_next_filter_init() + /// for filters + 1. + lzma_init_function init; + + /// Calculates memory usage of the encoder. If the options are + /// invalid, UINT64_MAX is returned. + uint64_t (*memusage)(const void *options); + + /// Calculates the minimum sane size for Blocks (or other types of + /// chunks) to which the input data can be splitted to make + /// multithreaded encoding possible. If this is NULL, it is assumed + /// that the encoder is fast enough with single thread. + lzma_vli (*chunk_size)(const void *options); + + /// Tells the size of the Filter Properties field. If options are + /// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed + /// is used. + lzma_ret (*props_size_get)(uint32_t *size, const void *options); + uint32_t props_size_fixed; + + /// Encodes Filter Properties. + /// + /// \return - LZMA_OK: Properties encoded sucessfully. + /// - LZMA_HEADER_ERROR: Unsupported options + /// - LZMA_PROG_ERROR: Invalid options or not enough + /// output space + lzma_ret (*props_encode)(const void *options, uint8_t *out); + +} lzma_filter_encoder; + + +static const lzma_vli ids[] = { +#ifdef HAVE_ENCODER_LZMA + LZMA_FILTER_LZMA, +#endif + +#ifdef HAVE_ENCODER_LZMA2 + LZMA_FILTER_LZMA2, +#endif + +#ifdef HAVE_ENCODER_SUBBLOCK + LZMA_FILTER_SUBBLOCK, +#endif + +#ifdef HAVE_ENCODER_X86 + LZMA_FILTER_X86, +#endif + +#ifdef HAVE_ENCODER_POWERPC + LZMA_FILTER_POWERPC, +#endif + +#ifdef HAVE_ENCODER_IA64 + LZMA_FILTER_IA64, +#endif + +#ifdef HAVE_ENCODER_ARM + LZMA_FILTER_ARM, +#endif + +#ifdef HAVE_ENCODER_ARMTHUMB + LZMA_FILTER_ARMTHUMB, +#endif + +#ifdef HAVE_ENCODER_SPARC + LZMA_FILTER_SPARC, +#endif + +#ifdef HAVE_ENCODER_DELTA + LZMA_FILTER_DELTA, +#endif + + LZMA_VLI_VALUE_UNKNOWN +}; + + +// Using a pointer to avoid putting the size of the array to API/ABI. +LZMA_API const lzma_vli *const lzma_filter_encoders = ids; + + +// These must be in the same order as ids[]. +static const lzma_filter_encoder funcs[] = { +#ifdef HAVE_ENCODER_LZMA + { + .init = &lzma_lzma_encoder_init, + .memusage = &lzma_lzma_encoder_memusage, + .chunk_size = NULL, // FIXME + .props_size_get = NULL, + .props_size_fixed = 5, + .props_encode = &lzma_lzma_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_LZMA2 + { + .init = &lzma_lzma2_encoder_init, + .memusage = &lzma_lzma2_encoder_memusage, + .chunk_size = NULL, // FIXME + .props_size_get = NULL, + .props_size_fixed = 1, + .props_encode = &lzma_lzma2_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_SUBBLOCK + { + .init = &lzma_subblock_encoder_init, +// .memusage = &lzma_subblock_encoder_memusage, + .chunk_size = NULL, + .props_size_get = NULL, + .props_size_fixed = 0, + .props_encode = NULL, + }, +#endif +#ifdef HAVE_ENCODER_X86 + { + .init = &lzma_simple_x86_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_POWERPC + { + .init = &lzma_simple_powerpc_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_IA64 + { + .init = &lzma_simple_ia64_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_ARM + { + .init = &lzma_simple_arm_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_ARMTHUMB + { + .init = &lzma_simple_armthumb_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_SPARC + { + .init = &lzma_simple_sparc_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif +#ifdef HAVE_ENCODER_DELTA + { + .init = &lzma_delta_encoder_init, + .memusage = NULL, + .chunk_size = NULL, + .props_size_get = NULL, + .props_size_fixed = 1, + .props_encode = &lzma_delta_props_encode, + }, +#endif +}; + + +static const lzma_filter_encoder * +encoder_find(lzma_vli id) +{ + for (size_t i = 0; ids[i] != LZMA_VLI_VALUE_UNKNOWN; ++i) + if (ids[i] == id) + return funcs + i; + + return NULL; +} + + +extern lzma_ret +lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter *options) +{ + return lzma_raw_coder_init(next, allocator, + options, (lzma_filter_find)(&encoder_find), true); +} + + +extern LZMA_API lzma_ret +lzma_raw_encoder(lzma_stream *strm, const lzma_filter *options) +{ + lzma_next_strm_init(lzma_raw_coder_init, strm, options, + (lzma_filter_find)(&encoder_find), true); + + strm->internal->supported_actions[LZMA_RUN] = true; + strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; + strm->internal->supported_actions[LZMA_FINISH] = true; + + return LZMA_OK; +} + + +extern LZMA_API uint64_t +lzma_memusage_encoder(const lzma_filter *filters) +{ + return lzma_memusage_coder( + (lzma_filter_find)(&encoder_find), filters); +} + + +extern LZMA_API lzma_vli +lzma_chunk_size(const lzma_filter *filters) +{ + uint64_t max = 0; + + for (size_t i = 0; filters[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) { + const lzma_filter_encoder *const fe + = encoder_find(filters[i].id); + if (fe->chunk_size != NULL) { + const lzma_vli size + = fe->chunk_size(filters[i].options); + if (size == LZMA_VLI_VALUE_UNKNOWN) + return LZMA_VLI_VALUE_UNKNOWN; + + if (size > max) + max = size; + } + } + + return max; +} + + +extern LZMA_API lzma_ret +lzma_properties_size(uint32_t *size, const lzma_filter *filter) +{ + const lzma_filter_encoder *const fe = encoder_find(filter->id); + if (fe == NULL) { + // 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. + return filter->id <= LZMA_VLI_VALUE_MAX + ? LZMA_HEADER_ERROR : LZMA_PROG_ERROR; + } + + if (fe->props_size_get == NULL) { + // No props_size() function, use props_size_fixed. + *size = fe->props_size_fixed; + return LZMA_OK; + } + + return fe->props_size_get(size, filter->options); +} + + +extern LZMA_API lzma_ret +lzma_properties_encode(const lzma_filter *filter, uint8_t *props) +{ + const lzma_filter_encoder *const fe = encoder_find(filter->id); + if (fe == NULL) + return LZMA_PROG_ERROR; + + if (fe->props_encode == NULL) + return LZMA_OK; + + return fe->props_encode(filter->options, props); +} diff --git a/src/liblzma/common/delta_common.h b/src/liblzma/common/filter_encoder.h index 1d58899d..b2bf851d 100644 --- a/src/liblzma/common/delta_common.h +++ b/src/liblzma/common/filter_encoder.h @@ -1,9 +1,9 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file delta_common.h -/// \brief Common stuff for Delta encoder and decoder +/// \file filter_encoder.c +/// \brief Filter ID mapping to filter-specific functions // -// Copyright (C) 2007 Lasse Collin +// Copyright (C) 2008 Lasse Collin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -17,28 +17,22 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifndef LZMA_DELTA_COMMON_H -#define LZMA_DELTA_COMMON_H +#ifndef LZMA_FILTER_ENCODER_H +#define LZMA_FILTER_ENCODER_H #include "common.h" -struct lzma_coder_s { - /// Next coder in the chain - lzma_next_coder next; - /// Delta distance - size_t distance; +// FIXME !!! Public API +extern lzma_vli lzma_chunk_size(const lzma_filter *filters); +extern lzma_ret lzma_properties_size( + uint32_t *size, const lzma_filter *filter); +extern lzma_ret lzma_properties_encode( + const lzma_filter *filter, uint8_t *props); - /// Position in history[] - uint8_t pos; - /// Buffer to hold history of the original data - uint8_t history[LZMA_DELTA_DISTANCE_MAX]; -}; - - -extern lzma_ret lzma_delta_coder_init( +extern lzma_ret lzma_raw_encoder_init( lzma_next_coder *next, lzma_allocator *allocator, - const lzma_filter_info *filters, lzma_code_function code); + const lzma_filter *options); #endif diff --git a/src/liblzma/common/filter_flags_decoder.c b/src/liblzma/common/filter_flags_decoder.c index 498b2ad6..c2247312 100644 --- a/src/liblzma/common/filter_flags_decoder.c +++ b/src/liblzma/common/filter_flags_decoder.c @@ -17,192 +17,37 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "common.h" -#include "lzma_decoder.h" - - -#ifdef HAVE_FILTER_SUBBLOCK -static lzma_ret -properties_subblock(lzma_options_filter *options, lzma_allocator *allocator, - const uint8_t *props lzma_attribute((unused)), - size_t prop_size lzma_attribute((unused))) -{ - if (prop_size != 0) - return LZMA_HEADER_ERROR; - - options->options = lzma_alloc( - sizeof(lzma_options_subblock), allocator); - if (options->options == NULL) - return LZMA_MEM_ERROR; - - ((lzma_options_subblock *)(options->options))->allow_subfilters = true; - return LZMA_OK; -} -#endif - - -#ifdef HAVE_FILTER_SIMPLE -static lzma_ret -properties_simple(lzma_options_filter *options, lzma_allocator *allocator, - const uint8_t *props, size_t prop_size) -{ - if (prop_size == 0) - return LZMA_OK; - - if (prop_size != 4) - return LZMA_HEADER_ERROR; - - lzma_options_simple *simple = lzma_alloc( - sizeof(lzma_options_simple), allocator); - if (simple == NULL) - return LZMA_MEM_ERROR; - - simple->start_offset = integer_read_32(props); - - // Don't leave an options structure allocated if start_offset is zero. - if (simple->start_offset == 0) - lzma_free(simple, allocator); - else - options->options = simple; - - return LZMA_OK; -} -#endif - - -#ifdef HAVE_FILTER_DELTA -static lzma_ret -properties_delta(lzma_options_filter *options, lzma_allocator *allocator, - const uint8_t *props, size_t prop_size) -{ - if (prop_size != 1) - return LZMA_HEADER_ERROR; - - options->options = lzma_alloc(sizeof(lzma_options_delta), allocator); - if (options->options == NULL) - return LZMA_MEM_ERROR; - - ((lzma_options_delta *)(options->options))->distance - = (uint32_t)(props[0]) + 1; - - return LZMA_OK; -} -#endif - - -#ifdef HAVE_FILTER_LZMA -static lzma_ret -properties_lzma(lzma_options_filter *options, lzma_allocator *allocator, - const uint8_t *props, size_t prop_size) -{ - // LZMA properties are always two bytes (at least for now). - if (prop_size != 2) - return LZMA_HEADER_ERROR; - - lzma_options_lzma *lzma = lzma_alloc( - sizeof(lzma_options_lzma), allocator); - if (lzma == NULL) - return LZMA_MEM_ERROR; - - // Decode lc, lp, and pb. - if (lzma_lzma_decode_properties(lzma, props[0])) - goto error; - - // Check that reserved bits are unset. - if (props[1] & 0xC0) - goto error; - - // Decode the dictionary size. - // FIXME The specification says that maximum is 4 GiB. - if (props[1] > 36) - goto error; -#if LZMA_DICTIONARY_SIZE_MAX != UINT32_C(1) << 30 -# error Update the if()-condition a few lines -# error above to match LZMA_DICTIONARY_SIZE_MAX. -#endif - - lzma->dictionary_size = 2 | (props[1] & 1); - lzma->dictionary_size <<= props[1] / 2 + 11; - - options->options = lzma; - return LZMA_OK; - -error: - lzma_free(lzma, allocator); - return LZMA_HEADER_ERROR; -} -#endif +#include "filter_decoder.h" extern LZMA_API lzma_ret lzma_filter_flags_decode( - lzma_options_filter *options, lzma_allocator *allocator, + lzma_filter *filter, lzma_allocator *allocator, const uint8_t *in, size_t *in_pos, size_t in_size) { // Set the pointer to NULL so the caller can always safely free it. - options->options = NULL; + filter->options = NULL; // Filter ID - return_if_error(lzma_vli_decode(&options->id, NULL, + return_if_error(lzma_vli_decode(&filter->id, NULL, in, in_pos, in_size)); + if (filter->id >= LZMA_FILTER_RESERVED_START) + return LZMA_DATA_ERROR; + // Size of Properties - lzma_vli prop_size; - return_if_error(lzma_vli_decode(&prop_size, NULL, + lzma_vli props_size; + return_if_error(lzma_vli_decode(&props_size, NULL, in, in_pos, in_size)); - // Check that we have enough input. - if (prop_size > in_size - *in_pos) + // Filter Properties + if (in_size - *in_pos < props_size) return LZMA_DATA_ERROR; - // Determine the function to decode the properties. - lzma_ret (*get_properties)(lzma_options_filter *options, - lzma_allocator *allocator, const uint8_t *props, - size_t prop_size); + const lzma_ret ret = lzma_properties_decode( + filter, allocator, in + *in_pos, props_size); - switch (options->id) { -#ifdef HAVE_FILTER_SUBBLOCK - case LZMA_FILTER_SUBBLOCK: - get_properties = &properties_subblock; - 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 - get_properties = &properties_simple; - break; -#endif -#ifdef HAVE_FILTER_DELTA - case LZMA_FILTER_DELTA: - get_properties = &properties_delta; - break; -#endif -#ifdef HAVE_FILTER_LZMA - case LZMA_FILTER_LZMA: - get_properties = &properties_lzma; - break; -#endif - default: - return LZMA_HEADER_ERROR; - } + *in_pos += props_size; - const uint8_t *props = in + *in_pos; - *in_pos += prop_size; - return get_properties(options, allocator, props, prop_size); + return ret; } diff --git a/src/liblzma/common/filter_flags_encoder.c b/src/liblzma/common/filter_flags_encoder.c index 45fbbb00..46464c0f 100644 --- a/src/liblzma/common/filter_flags_encoder.c +++ b/src/liblzma/common/filter_flags_encoder.c @@ -17,267 +17,46 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "common.h" -#include "lzma_encoder.h" -#include "fastpos.h" - - -/// Calculate the size of the Filter Properties field -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; -} +#include "filter_encoder.h" 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. - uint32_t prop_size; - return_if_error(get_properties_size(&prop_size, options)); - - // 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; - - 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; - - integer_write_32(out + *out_pos, options->start_offset); - *out_pos += 4; - - 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; - - 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) +lzma_filter_flags_size(uint32_t *size, const lzma_filter *filter) { - if (options == NULL) - return LZMA_PROG_ERROR; - - if (out_size - *out_pos < 2) - return LZMA_PROG_ERROR; - - // LZMA Properties - if (lzma_lzma_encode_properties(options, out + *out_pos)) - return LZMA_HEADER_ERROR; - - ++*out_pos; + return_if_error(lzma_properties_size(size, filter)); - // Dictionary flags - // - // Dictionary size is encoded using similar encoding that is used - // internally by LZMA. - // - // This won't work if dictionary size can be zero: -# if LZMA_DICTIONARY_SIZE_MIN < 1 -# error LZMA_DICTIONARY_SIZE_MIN cannot be zero. -# endif - - uint32_t d = options->dictionary_size; - - // Validate it: - if (d < LZMA_DICTIONARY_SIZE_MIN || d > LZMA_DICTIONARY_SIZE_MAX) - 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; - ++*out_pos; + // lzma_properties_size() validates the Filter ID as a side-effect, + // so we know that it is a valid VLI. + *size += lzma_vli_size(filter->id) + lzma_vli_size(*size); 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) +lzma_filter_flags_encode(const lzma_filter *filter, + uint8_t *out, size_t *out_pos, size_t out_size) { - // 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, + if (filter->id >= LZMA_FILTER_RESERVED_START) + return LZMA_HEADER_ERROR; + + return_if_error(lzma_vli_encode(filter->id, NULL, out, out_pos, out_size)); // Size of Properties - return_if_error(lzma_vli_encode(prop_size, NULL, + uint32_t props_size; + return_if_error(lzma_properties_size(&props_size, filter)); + return_if_error(lzma_vli_encode(props_size, NULL, out, out_pos, out_size)); // Filter Properties - lzma_ret ret; - 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 + if (out_size - *out_pos < props_size) + return LZMA_PROG_ERROR; -#ifdef HAVE_FILTER_LZMA - case LZMA_FILTER_LZMA: - ret = properties_lzma(out, out_pos, out_size, - options->options); - break; -#endif + return_if_error(lzma_properties_encode(filter, out + *out_pos)); - default: - assert(0); - ret = LZMA_PROG_ERROR; - break; - } + *out_pos += props_size; - return ret; + return LZMA_OK; } diff --git a/src/liblzma/common/index_decoder.c b/src/liblzma/common/index_decoder.c index 1635948c..ae66595a 100644 --- a/src/liblzma/common/index_decoder.c +++ b/src/liblzma/common/index_decoder.c @@ -201,6 +201,8 @@ static lzma_ret index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, lzma_index **i) { + lzma_next_coder_init(index_decoder_init, next, allocator); + if (i == NULL) return LZMA_PROG_ERROR; @@ -231,20 +233,10 @@ index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, } -/* -extern lzma_ret -lzma_index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_index **i) -{ - lzma_next_coder_init(index_decoder_init, next, allocator, i); -} -*/ - - extern LZMA_API lzma_ret lzma_index_decoder(lzma_stream *strm, lzma_index **i) { - lzma_next_strm_init(strm, index_decoder_init, i); + lzma_next_strm_init(index_decoder_init, strm, i); strm->internal->supported_actions[LZMA_RUN] = true; diff --git a/src/liblzma/common/index_encoder.c b/src/liblzma/common/index_encoder.c index 5a7d8c8c..3005f835 100644 --- a/src/liblzma/common/index_encoder.c +++ b/src/liblzma/common/index_encoder.c @@ -176,10 +176,12 @@ index_encoder_end(lzma_coder *coder, lzma_allocator *allocator) } -static lzma_ret -index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, +extern lzma_ret +lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, lzma_index *i) { + lzma_next_coder_init(lzma_index_encoder_init, next, allocator); + if (i == NULL) return LZMA_PROG_ERROR; @@ -203,18 +205,10 @@ index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, } -extern lzma_ret -lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - lzma_index *i) -{ - lzma_next_coder_init(index_encoder_init, next, allocator, i); -} - - extern LZMA_API lzma_ret lzma_index_encoder(lzma_stream *strm, lzma_index *i) { - lzma_next_strm_init(strm, index_encoder_init, i); + lzma_next_strm_init(lzma_index_encoder_init, strm, i); strm->internal->supported_actions[LZMA_RUN] = true; diff --git a/src/liblzma/common/index_hash.c b/src/liblzma/common/index_hash.c index 35dea41f..dc533f9e 100644 --- a/src/liblzma/common/index_hash.c +++ b/src/liblzma/common/index_hash.c @@ -36,7 +36,7 @@ typedef struct { lzma_vli index_list_size; /// Check calculated from Total Sizes and Uncompressed Sizes. - lzma_check check; + lzma_check_state check; } lzma_index_hash_info; @@ -300,9 +300,9 @@ lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in, // Finish the hashes and compare them. lzma_check_finish(&index_hash->blocks.check, LZMA_CHECK_BEST); lzma_check_finish(&index_hash->records.check, LZMA_CHECK_BEST); - if (memcmp(index_hash->blocks.check.buffer, - index_hash->records.check.buffer, - lzma_check_sizes[LZMA_CHECK_BEST]) != 0) + if (memcmp(index_hash->blocks.check.buffer.u8, + index_hash->records.check.buffer.u8, + lzma_check_size(LZMA_CHECK_BEST)) != 0) return LZMA_DATA_ERROR; // Finish the CRC32 calculation. diff --git a/src/liblzma/common/init_encoder.c b/src/liblzma/common/init_encoder.c index 8a1644be..c5f12a91 100644 --- a/src/liblzma/common/init_encoder.c +++ b/src/liblzma/common/init_encoder.c @@ -31,7 +31,7 @@ lzma_init_encoder(void) lzma_init_check(); -#if defined(HAVE_SMALL) && defined(HAVE_ENCODER) && defined(HAVE_FILTER_LZMA) +#if defined(HAVE_SMALL) && defined(HAVE_ENCODER_LZMA) lzma_rc_init(); #endif diff --git a/src/liblzma/common/memory_usage.c b/src/liblzma/common/memory_usage.c deleted file mode 100644 index 8244c404..00000000 --- a/src/liblzma/common/memory_usage.c +++ /dev/null @@ -1,112 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file memory_usage.c -/// \brief Calculate rough amount of memory required by filters -// -// 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 "lz_encoder.h" -#include "lzma_literal.h" - - -static uint64_t -get_usage(const lzma_options_filter *filter, bool is_encoder) -{ - uint64_t ret; - - switch (filter->id) { - case LZMA_FILTER_X86: - case LZMA_FILTER_POWERPC: - case LZMA_FILTER_IA64: - case LZMA_FILTER_ARM: - case LZMA_FILTER_ARMTHUMB: - case LZMA_FILTER_SPARC: - case LZMA_FILTER_DELTA: - // These don't require any significant amount of memory. - ret = 0; - break; - - case LZMA_FILTER_SUBBLOCK: - if (is_encoder) { - const lzma_options_subblock *options = filter->options; - ret = options->subblock_data_size; - } else { - ret = 0; - } - break; - -#ifdef HAVE_FILTER_LZMA - case LZMA_FILTER_LZMA: { - const lzma_options_lzma *options = filter->options; - - // Literal coder - this can be signficant if both values are - // big, or if sizeof(probability) is big. - ret = literal_states(options->literal_context_bits, - options->literal_pos_bits) * LIT_SIZE - * sizeof(probability); - - // Dictionary base size - ret += options->dictionary_size; - - if (is_encoder) { -# ifdef HAVE_ENCODER - // This is rough, but should be accurate enough - // in practice. - ret += options->dictionary_size / 2; - - uint32_t dummy1; - uint32_t dummy2; - uint32_t num_items; - if (lzma_lz_encoder_hash_properties( - options->match_finder, - options->dictionary_size, - &dummy1, &dummy2, &num_items)) - return UINT64_MAX; - - ret += (uint64_t)(num_items) * sizeof(uint32_t); -# else - return UINT64_MAX; -# endif - } - - break; - } -#endif - - default: - return UINT64_MAX; - } - - return ret; -} - - -extern LZMA_API uint32_t -lzma_memory_usage(const lzma_options_filter *filters, lzma_bool is_encoder) -{ - uint64_t usage = 0; - - for (size_t i = 0; filters[i].id != UINT64_MAX; ++i) { - const uint64_t ret = get_usage(filters + i, is_encoder); - if (ret == UINT64_MAX) - return UINT32_MAX; - - usage += ret; - } - - // Convert to mebibytes with rounding. - return usage / (1024 * 1024) + (usage % (1024 * 1024) >= 512 ? 1 : 0); -} diff --git a/src/liblzma/common/next_coder.c b/src/liblzma/common/next_coder.c deleted file mode 100644 index c10fe24d..00000000 --- a/src/liblzma/common/next_coder.c +++ /dev/null @@ -1,65 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file next_coder.c -/// \brief Initializing and freeing the next coder in the chain -// -// 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" - -extern lzma_ret -lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_filter_info *filters) -{ - lzma_ret ret = LZMA_OK; - - // Free the existing coder if it is different than the current one. - if ((uintptr_t)(filters[0].init) != next->init) - lzma_next_coder_end(next, allocator); - - if (filters[0].init != NULL) { - // Initialize the new coder. - ret = filters[0].init(next, allocator, filters); - - // Set the init function pointer if initialization was - // successful. next->code and next->end are set by the - // initialization function itself. - if (ret == LZMA_OK) { - next->init = (uintptr_t)(filters[0].init); - assert(next->code != NULL); - assert(next->end != NULL); - } else { - lzma_next_coder_end(next, allocator); - } - } - - return ret; -} - - -extern void -lzma_next_coder_end(lzma_next_coder *next, lzma_allocator *allocator) -{ - if (next != NULL) { - if (next->end != NULL) - next->end(next->coder, allocator); - - // Reset the variables so the we don't accidentally think - // that it is an already initialized coder. - *next = LZMA_NEXT_CODER_INIT; - } - - return; -} diff --git a/src/liblzma/common/raw_common.c b/src/liblzma/common/raw_common.c deleted file mode 100644 index 35252fc2..00000000 --- a/src/liblzma/common/raw_common.c +++ /dev/null @@ -1,127 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file raw_common.c -/// \brief Stuff shared between raw encoder and raw decoder -// -// 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 "raw_common.h" - - -static lzma_ret -validate_options(const lzma_options_filter *options, size_t *count) -{ - if (options == NULL) - return LZMA_PROG_ERROR; - - // Number of non-last filters that may change the size of the data - // significantly (that is, more than 1-2 % or so). - size_t change = 0; - - // True if the last filter in the given chain is actually usable as - // the last filter. Only filters that support embedding End of Payload - // Marker can be used as the last filter in the chain. - bool last_ok = false; - - size_t i; - for (i = 0; options[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) { - switch (options[i].id) { - // Not #ifdeffing these for simplicity. - case LZMA_FILTER_X86: - case LZMA_FILTER_POWERPC: - case LZMA_FILTER_IA64: - case LZMA_FILTER_ARM: - case LZMA_FILTER_ARMTHUMB: - case LZMA_FILTER_SPARC: - case LZMA_FILTER_DELTA: - // These don't change the size of the data and cannot - // be used as the last filter in the chain. - last_ok = false; - break; - -#ifdef HAVE_FILTER_SUBBLOCK - case LZMA_FILTER_SUBBLOCK: - last_ok = true; - ++change; - break; -#endif - -#ifdef HAVE_FILTER_LZMA - case LZMA_FILTER_LZMA: - last_ok = true; - break; -#endif - - default: - return LZMA_HEADER_ERROR; - } - } - - // There must be 1-4 filters and the last filter must be usable as - // the last filter in the chain. - if (i == 0 || i > 4 || !last_ok) - return LZMA_HEADER_ERROR; - - // At maximum of two non-last filters are allowed to change the - // size of the data. - if (change > 2) - return LZMA_HEADER_ERROR; - - *count = i; - return LZMA_OK; -} - - -extern lzma_ret -lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_options_filter *options, - lzma_init_function (*get_function)(lzma_vli id), - bool is_encoder) -{ - // Do some basic validation and get the number of filters. - size_t count; - return_if_error(validate_options(options, &count)); - - // Set the filter functions and copy the options pointer. - lzma_filter_info filters[count + 1]; - if (is_encoder) { - for (size_t i = 0; i < count; ++i) { - // The order of the filters is reversed in the - // encoder. It allows more efficient handling - // of the uncompressed data. - const size_t j = count - i - 1; - - filters[j].init = get_function(options[i].id); - if (filters[j].init == NULL) - return LZMA_HEADER_ERROR; - - filters[j].options = options[i].options; - } - } else { - for (size_t i = 0; i < count; ++i) { - filters[i].init = get_function(options[i].id); - if (filters[i].init == NULL) - return LZMA_HEADER_ERROR; - - filters[i].options = options[i].options; - } - } - - // Terminate the array. - filters[count].init = NULL; - - // Initialize the filters. - return lzma_next_filter_init(next, allocator, filters); -} diff --git a/src/liblzma/common/raw_decoder.c b/src/liblzma/common/raw_decoder.c deleted file mode 100644 index 4fb7111c..00000000 --- a/src/liblzma/common/raw_decoder.c +++ /dev/null @@ -1,116 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file raw_decoder.c -/// \brief Raw decoder initialization API -// -// 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 "raw_decoder.h" -#include "simple_coder.h" -#include "subblock_decoder.h" -#include "subblock_decoder_helper.h" -#include "delta_decoder.h" -#include "lzma_decoder.h" - - -static lzma_init_function -get_function(lzma_vli id) -{ - switch (id) { -#ifdef HAVE_FILTER_SUBBLOCK - case LZMA_FILTER_SUBBLOCK: - return &lzma_subblock_decoder_init; -#endif - -#ifdef HAVE_FILTER_X86 - case LZMA_FILTER_X86: - return &lzma_simple_x86_decoder_init; -#endif - -#ifdef HAVE_FILTER_POWERPC - case LZMA_FILTER_POWERPC: - return &lzma_simple_powerpc_decoder_init; -#endif - -#ifdef HAVE_FILTER_IA64 - case LZMA_FILTER_IA64: - return &lzma_simple_ia64_decoder_init; -#endif - -#ifdef HAVE_FILTER_ARM - case LZMA_FILTER_ARM: - return &lzma_simple_arm_decoder_init; -#endif - -#ifdef HAVE_FILTER_ARMTHUMB - case LZMA_FILTER_ARMTHUMB: - return &lzma_simple_armthumb_decoder_init; -#endif - -#ifdef HAVE_FILTER_SPARC - case LZMA_FILTER_SPARC: - return &lzma_simple_sparc_decoder_init; -#endif - -#ifdef HAVE_FILTER_DELTA - case LZMA_FILTER_DELTA: - return &lzma_delta_decoder_init; -#endif - -#ifdef HAVE_FILTER_LZMA - case LZMA_FILTER_LZMA: - return &lzma_lzma_decoder_init; -#endif - -#ifdef HAVE_FILTER_SUBBLOCK - case LZMA_FILTER_SUBBLOCK_HELPER: - return &lzma_subblock_decoder_helper_init; -#endif - } - - return NULL; -} - - -extern lzma_ret -lzma_raw_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_options_filter *options) -{ - const lzma_ret ret = lzma_raw_coder_init(next, allocator, - options, &get_function, false); - - if (ret != LZMA_OK) - lzma_next_coder_end(next, allocator); - - return ret; -} - - -extern LZMA_API lzma_ret -lzma_raw_decoder(lzma_stream *strm, const lzma_options_filter *options) -{ - return_if_error(lzma_strm_init(strm)); - - strm->internal->supported_actions[LZMA_RUN] = true; - strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; - - const lzma_ret ret = lzma_raw_coder_init(&strm->internal->next, - strm->allocator, options, &get_function, false); - - if (ret != LZMA_OK) - lzma_end(strm); - - return ret; -} diff --git a/src/liblzma/common/raw_decoder.h b/src/liblzma/common/raw_decoder.h deleted file mode 100644 index c0e626a8..00000000 --- a/src/liblzma/common/raw_decoder.h +++ /dev/null @@ -1,29 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file raw_decoder.h -/// \brief Raw decoder initialization API -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef LZMA_RAW_DECODER_H -#define LZMA_RAW_DECODER_H - -#include "raw_common.h" - - -extern lzma_ret lzma_raw_decoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_options_filter *options); - -#endif diff --git a/src/liblzma/common/raw_encoder.c b/src/liblzma/common/raw_encoder.c deleted file mode 100644 index 9b8cbfae..00000000 --- a/src/liblzma/common/raw_encoder.c +++ /dev/null @@ -1,111 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file raw_encoder.c -/// \brief Raw encoder initialization API -// -// 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 "raw_encoder.h" -#include "simple_coder.h" -#include "subblock_encoder.h" -#include "delta_encoder.h" -#include "lzma_encoder.h" - - -static lzma_init_function -get_function(lzma_vli id) -{ - switch (id) { -#ifdef HAVE_FILTER_SUBBLOCK - case LZMA_FILTER_SUBBLOCK: - return &lzma_subblock_encoder_init; -#endif - -#ifdef HAVE_FILTER_X86 - case LZMA_FILTER_X86: - return &lzma_simple_x86_encoder_init; -#endif - -#ifdef HAVE_FILTER_POWERPC - case LZMA_FILTER_POWERPC: - return &lzma_simple_powerpc_encoder_init; -#endif - -#ifdef HAVE_FILTER_IA64 - case LZMA_FILTER_IA64: - return &lzma_simple_ia64_encoder_init; -#endif - -#ifdef HAVE_FILTER_ARM - case LZMA_FILTER_ARM: - return &lzma_simple_arm_encoder_init; -#endif - -#ifdef HAVE_FILTER_ARMTHUMB - case LZMA_FILTER_ARMTHUMB: - return &lzma_simple_armthumb_encoder_init; -#endif - -#ifdef HAVE_FILTER_SPARC - case LZMA_FILTER_SPARC: - return &lzma_simple_sparc_encoder_init; -#endif - -#ifdef HAVE_FILTER_DELTA - case LZMA_FILTER_DELTA: - return &lzma_delta_encoder_init; -#endif - -#ifdef HAVE_FILTER_LZMA - case LZMA_FILTER_LZMA: - return &lzma_lzma_encoder_init; -#endif - } - - return NULL; -} - - -extern lzma_ret -lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_options_filter *options) -{ - const lzma_ret ret = lzma_raw_coder_init(next, allocator, - options, &get_function, true); - - if (ret != LZMA_OK) - lzma_next_coder_end(next, allocator); - - return ret; -} - - -extern LZMA_API lzma_ret -lzma_raw_encoder(lzma_stream *strm, const lzma_options_filter *options) -{ - return_if_error(lzma_strm_init(strm)); - - strm->internal->supported_actions[LZMA_RUN] = true; - strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; - strm->internal->supported_actions[LZMA_FINISH] = true; - - const lzma_ret ret = lzma_raw_coder_init(&strm->internal->next, - strm->allocator, options, &get_function, true); - - if (ret != LZMA_OK) - lzma_end(strm); - - return ret; -} diff --git a/src/liblzma/common/raw_encoder.h b/src/liblzma/common/raw_encoder.h deleted file mode 100644 index 4e148489..00000000 --- a/src/liblzma/common/raw_encoder.h +++ /dev/null @@ -1,29 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file raw_encoder.h -/// \brief Raw encoder initialization API -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef LZMA_RAW_ENCODER_H -#define LZMA_RAW_ENCODER_H - -#include "raw_common.h" - - -extern lzma_ret lzma_raw_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_options_filter *options); - -#endif diff --git a/src/liblzma/common/stream_common.c b/src/liblzma/common/stream_common.c deleted file mode 100644 index 121a6674..00000000 --- a/src/liblzma/common/stream_common.c +++ /dev/null @@ -1,23 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file stream_common.c -/// \brief Common stuff for Stream coders -// -// 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 "stream_common.h" - -const uint8_t lzma_header_magic[6] = { 0xFF, 0x4C, 0x5A, 0x4D, 0x41, 0x00 }; -const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A }; diff --git a/src/liblzma/common/stream_decoder.c b/src/liblzma/common/stream_decoder.c index 1bf7f1f8..5b46819d 100644 --- a/src/liblzma/common/stream_decoder.c +++ b/src/liblzma/common/stream_decoder.c @@ -17,8 +17,8 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "stream_common.h" #include "stream_decoder.h" +#include "stream_flags_common.h" #include "check.h" #include "stream_flags_decoder.h" #include "block_decoder.h" @@ -31,6 +31,7 @@ struct lzma_coder_s { SEQ_BLOCK, SEQ_INDEX, SEQ_STREAM_FOOTER, + SEQ_STREAM_PADDING, } sequence; /// Block or Metadata decoder. This takes little memory and the same @@ -40,7 +41,7 @@ struct lzma_coder_s { /// Block options decoded by the Block Header decoder and used by /// the Block decoder. - lzma_options_block block_options; + lzma_block block_options; /// Stream Flags from Stream Header lzma_stream_flags stream_flags; @@ -49,8 +50,35 @@ struct lzma_coder_s { /// with O(1) memory usage. lzma_index_hash *index_hash; - /// Write position in buffer[] - size_t buffer_pos; + /// Memory usage limit + uint64_t memlimit; + + /// If true, LZMA_NO_CHECK is returned if the Stream has + /// no integrity check. + bool warn_no_check; + + /// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has + /// an integrity check that isn't supported by this liblzma build. + bool warn_unsupported_check; + + /// If true, LZMA_SEE_CHECK is returned after decoding Stream Header. + bool tell_check; + + /// If true, we will decode concatenated Streams that possibly have + /// Stream Padding between or after them. LZMA_STREAM_END is returned + /// once the application isn't giving us any new input and we aren't + /// in the middle of a Stream and possible Stream Padding is a + /// multiple of four bytes. FIXME + bool concatenated; + + /// When decoding concatenated Streams, this is true as long as we + /// are decoding the first Stream. This is needed to avoid misleading + /// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic + /// bytes. + bool first_stream; + + /// Write position in buffer[] and position in Stream Padding + size_t pos; /// Buffer to hold Stream Header, Block Header, and Stream Footer. /// Block Header has biggest maximum size. @@ -59,6 +87,23 @@ struct lzma_coder_s { static lzma_ret +stream_decoder_reset(lzma_coder *coder, lzma_allocator *allocator) +{ + // Initialize the Index hash used to verify the Index. + coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator); + if (coder->index_hash == NULL) + return LZMA_MEM_ERROR; + + // Reset the rest of the variables. + coder->sequence = SEQ_STREAM_HEADER; + coder->block_options.filters = NULL; + coder->pos = 0; + + return LZMA_OK; +} + + +static lzma_ret stream_decode(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size, uint8_t *restrict out, @@ -66,43 +111,56 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, { // When decoding the actual Block, it may be able to produce more // output even if we don't give it any new input. - while (*out_pos < out_size && (*in_pos < in_size - || coder->sequence == SEQ_BLOCK)) + while (true) switch (coder->sequence) { case SEQ_STREAM_HEADER: { // Copy the Stream Header to the internal buffer. - bufcpy(in, in_pos, in_size, coder->buffer, &coder->buffer_pos, + lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, LZMA_STREAM_HEADER_SIZE); // Return if we didn't get the whole Stream Header yet. - if (coder->buffer_pos < LZMA_STREAM_HEADER_SIZE) + if (coder->pos < LZMA_STREAM_HEADER_SIZE) return LZMA_OK; - coder->buffer_pos = 0; + coder->pos = 0; // Decode the Stream Header. - return_if_error(lzma_stream_header_decode( - &coder->stream_flags, coder->buffer)); + const lzma_ret ret = lzma_stream_header_decode( + &coder->stream_flags, coder->buffer); + if (ret != LZMA_OK) + return ret == LZMA_FORMAT_ERROR && !coder->first_stream + ? LZMA_DATA_ERROR : ret; // Copy the type of the Check so that Block Header and Block // decoders see it. coder->block_options.check = coder->stream_flags.check; - // Even if we return LZMA_UNSUPPORTED_CHECK below, we want + // Even if we return LZMA_*_CHECK below, we want // to continue from Block Header decoding. coder->sequence = SEQ_BLOCK_HEADER; - // Detect if the Check type is supported and give appropriate - // warning if it isn't. We don't warn every time a new Block - // is started. - if (!lzma_available_checks[coder->block_options.check]) + // Detect if there's no integrity check or if it is + // unsupported if those were requested by the application. + if (coder->warn_no_check && coder->stream_flags.check + == LZMA_CHECK_NONE) + return LZMA_NO_CHECK; + + if (coder->warn_unsupported_check + && !lzma_check_is_supported( + coder->stream_flags.check)) return LZMA_UNSUPPORTED_CHECK; + if (coder->tell_check) + return LZMA_SEE_CHECK; + break; } case SEQ_BLOCK_HEADER: { - if (coder->buffer_pos == 0) { + if (*in_pos >= in_size) + return LZMA_OK; + + if (coder->pos == 0) { // Detect if it's Index. if (in[*in_pos] == 0x00) { coder->sequence = SEQ_INDEX; @@ -118,29 +176,41 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, } // Copy the Block Header to the internal buffer. - bufcpy(in, in_pos, in_size, coder->buffer, &coder->buffer_pos, + lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, coder->block_options.header_size); // Return if we didn't get the whole Block Header yet. - if (coder->buffer_pos < coder->block_options.header_size) + if (coder->pos < coder->block_options.header_size) return LZMA_OK; - coder->buffer_pos = 0; + coder->pos = 0; // Set up a buffer to hold the filter chain. Block Header // decoder will initialize all members of this array so // we don't need to do it here. - lzma_options_filter filters[LZMA_BLOCK_FILTERS_MAX + 1]; + lzma_filter filters[LZMA_BLOCK_FILTERS_MAX + 1]; coder->block_options.filters = filters; // Decode the Block Header. return_if_error(lzma_block_header_decode(&coder->block_options, allocator, coder->buffer)); - // Initialize the Block decoder. - const lzma_ret ret = lzma_block_decoder_init( - &coder->block_decoder, - allocator, &coder->block_options); + // Check the memory usage limit. + const uint64_t memusage = lzma_memusage_decoder(filters); + lzma_ret ret; + + if (memusage == UINT64_MAX) { + // One or more unknown Filter IDs. + ret = LZMA_HEADER_ERROR; + } else if (memusage > coder->memlimit) { + // The chain would need too much memory. + ret = LZMA_MEMLIMIT_ERROR; + } else { + // Memory usage is OK. Initialize the Block decoder. + ret = lzma_block_decoder_init( + &coder->block_decoder, + allocator, &coder->block_options); + } // Free the allocated filter options since they are needed // only to initialize the Block decoder. @@ -149,10 +219,9 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, coder->block_options.filters = NULL; - // Check if Block enocoder initialization succeeded. Don't - // warn about unsupported check anymore since we did it - // earlier if it was needed. - if (ret != LZMA_OK && ret != LZMA_UNSUPPORTED_CHECK) + // Check if memory usage calculation and Block enocoder + // initialization succeeded. + if (ret != LZMA_OK) return ret; coder->sequence = SEQ_BLOCK; @@ -160,7 +229,7 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, } case SEQ_BLOCK: { - lzma_ret ret = coder->block_decoder.code( + const lzma_ret ret = coder->block_decoder.code( coder->block_decoder.coder, allocator, in, in_pos, in_size, out, out_pos, out_size, action); @@ -180,6 +249,12 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, } case SEQ_INDEX: { + // If we don't have any input, don't call + // lzma_index_hash_decode() since it would return + // LZMA_BUF_ERROR, which we must not do here. + if (*in_pos >= in_size) + return LZMA_OK; + // Decode the Index and compare it to the hash calculated // from the sizes of the Blocks (if any). const lzma_ret ret = lzma_index_hash_decode(coder->index_hash, @@ -193,14 +268,17 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, case SEQ_STREAM_FOOTER: // Copy the Stream Footer to the internal buffer. - bufcpy(in, in_pos, in_size, coder->buffer, &coder->buffer_pos, + lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, LZMA_STREAM_HEADER_SIZE); // Return if we didn't get the whole Stream Footer yet. - if (coder->buffer_pos < LZMA_STREAM_HEADER_SIZE) + if (coder->pos < LZMA_STREAM_HEADER_SIZE) return LZMA_OK; + coder->pos = 0; + // Decode the Stream Footer. + // FIXME LZMA_FORMAT_ERROR doesn't make sense here. lzma_stream_flags footer_flags; return_if_error(lzma_stream_footer_decode( &footer_flags, coder->buffer)); @@ -217,7 +295,48 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, &footer_flags)) return LZMA_DATA_ERROR; - return LZMA_STREAM_END; + if (!coder->concatenated) + return LZMA_STREAM_END; + + coder->sequence = SEQ_STREAM_PADDING; + break; + + case SEQ_STREAM_PADDING: + assert(coder->concatenated); + + while (true) { + if (*in_pos >= in_size) { + // Unless LZMA_FINISH was used, we cannot + // know if there's more input coming later. + if (action != LZMA_FINISH) + return LZMA_OK; + + // Stream Padding must be a multiple of + // four bytes. + return coder->pos == 0 + ? LZMA_STREAM_END + : LZMA_DATA_ERROR; + } + + if (in[*in_pos] != 0x00) { + if (coder->pos != 0) { + // Stream Padding is not a multiple of + // four bytes. + ++*in_pos; + return LZMA_DATA_ERROR; + } + + // Prepare to decode the next Stream. + return_if_error(stream_decoder_reset( + coder, allocator)); + break; + } + + ++*in_pos; + coder->pos = (coder->pos + 1) & 3; + } + + break; default: assert(0); @@ -231,16 +350,29 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator, static void stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->block_decoder, allocator); + lzma_next_end(&coder->block_decoder, allocator); lzma_index_hash_end(coder->index_hash, allocator); lzma_free(coder, allocator); return; } -static lzma_ret -stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) +static lzma_check +stream_decoder_see_check(const lzma_coder *coder) { + return coder->stream_flags.check; +} + + +extern lzma_ret +lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator, + uint64_t memlimit, uint32_t flags) +{ + lzma_next_coder_init(lzma_stream_decoder_init, next, allocator); + + if (flags & ~LZMA_SUPPORTED_FLAGS) + return LZMA_HEADER_ERROR; + if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); if (next->coder == NULL) @@ -248,40 +380,32 @@ stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) next->code = &stream_decode; next->end = &stream_decoder_end; + next->see_check = &stream_decoder_see_check; next->coder->block_decoder = LZMA_NEXT_CODER_INIT; next->coder->index_hash = NULL; } - // Initialize the Index hash used to verify the Index. - next->coder->index_hash = lzma_index_hash_init( - next->coder->index_hash, allocator); - if (next->coder->index_hash == NULL) - return LZMA_MEM_ERROR; - - // Reset the rest of the variables. - next->coder->sequence = SEQ_STREAM_HEADER; - next->coder->block_options.filters = NULL; - next->coder->buffer_pos = 0; + next->coder->memlimit = memlimit; + next->coder->warn_no_check = (flags & LZMA_WARN_NO_CHECK) != 0; + next->coder->warn_unsupported_check + = (flags & LZMA_WARN_UNSUPPORTED_CHECK) != 0; + next->coder->tell_check = (flags & LZMA_TELL_CHECK) != 0; + next->coder->concatenated + = (flags & LZMA_CONCATENATED) != 0; - return LZMA_OK; -} - - -extern lzma_ret -lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator) -{ - lzma_next_coder_init0(stream_decoder_init, next, allocator); + return stream_decoder_reset(next->coder, allocator); } extern LZMA_API lzma_ret -lzma_stream_decoder(lzma_stream *strm) +lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags) { - lzma_next_strm_init0(strm, stream_decoder_init); + lzma_next_strm_init(lzma_stream_decoder_init, strm, memlimit, flags); strm->internal->supported_actions[LZMA_RUN] = true; - strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; +// strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; // FIXME + strm->internal->supported_actions[LZMA_FINISH] = true; return LZMA_OK; } diff --git a/src/liblzma/common/stream_decoder.h b/src/liblzma/common/stream_decoder.h index dcda387d..59d58c6f 100644 --- a/src/liblzma/common/stream_decoder.h +++ b/src/liblzma/common/stream_decoder.h @@ -22,7 +22,7 @@ #include "common.h" -extern lzma_ret lzma_stream_decoder_init( - lzma_next_coder *next, lzma_allocator *allocator); +extern lzma_ret lzma_stream_decoder_init(lzma_next_coder *next, + lzma_allocator *allocator, uint64_t memlimit, uint32_t flags); #endif diff --git a/src/liblzma/common/stream_encoder.c b/src/liblzma/common/stream_encoder.c index 767b8014..9d56c899 100644 --- a/src/liblzma/common/stream_encoder.c +++ b/src/liblzma/common/stream_encoder.c @@ -17,8 +17,8 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "stream_common.h" #include "stream_encoder.h" +#include "stream_flags_common.h" #include "block_encoder.h" #include "index_encoder.h" @@ -37,7 +37,7 @@ struct lzma_coder_s { lzma_next_coder block_encoder; /// Options for the Block encoder - lzma_options_block block_options; + lzma_block block_options; /// Index encoder. This is separate from Block encoder, because this /// doesn't take much memory, and when encoding multiple Streams @@ -86,8 +86,8 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator, case SEQ_STREAM_HEADER: case SEQ_BLOCK_HEADER: case SEQ_STREAM_FOOTER: - bufcpy(coder->buffer, &coder->buffer_pos, coder->buffer_size, - out, out_pos, out_size); + lzma_bufcpy(coder->buffer, &coder->buffer_pos, + coder->buffer_size, out, out_pos, out_size); if (coder->buffer_pos < coder->buffer_size) return LZMA_OK; @@ -202,18 +202,20 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator, static void stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator) { - lzma_next_coder_end(&coder->block_encoder, allocator); - lzma_next_coder_end(&coder->index_encoder, allocator); + lzma_next_end(&coder->block_encoder, allocator); + lzma_next_end(&coder->index_encoder, allocator); lzma_index_end(coder->index, allocator); lzma_free(coder, allocator); return; } -static lzma_ret -stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_options_filter *filters, lzma_check_type check) +extern lzma_ret +lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, + const lzma_filter *filters, lzma_check check) { + lzma_next_coder_init(lzma_stream_encoder_init, next, allocator); + if (filters == NULL) return LZMA_PROG_ERROR; @@ -233,7 +235,7 @@ stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, // Basic initializations next->coder->sequence = SEQ_STREAM_HEADER; next->coder->block_options.check = check; - next->coder->block_options.filters = (lzma_options_filter *)(filters); + next->coder->block_options.filters = (lzma_filter *)(filters); // Initialize the Index next->coder->index = lzma_index_init(next->coder->index, allocator); @@ -258,20 +260,11 @@ stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, } -extern lzma_ret -lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, - const lzma_options_filter *filters, lzma_check_type check) -{ - lzma_next_coder_init(stream_encoder_init, next, allocator, - filters, check); -} - - extern LZMA_API lzma_ret lzma_stream_encoder(lzma_stream *strm, - const lzma_options_filter *filters, lzma_check_type check) + const lzma_filter *filters, lzma_check check) { - lzma_next_strm_init(strm, stream_encoder_init, filters, check); + lzma_next_strm_init(lzma_stream_encoder_init, strm, filters, check); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; diff --git a/src/liblzma/common/stream_encoder.h b/src/liblzma/common/stream_encoder.h index 3ce29561..cec2e5b5 100644 --- a/src/liblzma/common/stream_encoder.h +++ b/src/liblzma/common/stream_encoder.h @@ -25,6 +25,6 @@ extern lzma_ret lzma_stream_encoder_init( lzma_next_coder *next, lzma_allocator *allocator, - const lzma_options_filter *filters, lzma_check_type check); + const lzma_filter *filters, lzma_check check); #endif diff --git a/src/liblzma/common/stream_flags_equal.c b/src/liblzma/common/stream_flags_common.c index db22567f..c44b3ff2 100644 --- a/src/liblzma/common/stream_flags_equal.c +++ b/src/liblzma/common/stream_flags_common.c @@ -1,9 +1,9 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file stream_flags_equal.c -/// \brief Compare Stream Header and Stream Footer +/// \file stream_flags_common.c +/// \brief Common stuff for Stream flags coders // -// Copyright (C) 2008 Lasse Collin +// Copyright (C) 2007-2008 Lasse Collin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -17,11 +17,15 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "common.h" +#include "stream_flags_common.h" + + +const uint8_t lzma_header_magic[6] = { 0xFF, 0x4C, 0x5A, 0x4D, 0x41, 0x00 }; +const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A }; extern LZMA_API lzma_bool -lzma_stream_flags_equal(const lzma_stream_flags *a, lzma_stream_flags *b) +lzma_stream_flags_equal(const lzma_stream_flags *a, const lzma_stream_flags *b) { if (a->check != b->check) return false; diff --git a/src/liblzma/common/stream_common.h b/src/liblzma/common/stream_flags_common.h index 4f83fc58..6e57857b 100644 --- a/src/liblzma/common/stream_common.h +++ b/src/liblzma/common/stream_flags_common.h @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file stream_common.h -/// \brief Common stuff for Stream coders +/// \file stream_flags_common.h +/// \brief Common stuff for Stream flags coders // // Copyright (C) 2007 Lasse Collin // @@ -17,8 +17,8 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifndef LZMA_STREAM_COMMON_H -#define LZMA_STREAM_COMMON_H +#ifndef LZMA_STREAM_FLAGS_COMMON_H +#define LZMA_STREAM_FLAGS_COMMON_H #include "common.h" diff --git a/src/liblzma/common/stream_flags_decoder.c b/src/liblzma/common/stream_flags_decoder.c index 0270875a..ccc1539d 100644 --- a/src/liblzma/common/stream_flags_decoder.c +++ b/src/liblzma/common/stream_flags_decoder.c @@ -17,7 +17,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "stream_common.h" +#include "stream_flags_common.h" static bool diff --git a/src/liblzma/common/stream_flags_encoder.c b/src/liblzma/common/stream_flags_encoder.c index 4efbb6f4..1d736a8a 100644 --- a/src/liblzma/common/stream_flags_encoder.c +++ b/src/liblzma/common/stream_flags_encoder.c @@ -17,7 +17,7 @@ // /////////////////////////////////////////////////////////////////////////////// -#include "stream_common.h" +#include "stream_flags_common.h" static bool diff --git a/src/liblzma/common/version.c b/src/liblzma/common/version.c deleted file mode 100644 index dffec7ff..00000000 --- a/src/liblzma/common/version.c +++ /dev/null @@ -1,25 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file version.c -/// \brief liblzma version number -// -// 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" - - -LZMA_API const uint32_t lzma_version_number = LZMA_VERSION; - -LZMA_API const char *const lzma_version_string = PACKAGE_VERSION; diff --git a/src/liblzma/common/vli_decoder.c b/src/liblzma/common/vli_decoder.c index faff6ccb..60874baa 100644 --- a/src/liblzma/common/vli_decoder.c +++ b/src/liblzma/common/vli_decoder.c @@ -27,17 +27,30 @@ lzma_vli_decode(lzma_vli *restrict vli, size_t *restrict vli_pos, { // If we haven't been given vli_pos, work in single-call mode. size_t vli_pos_internal = 0; - if (vli_pos == NULL) + if (vli_pos == NULL) { vli_pos = &vli_pos_internal; - - // Initialize *vli when starting to decode a new integer. - if (*vli_pos == 0) *vli = 0; - // Validate the arguments. - if (*vli_pos >= LZMA_VLI_BYTES_MAX || *in_pos >= in_size - || (*vli >> (*vli_pos * 7)) != 0) - return LZMA_PROG_ERROR;; + // If there's no input, use LZMA_DATA_ERROR. This way it is + // easy to decode VLIs from buffers that have known size, + // and get the correct error code in case the buffer is + // too short. + if (*in_pos >= in_size) + return LZMA_DATA_ERROR; + + } else { + // Initialize *vli when starting to decode a new integer. + if (*vli_pos == 0) + *vli = 0; + + // Validate the arguments. + if (*vli_pos >= LZMA_VLI_BYTES_MAX + || (*vli >> (*vli_pos * 7)) != 0) + return LZMA_PROG_ERROR;; + + if (*in_pos >= in_size) + return LZMA_BUF_ERROR; + } do { // Read the next byte. diff --git a/src/liblzma/common/vli_encoder.c b/src/liblzma/common/vli_encoder.c index c48d6474..53022f16 100644 --- a/src/liblzma/common/vli_encoder.c +++ b/src/liblzma/common/vli_encoder.c @@ -31,10 +31,12 @@ lzma_vli_encode(lzma_vli vli, size_t *restrict vli_pos, vli_pos = &vli_pos_internal; // Validate the arguments. - if (*vli_pos >= LZMA_VLI_BYTES_MAX || *out_pos >= out_size - || vli > LZMA_VLI_VALUE_MAX) + if (*vli_pos >= LZMA_VLI_BYTES_MAX || vli > LZMA_VLI_VALUE_MAX) return LZMA_PROG_ERROR; + if (*out_pos >= out_size) + return LZMA_BUF_ERROR; + // Write the non-last bytes in a loop. while ((vli >> (*vli_pos * 7)) >= 0x80) { out[*out_pos] = (uint8_t)(vli >> (*vli_pos * 7)) | 0x80; @@ -55,20 +57,3 @@ lzma_vli_encode(lzma_vli vli, size_t *restrict vli_pos, return vli_pos == &vli_pos_internal ? LZMA_OK : LZMA_STREAM_END; } - - -extern LZMA_API uint32_t -lzma_vli_size(lzma_vli vli) -{ - if (vli > LZMA_VLI_VALUE_MAX) - return 0; - - uint32_t i = 0; - do { - vli >>= 7; - ++i; - } while (vli != 0); - - assert(i <= LZMA_VLI_BYTES_MAX); - return i; -} diff --git a/src/liblzma/common/delta_encoder.h b/src/liblzma/common/vli_size.c index c669458d..547bba0b 100644 --- a/src/liblzma/common/delta_encoder.h +++ b/src/liblzma/common/vli_size.c @@ -1,9 +1,9 @@ /////////////////////////////////////////////////////////////////////////////// // -/// \file delta_encoder.h -/// \brief Delta filter encoder +/// \file vli_size.c +/// \brief Calculates the encoded size of a variable-length integer // -// Copyright (C) 2007 Lasse Collin +// Copyright (C) 2007-2008 Lasse Collin // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -17,12 +17,21 @@ // /////////////////////////////////////////////////////////////////////////////// -#ifndef LZMA_DELTA_ENCODER_H -#define LZMA_DELTA_ENCODER_H - #include "common.h" -extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next, - lzma_allocator *allocator, const lzma_filter_info *filters); -#endif +extern LZMA_API uint32_t +lzma_vli_size(lzma_vli vli) +{ + if (vli > LZMA_VLI_VALUE_MAX) + return 0; + + uint32_t i = 0; + do { + vli >>= 7; + ++i; + } while (vli != 0); + + assert(i <= LZMA_VLI_BYTES_MAX); + return i; +} |