aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/liblzma/common')
-rw-r--r--src/liblzma/common/Makefile.am94
-rw-r--r--src/liblzma/common/alignment.c118
-rw-r--r--src/liblzma/common/allocator.c57
-rw-r--r--src/liblzma/common/alone_decoder.c197
-rw-r--r--src/liblzma/common/alone_decoder.h24
-rw-r--r--src/liblzma/common/alone_encoder.c167
-rw-r--r--src/liblzma/common/auto_decoder.c113
-rw-r--r--src/liblzma/common/block_decoder.c405
-rw-r--r--src/liblzma/common/block_decoder.h29
-rw-r--r--src/liblzma/common/block_encoder.c375
-rw-r--r--src/liblzma/common/block_encoder.h29
-rw-r--r--src/liblzma/common/block_header_decoder.c373
-rw-r--r--src/liblzma/common/block_header_encoder.c211
-rw-r--r--src/liblzma/common/block_private.h46
-rw-r--r--src/liblzma/common/chunk_size.c74
-rw-r--r--src/liblzma/common/code.c203
-rw-r--r--src/liblzma/common/common.h271
-rw-r--r--src/liblzma/common/copy_coder.c143
-rw-r--r--src/liblzma/common/copy_coder.h31
-rw-r--r--src/liblzma/common/delta_coder.c210
-rw-r--r--src/liblzma/common/delta_coder.h31
-rw-r--r--src/liblzma/common/extra.c33
-rw-r--r--src/liblzma/common/features.c70
-rw-r--r--src/liblzma/common/filter_flags_decoder.c382
-rw-r--r--src/liblzma/common/filter_flags_encoder.c359
-rw-r--r--src/liblzma/common/index.c140
-rw-r--r--src/liblzma/common/info.c823
-rw-r--r--src/liblzma/common/init.c39
-rw-r--r--src/liblzma/common/init_decoder.c33
-rw-r--r--src/liblzma/common/init_encoder.c44
-rw-r--r--src/liblzma/common/memory_limitter.c200
-rw-r--r--src/liblzma/common/memory_usage.c113
-rw-r--r--src/liblzma/common/metadata_decoder.c555
-rw-r--r--src/liblzma/common/metadata_decoder.h31
-rw-r--r--src/liblzma/common/metadata_encoder.c436
-rw-r--r--src/liblzma/common/metadata_encoder.h30
-rw-r--r--src/liblzma/common/next_coder.c65
-rw-r--r--src/liblzma/common/raw_common.c175
-rw-r--r--src/liblzma/common/raw_common.h31
-rw-r--r--src/liblzma/common/raw_decoder.c127
-rw-r--r--src/liblzma/common/raw_decoder.h30
-rw-r--r--src/liblzma/common/raw_encoder.c124
-rw-r--r--src/liblzma/common/raw_encoder.h30
-rw-r--r--src/liblzma/common/stream_common.c23
-rw-r--r--src/liblzma/common/stream_common.h28
-rw-r--r--src/liblzma/common/stream_decoder.c454
-rw-r--r--src/liblzma/common/stream_encoder_multi.c460
-rw-r--r--src/liblzma/common/stream_encoder_single.c220
-rw-r--r--src/liblzma/common/stream_flags_decoder.c258
-rw-r--r--src/liblzma/common/stream_flags_decoder.h31
-rw-r--r--src/liblzma/common/stream_flags_encoder.c75
l---------src/liblzma/common/sysdefs.h1
-rw-r--r--src/liblzma/common/version.c25
-rw-r--r--src/liblzma/common/vli_decoder.c69
-rw-r--r--src/liblzma/common/vli_encoder.c81
-rw-r--r--src/liblzma/common/vli_reverse_decoder.c55
56 files changed, 8851 insertions, 0 deletions
diff --git a/src/liblzma/common/Makefile.am b/src/liblzma/common/Makefile.am
new file mode 100644
index 00000000..4eb9d54e
--- /dev/null
+++ b/src/liblzma/common/Makefile.am
@@ -0,0 +1,94 @@
+##
+## 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.
+##
+
+noinst_LTLIBRARIES = libcommon.la
+libcommon_la_CPPFLAGS = \
+ -I@top_srcdir@/src/liblzma/api \
+ -I@top_srcdir@/src/liblzma/check \
+ -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
+libcommon_la_SOURCES = \
+ common.h \
+ sysdefs.h \
+ allocator.c \
+ block_private.h \
+ extra.c \
+ features.c \
+ index.c \
+ info.c \
+ init.c \
+ memory_limitter.c \
+ memory_usage.c \
+ next_coder.c \
+ raw_common.c \
+ raw_common.h \
+ code.c \
+ version.c
+
+if COND_FILTER_COPY
+libcommon_la_SOURCES += \
+ copy_coder.c \
+ copy_coder.h
+endif
+
+if COND_FILTER_DELTA
+libcommon_la_SOURCES += \
+ delta_coder.c \
+ delta_coder.h
+endif
+
+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 \
+ filter_flags_encoder.c \
+ init_encoder.c \
+ metadata_encoder.c \
+ metadata_encoder.h \
+ raw_encoder.c \
+ raw_encoder.h \
+ stream_common.c \
+ stream_common.h \
+ stream_encoder_single.c \
+ stream_encoder_multi.c \
+ stream_flags_encoder.c \
+ vli_encoder.c
+endif
+
+if COND_MAIN_DECODER
+libcommon_la_SOURCES += \
+ alone_decoder.c \
+ alone_decoder.h \
+ block_decoder.c \
+ block_decoder.h \
+ block_header_decoder.c \
+ filter_flags_decoder.c \
+ init_decoder.c \
+ metadata_decoder.c \
+ metadata_decoder.h \
+ raw_decoder.c \
+ raw_decoder.h \
+ stream_decoder.c \
+ stream_flags_decoder.c \
+ stream_flags_decoder.h \
+ vli_decoder.c \
+ vli_reverse_decoder.c
+endif
diff --git a/src/liblzma/common/alignment.c b/src/liblzma/common/alignment.c
new file mode 100644
index 00000000..2d468fe5
--- /dev/null
+++ b/src/liblzma/common/alignment.c
@@ -0,0 +1,118 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alignment.c
+/// \brief Calculates preferred alignments of different 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"
+
+
+extern LZMA_API uint32_t
+lzma_alignment_input(const lzma_options_filter *filters, uint32_t guess)
+{
+ for (size_t i = 0; filters[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
+ switch (filters[i].id) {
+ case LZMA_FILTER_COPY:
+ case LZMA_FILTER_DELTA:
+ // The same as the input, check the next filter.
+ continue;
+
+ case LZMA_FILTER_SUBBLOCK:
+ if (filters[i].options == NULL)
+ return LZMA_SUBBLOCK_ALIGNMENT_DEFAULT;
+ else
+ return ((const lzma_options_subblock *)(
+ filters[i].options))->alignment;
+
+ case LZMA_FILTER_X86:
+ return 1;
+
+ case LZMA_FILTER_ARMTHUMB:
+ return 2;
+
+ case LZMA_FILTER_POWERPC:
+ case LZMA_FILTER_ARM:
+ case LZMA_FILTER_SPARC:
+ return 4;
+
+ case LZMA_FILTER_IA64:
+ return 16;
+
+ case LZMA_FILTER_LZMA: {
+ const lzma_options_lzma *lzma = filters[i].options;
+ return 1 << MAX(lzma->pos_bits,
+ lzma->literal_pos_bits);
+ }
+
+ default:
+ return UINT32_MAX;
+ }
+ }
+
+ return guess;
+}
+
+
+extern LZMA_API uint32_t
+lzma_alignment_output(const lzma_options_filter *filters, uint32_t guess)
+{
+ // Check if there is only an implicit Copy filter.
+ if (filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
+ return guess;
+
+ // Find the last filter in the chain.
+ size_t i = 0;
+ while (filters[i + 1].id != LZMA_VLI_VALUE_UNKNOWN)
+ ++i;
+
+ do {
+ switch (filters[i].id) {
+ case LZMA_FILTER_COPY:
+ case LZMA_FILTER_DELTA:
+ // It's the same as the input alignment, so
+ // check the next filter.
+ continue;
+
+ case LZMA_FILTER_SUBBLOCK:
+ if (filters[i].options == NULL)
+ return LZMA_SUBBLOCK_ALIGNMENT_DEFAULT;
+ else
+ return ((const lzma_options_subblock *)(
+ filters[i].options))->alignment;
+
+ case LZMA_FILTER_X86:
+ case LZMA_FILTER_LZMA:
+ return 1;
+
+ case LZMA_FILTER_ARMTHUMB:
+ return 2;
+
+ case LZMA_FILTER_POWERPC:
+ case LZMA_FILTER_ARM:
+ case LZMA_FILTER_SPARC:
+ return 4;
+
+ case LZMA_FILTER_IA64:
+ return 16;
+
+ default:
+ return UINT32_MAX;
+ }
+ } while (i-- != 0);
+
+ // If we get here, we have the same alignment as the input data.
+ return guess;
+}
diff --git a/src/liblzma/common/allocator.c b/src/liblzma/common/allocator.c
new file mode 100644
index 00000000..edea0f68
--- /dev/null
+++ b/src/liblzma/common/allocator.c
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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);
+
+#if !defined(NDEBUG) && defined(HAVE_MEMSET)
+ // This helps to catch some stupid mistakes.
+ 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
new file mode 100644
index 00000000..092047b4
--- /dev/null
+++ b/src/liblzma/common/alone_decoder.c
@@ -0,0 +1,197 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alone_decoder.c
+/// \brief Decoder for LZMA_Alone files
+//
+// 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 "alone_decoder.h"
+#include "lzma_decoder.h"
+
+
+struct lzma_coder_s {
+ lzma_next_coder next;
+
+ enum {
+ SEQ_PROPERTIES,
+ SEQ_DICTIONARY_SIZE,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_CODER_INIT,
+ SEQ_CODE,
+ } sequence;
+
+ size_t pos;
+
+ lzma_options_alone options;
+};
+
+
+static lzma_ret
+alone_decode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((unused)),
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size, uint8_t *restrict out,
+ size_t *restrict out_pos, size_t out_size,
+ lzma_action action)
+{
+ while (*out_pos < out_size
+ && (coder->sequence == SEQ_CODE || *in_pos < in_size))
+ switch (coder->sequence) {
+ case SEQ_PROPERTIES:
+ if (lzma_lzma_decode_properties(
+ &coder->options.lzma, in[*in_pos]))
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_DICTIONARY_SIZE;
+ ++*in_pos;
+ break;
+
+ case SEQ_DICTIONARY_SIZE:
+ coder->options.lzma.dictionary_size
+ |= (size_t)(in[*in_pos]) << (coder->pos * 8);
+
+ if (++coder->pos == 4) {
+ // A hack to ditch tons of false positives: We allow
+ // only dictionary sizes that are a power of two.
+ // LZMA_Alone didn't create other kinds of files,
+ // although it's not impossible that files with
+ // other dictionary sizes exist. Well, if someone
+ // complains, this will be reconsidered.
+ size_t count = 0;
+ for (size_t i = 0; i < 32; ++i)
+ if (coder->options.lzma.dictionary_size
+ & (UINT32_C(1) << i))
+ ++count;
+
+ if (count > 1)
+ return LZMA_DATA_ERROR;
+
+ coder->pos = 0;
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ }
+
+ ++*in_pos;
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ coder->options.uncompressed_size
+ |= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
+
+ if (++coder->pos == 8) {
+ // Another hack to ditch false positives: Assume that
+ // if the uncompressed size is known, it must be less
+ // than 256 GiB. Again, if someone complains, this
+ // will be reconsidered.
+ if (coder->options.uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && coder->options.uncompressed_size
+ >= (LZMA_VLI_C(1) << 38))
+ return LZMA_DATA_ERROR;
+
+ coder->pos = 0;
+ coder->sequence = SEQ_CODER_INIT;
+ }
+
+ ++*in_pos;
+ break;
+
+ case SEQ_CODER_INIT: {
+ // Two is enough because there won't be implicit filters.
+ lzma_filter_info filters[2] = {
+ {
+ .init = &lzma_lzma_decoder_init,
+ .options = &coder->options.lzma,
+ .uncompressed_size = coder->options
+ .uncompressed_size,
+ }, {
+ .init = NULL,
+ }
+ };
+
+ const lzma_ret ret = lzma_next_filter_init(&coder->next,
+ allocator, filters);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_CODE;
+ }
+
+ // Fall through
+
+ case SEQ_CODE: {
+ return coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
+{
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &alone_decode;
+ next->end = &alone_decoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ next->coder->sequence = SEQ_PROPERTIES;
+ next->coder->pos = 0;
+ next->coder->options.lzma.dictionary_size = 0;
+ next->coder->options.uncompressed_size = 0;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
+{
+ // We need to use _init2 because we don't pass any varadic args.
+ lzma_next_coder_init2(next, allocator, alone_decoder_init,
+ alone_decoder_init, allocator);
+}
+
+
+extern LZMA_API lzma_ret
+lzma_alone_decoder(lzma_stream *strm)
+{
+ lzma_next_strm_init2(strm, alone_decoder_init,
+ alone_decoder_init, strm->allocator);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/alone_decoder.h b/src/liblzma/common/alone_decoder.h
new file mode 100644
index 00000000..a9b7e84b
--- /dev/null
+++ b/src/liblzma/common/alone_decoder.h
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alone_decoder.h
+/// \brief Decoder for LZMA_Alone files
+//
+// 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_alone_decoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator);
diff --git a/src/liblzma/common/alone_encoder.c b/src/liblzma/common/alone_encoder.c
new file mode 100644
index 00000000..7629aa77
--- /dev/null
+++ b/src/liblzma/common/alone_encoder.c
@@ -0,0 +1,167 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alone_decoder.c
+/// \brief Decoder for LZMA_Alone files
+//
+// 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 "lzma_encoder.h"
+
+
+struct lzma_coder_s {
+ lzma_next_coder next;
+
+ enum {
+ SEQ_PROPERTIES,
+ SEQ_DICTIONARY_SIZE,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_CODE,
+ } sequence;
+
+ size_t pos;
+
+ lzma_options_alone options;
+};
+
+
+static lzma_ret
+alone_encode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((unused)),
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size, uint8_t *restrict out,
+ size_t *restrict out_pos, size_t out_size,
+ lzma_action action)
+{
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_PROPERTIES:
+ if (lzma_lzma_encode_properties(
+ &coder->options.lzma, out + *out_pos)) {
+ return LZMA_PROG_ERROR;
+ }
+
+ coder->sequence = SEQ_DICTIONARY_SIZE;
+ ++*out_pos;
+ break;
+
+ case SEQ_DICTIONARY_SIZE:
+ out[*out_pos] = coder->options.lzma.dictionary_size
+ >> (coder->pos * 8);
+
+ if (++coder->pos == 4) {
+ coder->pos = 0;
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ }
+
+ ++*out_pos;
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ out[*out_pos] = coder->options.uncompressed_size
+ >> (coder->pos * 8);
+
+ if (++coder->pos == 8) {
+ coder->pos = 0;
+ coder->sequence = SEQ_CODE;
+ }
+
+ ++*out_pos;
+ break;
+
+ case SEQ_CODE: {
+ return coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+// At least for now, this is not used by any internal function.
+static lzma_ret
+alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_options_alone *options)
+{
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &alone_encode;
+ next->end = &alone_encoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Initialize the LZMA_Alone coder variables.
+ next->coder->sequence = SEQ_PROPERTIES;
+ next->coder->pos = 0;
+ next->coder->options = *options;
+
+ // Verify uncompressed_size since the other functions assume that
+ // it is valid.
+ if (!lzma_vli_is_valid(next->coder->options.uncompressed_size))
+ return LZMA_PROG_ERROR;
+
+ // Initialize the LZMA encoder.
+ const lzma_filter_info filters[2] = {
+ {
+ .init = &lzma_lzma_encoder_init,
+ .options = &next->coder->options.lzma,
+ .uncompressed_size = next->coder->options
+ .uncompressed_size,
+ }, {
+ .init = NULL,
+ }
+ };
+
+ return lzma_next_filter_init(&next->coder->next, allocator, filters);
+}
+
+
+/*
+extern lzma_ret
+lzma_alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_options_alone *options)
+{
+ lzma_next_coder_init(alone_encoder_init, next, allocator, options);
+}
+*/
+
+
+extern LZMA_API lzma_ret
+lzma_alone_encoder(lzma_stream *strm, const lzma_options_alone *options)
+{
+ lzma_next_strm_init(strm, alone_encoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/auto_decoder.c b/src/liblzma/common/auto_decoder.c
new file mode 100644
index 00000000..7e92df9a
--- /dev/null
+++ b/src/liblzma/common/auto_decoder.c
@@ -0,0 +1,113 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file auto_decoder.c
+/// \brief Autodetect between .lzma Stream and LZMA_Alone formats
+//
+// 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 "alone_decoder.h"
+
+
+struct lzma_coder_s {
+ lzma_next_coder next;
+
+ lzma_extra **header;
+ lzma_extra **footer;
+ bool initialized;
+};
+
+
+static lzma_ret
+auto_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)
+{
+ if (!coder->initialized) {
+ if (*in_pos >= in_size)
+ return LZMA_OK;
+
+ lzma_ret ret;
+
+ if (in[*in_pos] == 0xFF)
+ ret = lzma_stream_decoder_init(&coder->next, allocator,
+ coder->header, coder->footer);
+ else
+ ret = lzma_alone_decoder_init(&coder->next, allocator);
+
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->initialized = true;
+ }
+
+ return coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size, action);
+}
+
+
+static void
+auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_extra **header, lzma_extra **footer)
+{
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &auto_decode;
+ next->end = &auto_decoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ next->coder->header = header;
+ next->coder->footer = footer;
+ 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_extra **header, lzma_extra **footer)
+{
+ lzma_next_strm_init(strm, auto_decoder_init, header, footer);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/block_decoder.c b/src/liblzma/common/block_decoder.c
new file mode 100644
index 00000000..b9dcde49
--- /dev/null
+++ b/src/liblzma/common/block_decoder.c
@@ -0,0 +1,405 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_decoder.c
+/// \brief Decodes .lzma Blocks
+//
+// 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 "block_decoder.h"
+#include "block_private.h"
+#include "raw_decoder.h"
+#include "check.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_CODE,
+ SEQ_CHECK,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_BACKWARD_SIZE,
+ SEQ_PADDING,
+ SEQ_END,
+ } sequence;
+
+ /// The filters in the chain; initialized with lzma_raw_decoder_init().
+ lzma_next_coder next;
+
+ /// Decoding 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;
+
+ /// Position in variable-length integers (and in some other places).
+ size_t pos;
+
+ /// Check of the uncompressed data
+ lzma_check check;
+
+ /// Total Size calculated while encoding
+ lzma_vli total_size;
+
+ /// Compressed Size calculated while encoding
+ lzma_vli compressed_size;
+
+ /// Uncompressed Size calculated while encoding
+ lzma_vli uncompressed_size;
+
+ /// Maximum allowed total_size
+ lzma_vli total_limit;
+
+ /// Maximum allowed uncompressed_size
+ lzma_vli uncompressed_limit;
+
+ /// Temporary location for the Uncompressed Size and Backward Size
+ /// fields in Block Footer.
+ lzma_vli tmp;
+
+ /// Size of the Backward Size field - This is needed so that we
+ /// can verify the Backward Size and still keep updating total_size.
+ size_t size_of_backward_size;
+};
+
+
+static lzma_ret
+update_sequence(lzma_coder *coder)
+{
+ switch (coder->sequence) {
+ case SEQ_CODE:
+ if (coder->options->check != LZMA_CHECK_NONE) {
+ lzma_check_finish(&coder->check,
+ coder->options->check);
+ coder->sequence = SEQ_CHECK;
+ break;
+ }
+
+ // Fall through
+
+ case SEQ_CHECK:
+ if (coder->options->has_uncompressed_size_in_footer) {
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ break;
+ }
+
+ // Fall through
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ if (coder->options->has_backward_size) {
+ coder->sequence = SEQ_BACKWARD_SIZE;
+ break;
+ }
+
+ // Fall through
+
+ case SEQ_BACKWARD_SIZE:
+ if (coder->options->handle_padding) {
+ coder->sequence = SEQ_PADDING;
+ break;
+ }
+
+ case SEQ_PADDING:
+ if (!is_size_valid(coder->total_size,
+ coder->options->total_size)
+ || !is_size_valid(coder->compressed_size,
+ coder->options->compressed_size)
+ || !is_size_valid(coder->uncompressed_size,
+ coder->options->uncompressed_size))
+ return LZMA_DATA_ERROR;
+
+ // Copy the values into coder->options. The caller
+ // may use this information to construct Index.
+ coder->options->total_size = coder->total_size;
+ coder->options->compressed_size = coder->compressed_size;
+ coder->options->uncompressed_size = coder->uncompressed_size;
+
+ return LZMA_STREAM_END;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+block_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)
+{
+ // Special case when the Block has only Block Header.
+ if (coder->sequence == SEQ_END)
+ return LZMA_STREAM_END;
+
+ // FIXME: Termination condition should work but could be cleaner.
+ while (*out_pos < out_size && (*in_pos < in_size
+ || coder->sequence == SEQ_CODE))
+ switch (coder->sequence) {
+ case SEQ_CODE: {
+ const size_t in_start = *in_pos;
+ const size_t out_start = *out_pos;
+
+ lzma_ret ret = coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+
+ const size_t in_used = *in_pos - in_start;
+ const size_t out_used = *out_pos - out_start;
+
+ if (update_size(&coder->total_size, in_used,
+ coder->total_limit)
+ || update_size(&coder->compressed_size,
+ in_used,
+ coder->options->compressed_size)
+ || update_size(&coder->uncompressed_size,
+ out_used, coder->uncompressed_limit))
+ return LZMA_DATA_ERROR;
+
+ lzma_check_update(&coder->check, coder->options->check,
+ out + out_start, out_used);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ ret = update_sequence(coder);
+ if (ret != LZMA_OK)
+ return ret;
+
+ break;
+ }
+
+ case SEQ_CHECK:
+ switch (coder->options->check) {
+ case LZMA_CHECK_CRC32:
+ if (((coder->check.crc32 >> (coder->pos * 8))
+ & 0xFF) != in[*in_pos])
+ return LZMA_DATA_ERROR;
+ break;
+
+ case LZMA_CHECK_CRC64:
+ if (((coder->check.crc64 >> (coder->pos * 8))
+ & 0xFF) != in[*in_pos])
+ return LZMA_DATA_ERROR;
+ break;
+
+ case LZMA_CHECK_SHA256:
+ if (coder->check.sha256.buffer[coder->pos]
+ != in[*in_pos])
+ return LZMA_DATA_ERROR;
+ break;
+
+ default:
+ assert(coder->options->check != LZMA_CHECK_NONE);
+ assert(coder->options->check <= LZMA_CHECK_ID_MAX);
+ break;
+ }
+
+ if (update_size(&coder->total_size, 1, coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+
+ if (++coder->pos == lzma_check_sizes[coder->options->check]) {
+ const lzma_ret ret = update_sequence(coder);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->pos = 0;
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE: {
+ const size_t in_start = *in_pos;
+
+ lzma_ret ret = lzma_vli_decode(&coder->tmp,
+ &coder->pos, in, in_pos, in_size);
+
+ if (update_size(&coder->total_size, *in_pos - in_start,
+ coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (coder->tmp != coder->uncompressed_size)
+ return LZMA_DATA_ERROR;
+
+ coder->pos = 0;
+ coder->tmp = 0;
+
+ ret = update_sequence(coder);
+ if (ret != LZMA_OK)
+ return ret;
+
+ break;
+ }
+
+ case SEQ_BACKWARD_SIZE: {
+ const size_t in_start = *in_pos;
+
+ lzma_ret ret = lzma_vli_decode(&coder->tmp,
+ &coder->pos, in, in_pos, in_size);
+
+ const size_t in_used = *in_pos - in_start;
+
+ if (update_size(&coder->total_size, in_used,
+ coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ coder->size_of_backward_size += in_used;
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (coder->tmp != coder->total_size
+ - coder->size_of_backward_size)
+ return LZMA_DATA_ERROR;
+
+ ret = update_sequence(coder);
+ if (ret != LZMA_OK)
+ return ret;
+
+ break;
+ }
+
+ case SEQ_PADDING:
+ if (in[*in_pos] == 0x00) {
+ if (update_size(&coder->total_size, 1,
+ coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+ break;
+ }
+
+ return update_sequence(coder);
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+extern lzma_ret
+lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options)
+{
+ // This is pretty similar to lzma_block_encoder_init().
+ // See comments there.
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &block_decode;
+ next->end = &block_decoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ if (!lzma_vli_is_valid(options->total_size)
+ || !lzma_vli_is_valid(options->compressed_size)
+ || !lzma_vli_is_valid(options->uncompressed_size)
+ || !lzma_vli_is_valid(options->total_size)
+ || !lzma_vli_is_valid(options->total_limit)
+ || !lzma_vli_is_valid(options->uncompressed_limit)
+ || (options->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && options->uncompressed_size
+ > options->uncompressed_limit)
+ || (options->total_size != LZMA_VLI_VALUE_UNKNOWN
+ && options->total_size
+ > options->total_limit)
+ || (!options->has_eopm && options->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN)
+ || options->header_size > options->total_size
+ || (options->handle_padding
+ && (options->has_uncompressed_size_in_footer
+ || options->has_backward_size)))
+ return LZMA_PROG_ERROR;
+
+ {
+ const lzma_ret ret = lzma_check_init(
+ &next->coder->check, options->check);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ if (!options->has_eopm && options->uncompressed_size == 0) {
+ if (!is_size_valid(0, options->compressed_size))
+ return LZMA_PROG_ERROR;
+
+ if (options->check != LZMA_CHECK_NONE) {
+ lzma_check_finish(&next->coder->check, options->check);
+ next->coder->sequence = SEQ_CHECK;
+ } else if (options->handle_padding) {
+ next->coder->sequence = SEQ_PADDING;
+ } else {
+ next->coder->sequence = SEQ_END;
+ }
+ } else {
+ next->coder->sequence = SEQ_CODE;
+ }
+
+ {
+ const lzma_ret ret = lzma_raw_decoder_init(
+ &next->coder->next, allocator,
+ options->filters, options->has_eopm
+ ? LZMA_VLI_VALUE_UNKNOWN
+ : options->uncompressed_size,
+ true);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ next->coder->options = options;
+ next->coder->pos = 0;
+ next->coder->total_size = options->header_size;
+ next->coder->compressed_size = 0;
+ next->coder->uncompressed_size = 0;
+ next->coder->total_limit
+ = MIN(options->total_size, options->total_limit);
+ next->coder->uncompressed_limit = MIN(options->uncompressed_size,
+ options->uncompressed_limit);
+ next->coder->tmp = 0;
+ next->coder->size_of_backward_size = 0;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_block_decoder(lzma_stream *strm, lzma_options_block *options)
+{
+ lzma_next_strm_init(strm, lzma_block_decoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/block_decoder.h b/src/liblzma/common/block_decoder.h
new file mode 100644
index 00000000..af71128d
--- /dev/null
+++ b/src/liblzma/common/block_decoder.h
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_decoder.h
+/// \brief Decodes .lzma Blocks
+//
+// 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_BLOCK_DECODER_H
+#define LZMA_BLOCK_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_options_block *options);
+
+#endif
diff --git a/src/liblzma/common/block_encoder.c b/src/liblzma/common/block_encoder.c
new file mode 100644
index 00000000..77ff78ea
--- /dev/null
+++ b/src/liblzma/common/block_encoder.c
@@ -0,0 +1,375 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_encoder.c
+/// \brief Encodes .lzma Blocks
+//
+// 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 "block_encoder.h"
+#include "block_private.h"
+#include "raw_encoder.h"
+#include "check.h"
+
+
+struct lzma_coder_s {
+ /// The filters in the chain; initialized with lzma_raw_decoder_init().
+ lzma_next_coder next;
+
+ /// 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;
+
+ enum {
+ SEQ_CODE,
+ SEQ_CHECK_FINISH,
+ SEQ_CHECK_COPY,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_BACKWARD_SIZE,
+ SEQ_PADDING,
+ } sequence;
+
+ /// Position in .header and .check.
+ size_t pos;
+
+ /// Check of the uncompressed data
+ lzma_check check;
+
+ /// Total Size calculated while encoding
+ lzma_vli total_size;
+
+ /// Compressed Size calculated while encoding
+ lzma_vli compressed_size;
+
+ /// Uncompressed Size calculated while encoding
+ lzma_vli uncompressed_size;
+
+ /// Maximum allowed total_size
+ lzma_vli total_limit;
+
+ /// Maximum allowed uncompressed_size
+ lzma_vli uncompressed_limit;
+
+ /// Backward Size - This is a copy of total_size right before
+ /// the Backward Size field.
+ lzma_vli backward_size;
+};
+
+
+static lzma_ret
+block_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)
+{
+ // Check that our amount of input stays in proper limits.
+ if (coder->options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ if (action == LZMA_FINISH) {
+ if (coder->options->uncompressed_size
+ - coder->uncompressed_size
+ != (lzma_vli)(in_size - *in_pos))
+ return LZMA_DATA_ERROR;
+ } else {
+ if (coder->options->uncompressed_size
+ - coder->uncompressed_size
+ < (lzma_vli)(in_size - *in_pos))
+ return LZMA_DATA_ERROR;
+ }
+ } else if (LZMA_VLI_VALUE_MAX - coder->uncompressed_size
+ < (lzma_vli)(in_size - *in_pos)) {
+ return LZMA_DATA_ERROR;
+ }
+
+ // Main loop
+ while (*out_pos < out_size
+ && (*in_pos < in_size || action == LZMA_FINISH))
+ switch (coder->sequence) {
+ case SEQ_CODE: {
+ const size_t in_start = *in_pos;
+ 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);
+
+ const size_t in_used = *in_pos - in_start;
+ const size_t out_used = *out_pos - out_start;
+
+ if (update_size(&coder->total_size, out_used,
+ coder->total_limit)
+ || update_size(&coder->compressed_size,
+ out_used,
+ coder->options->compressed_size))
+ return LZMA_DATA_ERROR;
+
+ // No need to check for overflow because we have already
+ // checked it at the beginning of this function.
+ coder->uncompressed_size += in_used;
+
+ lzma_check_update(&coder->check, coder->options->check,
+ in + in_start, in_used);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ assert(*in_pos == in_size);
+
+ // Compressed and Uncompressed Sizes are now at their final
+ // values. Verify that they match the values give to us.
+ if (!is_size_valid(coder->compressed_size,
+ coder->options->compressed_size)
+ || !is_size_valid(coder->uncompressed_size,
+ coder->options->uncompressed_size))
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_CHECK_FINISH;
+ break;
+ }
+
+ case SEQ_CHECK_FINISH:
+ if (coder->options->check == LZMA_CHECK_NONE) {
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ break;
+ }
+
+ lzma_check_finish(&coder->check, coder->options->check);
+ coder->sequence = SEQ_CHECK_COPY;
+
+ // Fall through
+
+ case SEQ_CHECK_COPY:
+ assert(lzma_check_sizes[coder->options->check] > 0);
+
+ switch (coder->options->check) {
+ case LZMA_CHECK_CRC32:
+ out[*out_pos] = coder->check.crc32 >> (coder->pos * 8);
+ break;
+
+ case LZMA_CHECK_CRC64:
+ out[*out_pos] = coder->check.crc64 >> (coder->pos * 8);
+ break;
+
+ case LZMA_CHECK_SHA256:
+ out[*out_pos] = coder->check.sha256.buffer[coder->pos];
+ break;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ ++*out_pos;
+
+ if (update_size(&coder->total_size, 1, coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ if (++coder->pos == lzma_check_sizes[coder->options->check]) {
+ coder->pos = 0;
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ if (coder->options->has_uncompressed_size_in_footer) {
+ const size_t out_start = *out_pos;
+
+ const lzma_ret ret = lzma_vli_encode(
+ coder->uncompressed_size,
+ &coder->pos, 1,
+ out, out_pos, out_size);
+
+ // Updating the size this way instead of doing in a
+ // single chunk using lzma_vli_size(), because this
+ // way we detect when exactly we are going out of
+ // our limits.
+ if (update_size(&coder->total_size,
+ *out_pos - out_start,
+ coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ coder->pos = 0;
+ }
+
+ coder->backward_size = coder->total_size;
+ coder->sequence = SEQ_BACKWARD_SIZE;
+ break;
+
+ case SEQ_BACKWARD_SIZE:
+ if (coder->options->has_backward_size) {
+ const size_t out_start = *out_pos;
+
+ const lzma_ret ret = lzma_vli_encode(
+ coder->backward_size, &coder->pos, 1,
+ out, out_pos, out_size);
+
+ if (update_size(&coder->total_size,
+ *out_pos - out_start,
+ coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+ }
+
+ coder->sequence = SEQ_PADDING;
+ break;
+
+ case SEQ_PADDING:
+ if (coder->options->handle_padding) {
+ assert(!coder->options
+ ->has_uncompressed_size_in_footer);
+ assert(!coder->options->has_backward_size);
+ assert(coder->options->total_size != LZMA_VLI_VALUE_UNKNOWN);
+
+ if (coder->total_size < coder->options->total_size) {
+ out[*out_pos] = 0x00;
+ ++*out_pos;
+
+ if (update_size(&coder->total_size, 1,
+ coder->total_limit))
+ return LZMA_DATA_ERROR;
+
+ break;
+ }
+ }
+
+ // Now also Total Size is known. Verify it.
+ if (!is_size_valid(coder->total_size,
+ coder->options->total_size))
+ return LZMA_DATA_ERROR;
+
+ // Copy the values into coder->options. The caller
+ // may use this information to construct Index.
+ coder->options->total_size = coder->total_size;
+ coder->options->compressed_size = coder->compressed_size;
+ coder->options->uncompressed_size = coder->uncompressed_size;
+
+ return LZMA_STREAM_END;
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_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)
+{
+ // Validate some options.
+ if (options == NULL
+ || !lzma_vli_is_valid(options->total_size)
+ || !lzma_vli_is_valid(options->compressed_size)
+ || !lzma_vli_is_valid(options->uncompressed_size)
+ || !lzma_vli_is_valid(options->total_size)
+ || !lzma_vli_is_valid(options->total_limit)
+ || !lzma_vli_is_valid(options->uncompressed_limit)
+ || (options->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && options->uncompressed_size
+ > options->uncompressed_limit)
+ || (options->total_size != LZMA_VLI_VALUE_UNKNOWN
+ && options->total_size
+ > options->total_limit)
+ || (!options->has_eopm && options->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN)
+ || (options->handle_padding && (options->total_size
+ == LZMA_VLI_VALUE_UNKNOWN
+ || options->has_uncompressed_size_in_footer
+ || options->has_backward_size))
+ || options->header_size > options->total_size)
+ return LZMA_PROG_ERROR;
+
+ // Allocate and initialize *next->coder if needed.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &block_encode;
+ next->end = &block_encoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Initialize the check.
+ return_if_error(lzma_check_init(&next->coder->check, options->check));
+
+ // If End of Payload Marker is not used and Uncompressed Size is zero,
+ // Compressed Data is empty. That is, we don't call the encoder at all.
+ // We initialize it though; it allows detecting invalid options.
+ if (!options->has_eopm && options->uncompressed_size == 0) {
+ // Also Compressed Size must also be zero if it has been
+ // given to us.
+ if (!is_size_valid(options->compressed_size, 0))
+ return LZMA_PROG_ERROR;
+
+ next->coder->sequence = SEQ_CHECK_FINISH;
+ } else {
+ next->coder->sequence = SEQ_CODE;
+ }
+
+ // Other initializations
+ next->coder->options = options;
+ next->coder->pos = 0;
+ next->coder->total_size = options->header_size;
+ next->coder->compressed_size = 0;
+ next->coder->uncompressed_size = 0;
+ next->coder->total_limit
+ = MIN(options->total_size, options->total_limit);
+ next->coder->uncompressed_limit = MIN(options->uncompressed_size,
+ options->uncompressed_limit);
+
+ // Initialize the requested filters.
+ return lzma_raw_encoder_init(&next->coder->next, allocator,
+ options->filters, options->has_eopm
+ ? LZMA_VLI_VALUE_UNKNOWN
+ : options->uncompressed_size,
+ true);
+}
+
+
+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_next_strm_init(strm, block_encoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/block_encoder.h b/src/liblzma/common/block_encoder.h
new file mode 100644
index 00000000..eafcc618
--- /dev/null
+++ b/src/liblzma/common/block_encoder.h
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_encoder.h
+/// \brief Encodes .lzma Blocks
+//
+// 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_BLOCK_ENCODER_H
+#define LZMA_BLOCK_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_options_block *options);
+
+#endif
diff --git a/src/liblzma/common/block_header_decoder.c b/src/liblzma/common/block_header_decoder.c
new file mode 100644
index 00000000..7676c795
--- /dev/null
+++ b/src/liblzma/common/block_header_decoder.c
@@ -0,0 +1,373 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_header_decoder.c
+/// \brief Decodes Block Header from .lzma files
+//
+// 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 "check.h"
+
+
+struct lzma_coder_s {
+ lzma_options_block *options;
+
+ enum {
+ SEQ_FLAGS_1,
+ SEQ_FLAGS_2,
+ SEQ_COMPRESSED_SIZE,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_FILTER_FLAGS_INIT,
+ SEQ_FILTER_FLAGS_DECODE,
+ SEQ_CRC32,
+ SEQ_PADDING
+ } sequence;
+
+ /// Position in variable-length integers
+ size_t pos;
+
+ /// CRC32 of the Block Header
+ uint32_t crc32;
+
+ lzma_next_coder filter_flags_decoder;
+};
+
+
+static bool
+update_sequence(lzma_coder *coder)
+{
+ switch (coder->sequence) {
+ case SEQ_FLAGS_2:
+ if (coder->options->compressed_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ coder->pos = 0;
+ coder->sequence = SEQ_COMPRESSED_SIZE;
+ break;
+ }
+
+ // Fall through
+
+ case SEQ_COMPRESSED_SIZE:
+ if (coder->options->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ coder->pos = 0;
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ break;
+ }
+
+ // Fall through
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ coder->pos = 0;
+
+ // Fall through
+
+ case SEQ_FILTER_FLAGS_DECODE:
+ if (coder->options->filters[coder->pos].id
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ coder->sequence = SEQ_FILTER_FLAGS_INIT;
+ break;
+ }
+
+ if (coder->options->has_crc32) {
+ coder->pos = 0;
+ coder->sequence = SEQ_CRC32;
+ break;
+ }
+
+ case SEQ_CRC32:
+ if (coder->options->padding != 0) {
+ coder->pos = 0;
+ coder->sequence = SEQ_PADDING;
+ break;
+ }
+
+ return true;
+
+ default:
+ assert(0);
+ return true;
+ }
+
+ return false;
+}
+
+
+static lzma_ret
+block_header_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 lzma_attribute((unused)),
+ size_t *restrict out_pos lzma_attribute((unused)),
+ size_t out_size lzma_attribute((unused)),
+ lzma_action action lzma_attribute((unused)))
+{
+ while (*in_pos < in_size)
+ switch (coder->sequence) {
+ case SEQ_FLAGS_1:
+ // Check that the reserved bit is unset. Use HEADER_ERROR
+ // because newer version of liblzma may support the reserved
+ // bit, although it is likely that this is just a broken file.
+ if (in[*in_pos] & 0x40)
+ return LZMA_HEADER_ERROR;
+
+ // Number of filters: we prepare appropriate amount of
+ // variables for variable-length integer parsing. The
+ // initialization function has already reset the rest
+ // of the values to LZMA_VLI_VALUE_UNKNOWN, which allows
+ // us to later know how many filters there are.
+ for (int i = (int)(in[*in_pos] & 0x07) - 1; i >= 0; --i)
+ coder->options->filters[i].id = 0;
+
+ // End of Payload Marker flag
+ coder->options->has_eopm = (in[*in_pos] & 0x08) != 0;
+
+ // Compressed Size: Prepare for variable-length integer
+ // parsing if it is known.
+ if (in[*in_pos] & 0x10)
+ coder->options->compressed_size = 0;
+
+ // Uncompressed Size: the same.
+ if (in[*in_pos] & 0x20)
+ coder->options->uncompressed_size = 0;
+
+ // Is Metadata Block flag
+ coder->options->is_metadata = (in[*in_pos] & 0x80) != 0;
+
+ // We need at least one: Uncompressed Size or EOPM.
+ if (coder->options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN
+ && !coder->options->has_eopm)
+ return LZMA_DATA_ERROR;
+
+ // Update header CRC32.
+ coder->crc32 = lzma_crc32(in + *in_pos, 1, coder->crc32);
+
+ ++*in_pos;
+ coder->sequence = SEQ_FLAGS_2;
+ break;
+
+ case SEQ_FLAGS_2:
+ // Check that the reserved bits are unset.
+ if (in[*in_pos] & 0xE0)
+ return LZMA_DATA_ERROR;
+
+ // Get the size of Header Padding.
+ coder->options->padding = in[*in_pos] & 0x1F;
+
+ coder->crc32 = lzma_crc32(in + *in_pos, 1, coder->crc32);
+
+ ++*in_pos;
+
+ if (update_sequence(coder))
+ return LZMA_STREAM_END;
+
+ break;
+
+ case SEQ_COMPRESSED_SIZE: {
+ // Store the old input position to be used when
+ // updating coder->header_crc32.
+ const size_t in_start = *in_pos;
+
+ const lzma_ret ret = lzma_vli_decode(
+ &coder->options->compressed_size,
+ &coder->pos, in, in_pos, in_size);
+
+ const size_t in_used = *in_pos - in_start;
+
+ coder->options->compressed_reserve += in_used;
+ assert(coder->options->compressed_reserve
+ <= LZMA_VLI_BYTES_MAX);
+
+ coder->options->header_size += in_used;
+
+ coder->crc32 = lzma_crc32(in + in_start, in_used,
+ coder->crc32);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (update_sequence(coder))
+ return LZMA_STREAM_END;
+
+ break;
+ }
+
+ case SEQ_UNCOMPRESSED_SIZE: {
+ const size_t in_start = *in_pos;
+
+ const lzma_ret ret = lzma_vli_decode(
+ &coder->options->uncompressed_size,
+ &coder->pos, in, in_pos, in_size);
+
+ const size_t in_used = *in_pos - in_start;
+
+ coder->options->uncompressed_reserve += in_used;
+ assert(coder->options->uncompressed_reserve
+ <= LZMA_VLI_BYTES_MAX);
+
+ coder->options->header_size += in_used;
+
+ coder->crc32 = lzma_crc32(in + in_start, in_used,
+ coder->crc32);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (update_sequence(coder))
+ return LZMA_STREAM_END;
+
+ break;
+ }
+
+ case SEQ_FILTER_FLAGS_INIT: {
+ assert(coder->options->filters[coder->pos].id
+ != LZMA_VLI_VALUE_UNKNOWN);
+
+ const lzma_ret ret = lzma_filter_flags_decoder_init(
+ &coder->filter_flags_decoder, allocator,
+ &coder->options->filters[coder->pos]);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_FILTER_FLAGS_DECODE;
+ }
+
+ // Fall through
+
+ case SEQ_FILTER_FLAGS_DECODE: {
+ const size_t in_start = *in_pos;
+
+ const lzma_ret ret = coder->filter_flags_decoder.code(
+ coder->filter_flags_decoder.coder,
+ allocator, in, in_pos, in_size,
+ NULL, NULL, 0, LZMA_RUN);
+
+ const size_t in_used = *in_pos - in_start;
+ coder->options->header_size += in_used;
+ coder->crc32 = lzma_crc32(in + in_start,
+ in_used, coder->crc32);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ ++coder->pos;
+
+ if (update_sequence(coder))
+ return LZMA_STREAM_END;
+
+ break;
+ }
+
+ case SEQ_CRC32:
+ assert(coder->options->has_crc32);
+
+ if (in[*in_pos] != ((coder->crc32 >> (coder->pos * 8)) & 0xFF))
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+ ++coder->pos;
+
+ // Check if we reached end of the CRC32 field.
+ if (coder->pos == 4) {
+ coder->options->header_size += 4;
+
+ if (update_sequence(coder))
+ return LZMA_STREAM_END;
+ }
+
+ break;
+
+ case SEQ_PADDING:
+ if (in[*in_pos] != 0x00)
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+ ++coder->options->header_size;
+ ++coder->pos;
+
+ if (coder->pos < (size_t)(coder->options->padding))
+ break;
+
+ return LZMA_STREAM_END;
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+block_header_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->filter_flags_decoder, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+extern lzma_ret
+lzma_block_header_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_options_block *options)
+{
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &block_header_decode;
+ next->end = &block_header_decoder_end;
+ next->coder->filter_flags_decoder = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Assume that Compressed Size and Uncompressed Size are unknown.
+ options->compressed_size = LZMA_VLI_VALUE_UNKNOWN;
+ options->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+
+ // We will calculate the sizes of these fields too so that the
+ // application may rewrite the header if it wishes so.
+ options->compressed_reserve = 0;
+ options->uncompressed_reserve = 0;
+
+ // The Block Flags field is always present, so include its size here
+ // and we don't need to worry about it in block_header_decode().
+ options->header_size = 2;
+
+ // Reset filters[] to indicate empty list of filters.
+ // See SEQ_FLAGS_1 in block_header_decode() for reasoning of this.
+ for (size_t i = 0; i < 8; ++i) {
+ options->filters[i].id = LZMA_VLI_VALUE_UNKNOWN;
+ options->filters[i].options = NULL;
+ }
+
+ next->coder->options = options;
+ next->coder->sequence = SEQ_FLAGS_1;
+ next->coder->pos = 0;
+ next->coder->crc32 = 0;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_block_header_decoder(lzma_stream *strm,
+ lzma_options_block *options)
+{
+ lzma_next_strm_init(strm, lzma_block_header_decoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/block_header_encoder.c b/src/liblzma/common/block_header_encoder.c
new file mode 100644
index 00000000..594b4fc0
--- /dev/null
+++ b/src/liblzma/common/block_header_encoder.c
@@ -0,0 +1,211 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_header_encoder.c
+/// \brief Encodes Block Header for .lzma files
+//
+// 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 "check.h"
+
+
+extern LZMA_API lzma_ret
+lzma_block_header_size(lzma_options_block *options)
+{
+ // Block Flags take two bytes.
+ size_t size = 2;
+
+ // Compressed Size
+ if (!lzma_vli_is_valid(options->compressed_size)) {
+ return LZMA_PROG_ERROR;
+
+ } else if (options->compressed_reserve != 0) {
+ // Make sure that the known Compressed Size fits into the
+ // reserved space. Note that lzma_vli_size() will return zero
+ // if options->compressed_size is LZMA_VLI_VALUE_UNKNOWN, so
+ // we don't need to handle that special case separately.
+ if (options->compressed_reserve > LZMA_VLI_BYTES_MAX
+ || lzma_vli_size(options->compressed_size)
+ > (size_t)(options->compressed_reserve))
+ return LZMA_PROG_ERROR;
+
+ size += options->compressed_reserve;
+
+ } else if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ // Compressed Size is known. We have already checked
+ // that is is a valid VLI, and since it isn't
+ // LZMA_VLI_VALUE_UNKNOWN, we can be sure that
+ // lzma_vli_size() will succeed.
+ size += lzma_vli_size(options->compressed_size);
+ }
+
+ // Uncompressed Size
+ if (!lzma_vli_is_valid(options->uncompressed_size)) {
+ return LZMA_PROG_ERROR;
+
+ } else if (options->uncompressed_reserve != 0) {
+ if (options->uncompressed_reserve > LZMA_VLI_BYTES_MAX
+ || lzma_vli_size(options->uncompressed_size)
+ > (size_t)(options->uncompressed_reserve))
+ return LZMA_PROG_ERROR;
+
+ size += options->uncompressed_reserve;
+
+ } else if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ size += lzma_vli_size(options->uncompressed_size);
+ }
+
+ // List of Filter Flags
+ for (size_t i = 0; options->filters[i].id != LZMA_VLI_VALUE_UNKNOWN;
+ ++i) {
+ // Don't allow too many filters.
+ if (i == 7)
+ return LZMA_PROG_ERROR;
+
+ uint32_t tmp;
+ const lzma_ret ret = lzma_filter_flags_size(&tmp,
+ options->filters + i);
+ if (ret != LZMA_OK)
+ return ret;
+
+ size += tmp;
+ }
+
+ // CRC32
+ if (options->has_crc32)
+ size += 4;
+
+ // Padding
+ int32_t padding;
+ if (options->padding == LZMA_BLOCK_HEADER_PADDING_AUTO) {
+ const uint32_t preferred = lzma_alignment_output(
+ options->filters, 1);
+ const uint32_t unaligned = size + options->alignment;
+ padding = (int32_t)(unaligned % preferred);
+ if (padding != 0)
+ padding = preferred - padding;
+ } else if (options->padding >= LZMA_BLOCK_HEADER_PADDING_MIN
+ && options->padding <= LZMA_BLOCK_HEADER_PADDING_MAX) {
+ padding = options->padding;
+ } else {
+ return LZMA_PROG_ERROR;
+ }
+
+ // All success. Copy the calculated values to the options structure.
+ options->padding = padding;
+ options->header_size = size + (size_t)(padding);
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_block_header_encode(uint8_t *out, const lzma_options_block *options)
+{
+ // We write the Block Flags later.
+ if (options->header_size < 2)
+ return LZMA_PROG_ERROR;
+
+ const size_t out_size = options->header_size;
+ size_t out_pos = 2;
+
+ // Compressed Size
+ if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
+ || options->compressed_reserve != 0) {
+ const lzma_vli size = options->compressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ ? options->compressed_size : 0;
+ size_t vli_pos = 0;
+ if (lzma_vli_encode(
+ size, &vli_pos, options->compressed_reserve,
+ out, &out_pos, out_size) != LZMA_STREAM_END)
+ return LZMA_PROG_ERROR;
+
+ }
+
+ // Uncompressed Size
+ if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
+ || options->uncompressed_reserve != 0) {
+ const lzma_vli size = options->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ ? options->uncompressed_size : 0;
+ size_t vli_pos = 0;
+ if (lzma_vli_encode(
+ size, &vli_pos, options->uncompressed_reserve,
+ out, &out_pos, out_size) != LZMA_STREAM_END)
+ return LZMA_PROG_ERROR;
+
+ }
+
+ // Filter Flags
+ size_t filter_count;
+ for (filter_count = 0; options->filters[filter_count].id
+ != LZMA_VLI_VALUE_UNKNOWN; ++filter_count) {
+ // There can be at maximum of seven filters.
+ if (filter_count == 7)
+ return LZMA_PROG_ERROR;
+
+ const lzma_ret ret = lzma_filter_flags_encode(out, &out_pos,
+ out_size, options->filters + filter_count);
+ // FIXME: Don't return LZMA_BUF_ERROR.
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ // Block Flags 1
+ out[0] = filter_count;
+
+ if (options->has_eopm)
+ out[0] |= 0x08;
+ else if (options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
+ return LZMA_PROG_ERROR;
+
+ if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
+ || options->compressed_reserve != 0)
+ out[0] |= 0x10;
+
+ if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
+ || options->uncompressed_reserve != 0)
+ out[0] |= 0x20;
+
+ if (options->is_metadata)
+ out[0] |= 0x80;
+
+ // Block Flags 2
+ if (options->padding < LZMA_BLOCK_HEADER_PADDING_MIN
+ || options->padding > LZMA_BLOCK_HEADER_PADDING_MAX)
+ return LZMA_PROG_ERROR;
+
+ out[1] = (uint8_t)(options->padding);
+
+ // CRC32
+ if (options->has_crc32) {
+ if (out_size - out_pos < 4)
+ return LZMA_PROG_ERROR;
+
+ const uint32_t crc = lzma_crc32(out, out_pos, 0);
+ for (size_t i = 0; i < 4; ++i)
+ out[out_pos++] = crc >> (i * 8);
+ }
+
+ // Padding - the amount of available space must now match with
+ // the size of the Padding field.
+ if (out_size - out_pos != (size_t)(options->padding))
+ return LZMA_PROG_ERROR;
+
+ memzero(out + out_pos, (size_t)(options->padding));
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/block_private.h b/src/liblzma/common/block_private.h
new file mode 100644
index 00000000..8e2db319
--- /dev/null
+++ b/src/liblzma/common/block_private.h
@@ -0,0 +1,46 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_private.h
+/// \brief Common stuff for Block 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_BLOCK_COMMON_H
+#define LZMA_BLOCK_COMMON_H
+
+#include "common.h"
+
+static inline bool
+update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
+{
+ if (limit > LZMA_VLI_VALUE_MAX)
+ limit = LZMA_VLI_VALUE_MAX;
+
+ if (limit < *size || limit - *size < add)
+ return true;
+
+ *size += add;
+
+ return false;
+}
+
+
+static inline bool
+is_size_valid(lzma_vli size, lzma_vli reference)
+{
+ return reference == LZMA_VLI_VALUE_UNKNOWN || reference == size;
+}
+
+#endif
diff --git a/src/liblzma/common/chunk_size.c b/src/liblzma/common/chunk_size.c
new file mode 100644
index 00000000..042201d2
--- /dev/null
+++ b/src/liblzma/common/chunk_size.c
@@ -0,0 +1,74 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file chunk_size.c
+/// \brief Finds out the minimal reasonable chunk size for a filter 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"
+
+
+/**
+ * \brief Finds out the minimal reasonable chunk size for a filter chain
+ *
+ * This function helps determining the Uncompressed Sizes of the Blocks when
+ * doing multi-threaded encoding.
+ *
+ * When compressing a large file on a system having multiple CPUs or CPU
+ * cores, the file can be splitted in smaller chunks, that are compressed
+ * independently into separate Blocks in the same .lzma Stream.
+ *
+ * \return Minimum reasonable Uncompressed Size of a Block. The
+ * recommended minimum Uncompressed Size is between this value
+ * and the value times two.
+
+ Zero if the Uncompressed Sizes of Blocks don't matter
+ */
+extern LZMA_API size_t
+lzma_chunk_size(const lzma_options_filter *filters)
+{
+ while (filters->id != LZMA_VLI_VALUE_UNKNOWN) {
+ switch (filters->id) {
+ // TODO LZMA_FILTER_SPARSE
+
+ case LZMA_FILTER_COPY:
+ case LZMA_FILTER_SUBBLOCK:
+ case LZMA_FILTER_X86:
+ case LZMA_FILTER_POWERPC:
+ case LZMA_FILTER_IA64:
+ case LZMA_FILTER_ARM:
+ case LZMA_FILTER_ARMTHUMB:
+ case LZMA_FILTER_SPARC:
+ // These are very fast, thus there is no point in
+ // splitting the data in smaller blocks.
+ break;
+
+ case LZMA_FILTER_LZMA:
+ // The block sizes of the possible next filters in
+ // the chain are irrelevant after the LZMA filter.
+ return ((lzma_options_lzma *)(filters->options))
+ ->dictionary_size;
+
+ default:
+ // Unknown filters
+ return 0;
+ }
+
+ ++filters;
+ }
+
+ // Indicate that splitting would be useless.
+ return SIZE_MAX;
+}
diff --git a/src/liblzma/common/code.c b/src/liblzma/common/code.c
new file mode 100644
index 00000000..0e3929b6
--- /dev/null
+++ b/src/liblzma/common/code.c
@@ -0,0 +1,203 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file code.c
+/// \brief zlib-like API wrapper for liblzma's internal 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 "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,
+};
+
+
+extern lzma_ret
+lzma_strm_init(lzma_stream *strm)
+{
+ if (strm == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (strm->internal == NULL) {
+ strm->internal = lzma_alloc(sizeof(lzma_internal),
+ strm->allocator);
+ if (strm->internal == NULL)
+ return LZMA_MEM_ERROR;
+
+ strm->internal->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ strm->internal->supported_actions[LZMA_RUN] = false;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false;
+ strm->internal->supported_actions[LZMA_FULL_FLUSH] = false;
+ strm->internal->supported_actions[LZMA_FINISH] = false;
+ strm->internal->sequence = ISEQ_RUN;
+
+ strm->total_in = 0;
+ strm->total_out = 0;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_code(lzma_stream *strm, lzma_action action)
+{
+ // Sanity checks
+ if ((strm->next_in == NULL && strm->avail_in != 0)
+ || (strm->next_out == NULL && strm->avail_out != 0)
+ || strm->internal == NULL
+ || strm->internal->next.code == NULL
+ || (unsigned int)(action) > LZMA_FINISH
+ || !strm->internal->supported_actions[action])
+ return LZMA_PROG_ERROR;
+
+ switch (strm->internal->sequence) {
+ case ISEQ_RUN:
+ switch (action) {
+ case LZMA_RUN:
+ break;
+
+ case LZMA_SYNC_FLUSH:
+ strm->internal->sequence = ISEQ_SYNC_FLUSH;
+ break;
+
+ case LZMA_FULL_FLUSH:
+ strm->internal->sequence = ISEQ_FULL_FLUSH;
+ break;
+
+ case LZMA_FINISH:
+ strm->internal->sequence = ISEQ_FINISH;
+ break;
+ }
+
+ break;
+
+ case ISEQ_SYNC_FLUSH:
+ if (action != LZMA_SYNC_FLUSH)
+ return LZMA_PROG_ERROR;
+
+ // Check that application doesn't change avail_in once
+ // LZMA_SYNC_FLUSH has been used.
+ if (strm->internal->avail_in != strm->avail_in)
+ return LZMA_DATA_ERROR;
+
+ break;
+
+ case ISEQ_FULL_FLUSH:
+ if (action != LZMA_FULL_FLUSH)
+ return LZMA_PROG_ERROR;
+
+ // Check that application doesn't change avail_in once
+ // LZMA_FULL_FLUSH has been used.
+ if (strm->internal->avail_in != strm->avail_in)
+ return LZMA_DATA_ERROR;
+
+ break;
+
+ case ISEQ_FINISH:
+ if (action != LZMA_FINISH)
+ return LZMA_PROG_ERROR;
+
+ if (strm->internal->avail_in != strm->avail_in)
+ return LZMA_DATA_ERROR;
+
+ break;
+
+ case ISEQ_END:
+ return LZMA_STREAM_END;
+
+ case ISEQ_ERROR:
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ size_t in_pos = 0;
+ size_t out_pos = 0;
+ lzma_ret ret = strm->internal->next.code(
+ strm->internal->next.coder, strm->allocator,
+ strm->next_in, &in_pos, strm->avail_in,
+ strm->next_out, &out_pos, strm->avail_out, action);
+
+ strm->next_in += in_pos;
+ strm->avail_in -= in_pos;
+ strm->total_in += in_pos;
+
+ strm->next_out += out_pos;
+ strm->avail_out -= out_pos;
+ strm->total_out += out_pos;
+
+ strm->internal->avail_in = strm->avail_in;
+
+ switch (ret) {
+ case LZMA_OK:
+ // Don't return LZMA_BUF_ERROR when it happens the first time.
+ // This is to avoid returning LZMA_BUF_ERROR when avail_out
+ // was zero but still there was no more data left to written
+ // to next_out.
+ if (out_pos == 0 && in_pos == 0) {
+ if (strm->internal->allow_buf_error)
+ ret = LZMA_BUF_ERROR;
+ else
+ strm->internal->allow_buf_error = true;
+ } else {
+ strm->internal->allow_buf_error = false;
+ }
+ break;
+
+ case LZMA_STREAM_END:
+ if (strm->internal->sequence == ISEQ_SYNC_FLUSH
+ || strm->internal->sequence == ISEQ_FULL_FLUSH)
+ strm->internal->sequence = ISEQ_RUN;
+ else
+ strm->internal->sequence = ISEQ_END;
+ break;
+
+ case LZMA_UNSUPPORTED_CHECK:
+ strm->internal->allow_buf_error = false;
+ break;
+
+ default:
+ // All the other errors are fatal; coding cannot be continued.
+ strm->internal->sequence = ISEQ_ERROR;
+ break;
+ }
+
+ return ret;
+}
+
+
+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_free(strm->internal, strm->allocator);
+ strm->internal = NULL;
+ }
+
+ return;
+}
diff --git a/src/liblzma/common/common.h b/src/liblzma/common/common.h
new file mode 100644
index 00000000..ca9c2f23
--- /dev/null
+++ b/src/liblzma/common/common.h
@@ -0,0 +1,271 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file common.h
+/// \brief Definitions common to the whole liblzma library
+//
+// 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_COMMON_H
+#define LZMA_COMMON_H
+
+#include "sysdefs.h"
+
+// Don't use ifdef...
+#if HAVE_VISIBILITY
+# define LZMA_API __attribute__((__visibility__("default")))
+#else
+# define LZMA_API
+#endif
+
+
+/// Size of temporary buffers needed in some filters
+#define LZMA_BUFFER_SIZE 4096
+
+
+/// 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)
+
+
+///////////
+// Types //
+///////////
+
+typedef struct lzma_coder_s lzma_coder;
+
+typedef struct lzma_next_coder_s lzma_next_coder;
+
+typedef struct lzma_filter_info_s lzma_filter_info;
+
+
+typedef lzma_ret (*lzma_init_function)(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters);
+
+typedef lzma_ret (*lzma_code_function)(
+ 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);
+
+typedef void (*lzma_end_function)(
+ lzma_coder *coder, lzma_allocator *allocator);
+
+
+/// Hold data and function pointers of the next filter in the chain.
+struct lzma_next_coder_s {
+ /// Pointer to coder-specific data
+ lzma_coder *coder;
+
+ /// "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.
+ uintptr_t init;
+
+ /// Pointer to function to do the actual coding
+ lzma_code_function code;
+
+ /// Pointer to function to free lzma_next_coder.coder
+ lzma_end_function end;
+};
+
+#define LZMA_NEXT_CODER_INIT \
+ (lzma_next_coder){ \
+ .coder = NULL, \
+ .init = 0, \
+ .code = NULL, \
+ .end = NULL, \
+ }
+
+
+struct lzma_internal_s {
+ lzma_next_coder next;
+
+ enum {
+ ISEQ_RUN,
+ ISEQ_SYNC_FLUSH,
+ ISEQ_FULL_FLUSH,
+ ISEQ_FINISH,
+ ISEQ_END,
+ ISEQ_ERROR,
+ } sequence;
+
+ bool supported_actions[4];
+ bool allow_buf_error;
+ 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;
+
+ /// Pointer to filter's options structure
+ void *options;
+
+ /// Uncompressed size of the filter, or LZMA_VLI_VALUE_UNKNOWN
+ /// if unknown.
+ lzma_vli uncompressed_size;
+};
+
+
+/*
+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 //
+///////////////
+
+/// Allocates memory
+extern void *lzma_alloc(size_t size, lzma_allocator *allocator)
+ lzma_attribute((malloc));
+
+/// Frees memory
+extern void lzma_free(void *ptr, lzma_allocator *allocator);
+
+/// Initializes lzma_stream FIXME desc
+extern lzma_ret lzma_strm_init(lzma_stream *strm);
+
+///
+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);
+
+
+extern lzma_ret lzma_filter_flags_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_options_filter *options);
+
+extern lzma_ret lzma_block_header_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_options_block *options);
+
+extern lzma_ret lzma_stream_encoder_single_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_options_stream *options);
+
+extern lzma_ret lzma_stream_decoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_extra **header, lzma_extra **footer);
+
+
+/// \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;
+}
+
+
+/// \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.
+///
+#define lzma_next_coder_init2(next, allocator, cmpfunc, func, ...) \
+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; \
+} 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_stream
+///
+/// lzma_strm initialization with more detailed options.
+#define lzma_next_strm_init2(strm, cmpfunc, func, ...) \
+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); \
+} 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 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) \
+do { \
+ const lzma_ret ret_ = expr; \
+ if (ret_ != LZMA_OK) \
+ return ret_; \
+} while (0)
+
+#endif
diff --git a/src/liblzma/common/copy_coder.c b/src/liblzma/common/copy_coder.c
new file mode 100644
index 00000000..64864f60
--- /dev/null
+++ b/src/liblzma/common/copy_coder.c
@@ -0,0 +1,143 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file copy_coder.c
+/// \brief The Copy filter 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 "copy_coder.h"
+
+
+struct lzma_coder_s {
+ lzma_next_coder next;
+ lzma_vli uncompressed_size;
+ bool is_encoder;
+};
+
+
+static lzma_ret
+copy_code(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)
+{
+ // If we aren't the last filter in the chain, the Copy filter
+ // is totally useless. Note that it is job of the next coder to
+ // take care of Uncompressed Size, so we don't need to update our
+ // coder->uncompressed_size at all.
+ if (coder->next.code != NULL)
+ return coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ action);
+
+ // If we get here, we are the last filter in the chain.
+
+ const size_t in_avail = in_size - *in_pos;
+
+ if (coder->is_encoder) {
+ // Check that we don't have too much input.
+ if ((lzma_vli)(in_avail) > coder->uncompressed_size)
+ return LZMA_DATA_ERROR;
+
+ // Check that once LZMA_FINISH has been given, the
+ // amount of input matches uncompressed_size if it
+ // is known.
+ if (action == LZMA_FINISH && coder->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && coder->uncompressed_size
+ != (lzma_vli)(in_avail))
+ return LZMA_DATA_ERROR;
+
+ } else {
+ // Limit in_size so that we don't copy too much.
+ if ((lzma_vli)(in_avail) > coder->uncompressed_size)
+ in_size = *in_pos + (size_t)(coder->uncompressed_size);
+ }
+
+ // Store the old input position, which is needed to update
+ // coder->uncompressed_size.
+ const size_t in_start = *in_pos;
+
+ // We are the last coder in the chain.
+ // Just copy as much data as possible.
+ bufcpy(in, in_pos, in_size, out, out_pos, out_size);
+
+ // Update uncompressed_size if it is known.
+ if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
+ coder->uncompressed_size -= *in_pos - in_start;
+
+ // action can be LZMA_FINISH only in the encoder.
+ if ((action == LZMA_FINISH && *in_pos == in_size)
+ || coder->uncompressed_size == 0)
+ return LZMA_STREAM_END;
+
+ return LZMA_OK;
+}
+
+
+static void
+copy_coder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+copy_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ // 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;
+
+ next->code = &copy_code;
+ next->end = &copy_coder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Copy Uncompressed Size which is used to limit the output size.
+ next->coder->uncompressed_size = filters[0].uncompressed_size;
+
+ // The coder acts slightly differently as encoder and decoder.
+ next->coder->is_encoder = is_encoder;
+
+ // Initialize the next decoder in the chain, if any.
+ return lzma_next_filter_init(
+ &next->coder->next, allocator, filters + 1);
+}
+
+
+#ifdef HAVE_ENCODER
+extern lzma_ret
+lzma_copy_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ lzma_next_coder_init(copy_coder_init, next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER
+extern lzma_ret
+lzma_copy_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ lzma_next_coder_init(copy_coder_init, next, allocator, filters, false);
+}
+#endif
diff --git a/src/liblzma/common/copy_coder.h b/src/liblzma/common/copy_coder.h
new file mode 100644
index 00000000..b8d0295d
--- /dev/null
+++ b/src/liblzma/common/copy_coder.h
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file copy_coder.h
+/// \brief The Copy filter 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_COPY_CODER_H
+#define LZMA_COPY_CODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_copy_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_copy_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+#endif
diff --git a/src/liblzma/common/delta_coder.c b/src/liblzma/common/delta_coder.c
new file mode 100644
index 00000000..ec8c6d59
--- /dev/null
+++ b/src/liblzma/common/delta_coder.c
@@ -0,0 +1,210 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_coder.c
+/// \brief Encoder and decoder for the Delta filter
+//
+// 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_coder.h"
+
+
+struct lzma_coder_s {
+ /// Next coder in the chain
+ lzma_next_coder next;
+
+ /// Uncompressed size - This is needed when we are the last
+ /// filter in the chain.
+ lzma_vli uncompressed_size;
+
+ /// Delta distance
+ size_t distance;
+
+ /// True if we are encoding; false if decoding
+ bool is_encoder;
+
+ /// Position in history[]
+ uint8_t pos;
+
+ /// Buffer to hold history of the original data
+ uint8_t history[LZMA_DELTA_DISTANCE_MAX];
+};
+
+
+static void
+encode_buffer(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--] = buffer[i];
+ buffer[i] -= tmp;
+ }
+
+ return;
+}
+
+
+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--] = buffer[i];
+ }
+
+ return;
+}
+
+
+static lzma_ret
+delta_code(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)
+{
+ const size_t out_start = *out_pos;
+ size_t size;
+ lzma_ret ret;
+
+ if (coder->next.code == NULL) {
+ const size_t in_avail = in_size - *in_pos;
+
+ if (coder->is_encoder) {
+ // Check that we don't have too much input.
+ if ((lzma_vli)(in_avail) > coder->uncompressed_size)
+ return LZMA_DATA_ERROR;
+
+ // Check that once LZMA_FINISH has been given, the
+ // amount of input matches uncompressed_size if it
+ // is known.
+ if (action == LZMA_FINISH && coder->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && coder->uncompressed_size
+ != (lzma_vli)(in_avail))
+ return LZMA_DATA_ERROR;
+
+ } else {
+ // Limit in_size so that we don't copy too much.
+ if ((lzma_vli)(in_avail) > coder->uncompressed_size)
+ in_size = *in_pos + (size_t)(
+ coder->uncompressed_size);
+ }
+
+ size = bufcpy(in, in_pos, in_size, out, out_pos, out_size);
+
+ if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
+ coder->uncompressed_size -= size;
+
+ // action can be LZMA_FINISH only in the encoder.
+ ret = (action == LZMA_FINISH && *in_pos == in_size)
+ || coder->uncompressed_size == 0
+ ? LZMA_STREAM_END : LZMA_OK;
+
+ } else {
+ ret = coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ action);
+ if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+ return ret;
+
+ size = *out_pos - out_start;
+ }
+
+ if (coder->is_encoder)
+ encode_buffer(coder, out + out_start, size);
+ else
+ decode_buffer(coder, out + out_start, size);
+
+ return ret;
+}
+
+
+static void
+delta_coder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ // 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;
+
+ next->code = &delta_code;
+ next->end = &delta_coder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Copy Uncompressed Size which is used to limit the output size.
+ next->coder->uncompressed_size = filters[0].uncompressed_size;
+
+ // The coder acts slightly differently as encoder and decoder.
+ next->coder->is_encoder = is_encoder;
+
+ // 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.
+ {
+ const lzma_ret ret = lzma_next_filter_init(&next->coder->next,
+ allocator, filters + 1);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ return LZMA_OK;
+}
+
+
+#ifdef HAVE_ENCODER
+extern lzma_ret
+lzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return delta_coder_init(next, allocator, filters, true);
+}
+#endif
+
+
+#ifdef HAVE_DECODER
+extern lzma_ret
+lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return delta_coder_init(next, allocator, filters, false);
+}
+#endif
diff --git a/src/liblzma/common/delta_coder.h b/src/liblzma/common/delta_coder.h
new file mode 100644
index 00000000..60cea95c
--- /dev/null
+++ b/src/liblzma/common/delta_coder.h
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_coder.h
+/// \brief The Delta filter 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_CODER_H
+#define LZMA_DELTA_CODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+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/extra.c b/src/liblzma/common/extra.c
new file mode 100644
index 00000000..b743a439
--- /dev/null
+++ b/src/liblzma/common/extra.c
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file extra.c
+/// \brief Handling of Extra in Metadata
+//
+// 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_API void
+lzma_extra_free(lzma_extra *extra, lzma_allocator *allocator)
+{
+ while (extra != NULL) {
+ lzma_extra *tmp = extra->next;
+ lzma_free(extra, allocator);
+ extra = tmp;
+ }
+
+ return;
+}
diff --git a/src/liblzma/common/features.c b/src/liblzma/common/features.c
new file mode 100644
index 00000000..33b2e0a2
--- /dev/null
+++ b/src/liblzma/common/features.c
@@ -0,0 +1,70 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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_COPY
+ LZMA_FILTER_COPY,
+#endif
+
+#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_flags_decoder.c b/src/liblzma/common/filter_flags_decoder.c
new file mode 100644
index 00000000..515f9346
--- /dev/null
+++ b/src/liblzma/common/filter_flags_decoder.c
@@ -0,0 +1,382 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_flags_decoder.c
+/// \brief Decodes a Filter Flags field
+//
+// 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 "lzma_decoder.h"
+
+
+struct lzma_coder_s {
+ lzma_options_filter *options;
+
+ enum {
+ SEQ_MISC,
+ SEQ_ID,
+ SEQ_SIZE,
+ SEQ_PROPERTIES,
+ } sequence;
+
+ /// \brief Position in variable-length integers
+ size_t pos;
+
+ /// \brief Size of Filter Properties
+ lzma_vli properties_size;
+};
+
+
+#ifdef HAVE_FILTER_SUBBLOCK
+static lzma_ret
+properties_subblock(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *in lzma_attribute((unused)),
+ size_t *in_pos lzma_attribute((unused)),
+ size_t in_size lzma_attribute((unused)))
+{
+ if (coder->properties_size != 0)
+ return LZMA_HEADER_ERROR;
+
+ coder->options->options = lzma_alloc(
+ sizeof(lzma_options_subblock), allocator);
+ if (coder->options->options == NULL)
+ return LZMA_MEM_ERROR;
+
+ ((lzma_options_subblock *)(coder->options->options))
+ ->allow_subfilters = true;
+ return LZMA_STREAM_END;
+}
+#endif
+
+
+#ifdef HAVE_FILTER_SIMPLE
+static lzma_ret
+properties_simple(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+ if (coder->properties_size == 0)
+ return LZMA_STREAM_END;
+
+ if (coder->properties_size != 4)
+ return LZMA_HEADER_ERROR;
+
+ lzma_options_simple *options = coder->options->options;
+
+ if (options == NULL) {
+ options = lzma_alloc(sizeof(lzma_options_simple), allocator);
+ if (options == NULL)
+ return LZMA_MEM_ERROR;
+
+ options->start_offset = 0;
+ coder->options->options = options;
+ }
+
+ while (coder->pos < 4) {
+ if (*in_pos == in_size)
+ return LZMA_OK;
+
+ options->start_offset
+ |= (uint32_t)(in[*in_pos]) << (8 * coder->pos);
+ ++*in_pos;
+ ++coder->pos;
+ }
+
+ // Don't leave an options structure allocated if start_offset is zero.
+ if (options->start_offset == 0) {
+ lzma_free(options, allocator);
+ coder->options->options = NULL;
+ }
+
+ return LZMA_STREAM_END;
+}
+#endif
+
+
+#ifdef HAVE_FILTER_DELTA
+static lzma_ret
+properties_delta(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+ if (coder->properties_size != 1)
+ return LZMA_HEADER_ERROR;
+
+ if (*in_pos == in_size)
+ return LZMA_OK;
+
+ lzma_options_delta *options = lzma_alloc(
+ sizeof(lzma_options_delta), allocator);
+ if (options == NULL)
+ return LZMA_MEM_ERROR;
+
+ coder->options->options = options;
+
+ options->distance = (uint32_t)(in[*in_pos]) + 1;
+ ++*in_pos;
+
+ return LZMA_STREAM_END;
+}
+#endif
+
+
+#ifdef HAVE_FILTER_LZMA
+static lzma_ret
+properties_lzma(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+ // LZMA properties are always two bytes (at least for now).
+ if (coder->properties_size != 2)
+ return LZMA_HEADER_ERROR;
+
+ assert(coder->pos < 2);
+
+ while (*in_pos < in_size) {
+ switch (coder->pos) {
+ case 0:
+ // Allocate the options structure.
+ coder->options->options = lzma_alloc(
+ sizeof(lzma_options_lzma), allocator);
+ if (coder->options->options == NULL)
+ return LZMA_MEM_ERROR;
+
+ // Decode lc, lp, and pb.
+ if (lzma_lzma_decode_properties(
+ coder->options->options, in[*in_pos]))
+ return LZMA_HEADER_ERROR;
+
+ ++*in_pos;
+ ++coder->pos;
+ break;
+
+ case 1: {
+ lzma_options_lzma *options = coder->options->options;
+
+ // Check that reserved bits are unset.
+ if (in[*in_pos] & 0xC0)
+ return LZMA_HEADER_ERROR;
+
+ // Decode the dictionary size. See the file format
+ // specification section 4.3.4.2 to understand this.
+ if (in[*in_pos] == 0) {
+ options->dictionary_size = 1;
+
+ } else if (in[*in_pos] > 59) {
+ // Dictionary size is over 1 GiB.
+ // It's not supported at the moment.
+ return LZMA_HEADER_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
+
+ } else {
+ options->dictionary_size
+ = 2 | ((in[*in_pos] + 1) & 1);
+ options->dictionary_size
+ <<= (in[*in_pos] - 1) / 2;
+ }
+
+ ++*in_pos;
+ return LZMA_STREAM_END;
+ }
+ }
+ }
+
+ assert(coder->pos < 2);
+ return LZMA_OK;
+}
+#endif
+
+
+static lzma_ret
+filter_flags_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 lzma_attribute((unused)),
+ size_t *restrict out_pos lzma_attribute((unused)),
+ size_t out_size lzma_attribute((unused)),
+ lzma_action action lzma_attribute((unused)))
+{
+ while (*in_pos < in_size || coder->sequence == SEQ_PROPERTIES)
+ switch (coder->sequence) {
+ case SEQ_MISC:
+ // Determine the Filter ID and Size of Filter Properties.
+ if (in[*in_pos] >= 0xE0) {
+ // Using External ID. Prepare the ID
+ // for variable-length integer parsing.
+ coder->options->id = 0;
+
+ if (in[*in_pos] == 0xFF) {
+ // Mark that Size of Filter Properties is
+ // unknown, so we know later that there is
+ // external Size of Filter Properties present.
+ coder->properties_size
+ = LZMA_VLI_VALUE_UNKNOWN;
+ } else {
+ // Take Size of Filter Properties from Misc.
+ coder->properties_size = in[*in_pos] - 0xE0;
+ }
+
+ coder->sequence = SEQ_ID;
+
+ } else {
+ // The Filter ID is the same as Misc.
+ coder->options->id = in[*in_pos];
+
+ // The Size of Filter Properties can be calculated
+ // from Misc too.
+ coder->properties_size = in[*in_pos] / 0x20;
+
+ coder->sequence = SEQ_PROPERTIES;
+ }
+
+ ++*in_pos;
+ break;
+
+ case SEQ_ID: {
+ const lzma_ret ret = lzma_vli_decode(&coder->options->id,
+ &coder->pos, in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (coder->properties_size == LZMA_VLI_VALUE_UNKNOWN) {
+ // We have also external Size of Filter
+ // Properties. Prepare the size for
+ // variable-length integer parsing.
+ coder->properties_size = 0;
+ coder->sequence = SEQ_SIZE;
+ } else {
+ coder->sequence = SEQ_PROPERTIES;
+ }
+
+ // Reset pos for its next job.
+ coder->pos = 0;
+ break;
+ }
+
+ case SEQ_SIZE: {
+ const lzma_ret ret = lzma_vli_decode(&coder->properties_size,
+ &coder->pos, in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ coder->pos = 0;
+ coder->sequence = SEQ_PROPERTIES;
+ break;
+ }
+
+ case SEQ_PROPERTIES: {
+ lzma_ret (*get_properties)(lzma_coder *coder,
+ lzma_allocator *allocator, const uint8_t *in,
+ size_t *in_pos, size_t in_size);
+
+ switch (coder->options->id) {
+#ifdef HAVE_FILTER_COPY
+ case LZMA_FILTER_COPY:
+ return coder->properties_size > 0
+ ? LZMA_HEADER_ERROR : LZMA_STREAM_END;
+#endif
+#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;
+ }
+
+ return get_properties(coder, allocator, in, in_pos, in_size);
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+filter_flags_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+extern lzma_ret
+lzma_filter_flags_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_options_filter *options)
+{
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &filter_flags_decode;
+ next->end = &filter_flags_decoder_end;
+ }
+
+ options->id = 0;
+ options->options = NULL;
+
+ next->coder->options = options;
+ next->coder->sequence = SEQ_MISC;
+ next->coder->pos = 0;
+ next->coder->properties_size = 0;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_filter_flags_decoder(lzma_stream *strm, lzma_options_filter *options)
+{
+ lzma_next_strm_init(strm, lzma_filter_flags_decoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/filter_flags_encoder.c b/src/liblzma/common/filter_flags_encoder.c
new file mode 100644
index 00000000..d8f260a1
--- /dev/null
+++ b/src/liblzma/common/filter_flags_encoder.c
@@ -0,0 +1,359 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_flags_encoder.c
+/// \brief Decodes a Filter Flags field
+//
+// 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 "lzma_encoder.h"
+
+
+/// \brief Calculates the size of the Filter Properties field
+///
+/// This currently can return only LZMA_OK or LZMA_HEADER_ERROR, but
+/// with some new filters it may return also LZMA_PROG_ERROR.
+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_COPY
+ case LZMA_FILTER_COPY:
+ *size = 0;
+ break;
+#endif
+
+#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;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_filter_flags_size(uint32_t *size, const lzma_options_filter *options)
+{
+ // Get size of Filter Properties.
+ uint32_t prop_size;
+ const lzma_ret ret = get_properties_size(&prop_size, options);
+ if (ret != LZMA_OK)
+ return ret;
+
+ // Size of Filter ID field if it exists.
+ size_t id_size;
+ size_t prop_size_size;
+ if (options->id < 0xE0
+ && (lzma_vli)(prop_size) == options->id / 0x20) {
+ // ID and Size of Filter Properties fit into Misc.
+ id_size = 0;
+ prop_size_size = 0;
+
+ } else {
+ // At least Filter ID is stored using the External ID field.
+ id_size = lzma_vli_size(options->id);
+ if (id_size == 0)
+ return LZMA_PROG_ERROR;
+
+ if (prop_size <= 30) {
+ // Size of Filter Properties fits into Misc still.
+ prop_size_size = 0;
+ } else {
+ // The Size of Filter Properties field is used too.
+ prop_size_size = lzma_vli_size(prop_size);
+ if (prop_size_size == 0)
+ return LZMA_PROG_ERROR;
+ }
+ }
+
+ // 1 is for the Misc field.
+ *size = 1 + id_size + prop_size_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_BUF_ERROR;
+
+ for (size_t i = 0; i < 4; ++i)
+ out[(*out_pos)++] = options->start_offset >> (i * 8);
+
+ 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_BUF_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)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (out_size - *out_pos < 2)
+ return LZMA_BUF_ERROR;
+
+ // LZMA Properties
+ if (lzma_lzma_encode_properties(options, out + *out_pos))
+ return LZMA_HEADER_ERROR;
+
+ ++*out_pos;
+
+ // Dictionary flags
+ //
+ // Dictionary size is encoded using six bits of
+ // which one is mantissa and five are exponent.
+ //
+ // There are some limits that must hold to keep
+ // this coding working.
+# if LZMA_DICTIONARY_SIZE_MAX > UINT32_MAX / 2
+# error LZMA_DICTIONARY_SIZE_MAX is too big.
+# endif
+# if LZMA_DICTIONARY_SIZE_MIN < 1
+# error LZMA_DICTIONARY_SIZE_MIN cannot be zero.
+# endif
+
+ // Validate it:
+ if (options->dictionary_size < LZMA_DICTIONARY_SIZE_MIN
+ || options->dictionary_size > LZMA_DICTIONARY_SIZE_MAX)
+ return LZMA_HEADER_ERROR;
+
+ if (options->dictionary_size == 1) {
+ // Special case
+ out[*out_pos] = 0x00;
+ } else {
+ // TODO This could be more elegant.
+ uint32_t i = 1;
+ while (((2 | ((i + 1) & 1)) << ((i - 1) / 2))
+ < options->dictionary_size)
+ ++i;
+ out[*out_pos] = i;
+ }
+
+ ++*out_pos;
+
+ 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)
+{
+ // 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;
+ lzma_ret ret = get_properties_size(&prop_size, options);
+ if (ret != LZMA_OK)
+ return ret;
+
+ // Misc, External ID, and Size of Properties
+ if (options->id < 0xE0
+ && (lzma_vli)(prop_size) == options->id / 0x20) {
+ // ID and Size of Filter Properties fit into Misc.
+ out[*out_pos] = options->id;
+ ++*out_pos;
+
+ } else if (prop_size <= 30) {
+ // Size of Filter Properties fits into Misc.
+ out[*out_pos] = prop_size + 0xE0;
+ ++*out_pos;
+
+ // External ID is used to encode the Filter ID. If encoding
+ // the VLI fails, it's because the caller has given as too
+ // little output space, which it should have checked already.
+ // So return LZMA_PROG_ERROR, not LZMA_BUF_ERROR.
+ size_t dummy = 0;
+ if (lzma_vli_encode(options->id, &dummy, 1,
+ out, out_pos, out_size) != LZMA_STREAM_END)
+ return LZMA_PROG_ERROR;
+
+ } else {
+ // Nothing fits into Misc.
+ out[*out_pos] = 0xFF;
+ ++*out_pos;
+
+ // External ID is used to encode the Filter ID.
+ size_t dummy = 0;
+ if (lzma_vli_encode(options->id, &dummy, 1,
+ out, out_pos, out_size) != LZMA_STREAM_END)
+ return LZMA_PROG_ERROR;
+
+ // External Size of Filter Properties
+ dummy = 0;
+ if (lzma_vli_encode(prop_size, &dummy, 1,
+ out, out_pos, out_size) != LZMA_STREAM_END)
+ return LZMA_PROG_ERROR;
+ }
+
+ // Filter Properties
+ switch (options->id) {
+#ifdef HAVE_FILTER_COPY
+ case LZMA_FILTER_COPY:
+ assert(prop_size == 0);
+ ret = options->options == NULL ? LZMA_OK : LZMA_HEADER_ERROR;
+ break;
+#endif
+
+#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
+
+#ifdef HAVE_FILTER_LZMA
+ case LZMA_FILTER_LZMA:
+ ret = properties_lzma(out, out_pos, out_size,
+ options->options);
+ break;
+#endif
+
+ default:
+ assert(0);
+ ret = LZMA_PROG_ERROR;
+ break;
+ }
+
+ return ret;
+}
diff --git a/src/liblzma/common/index.c b/src/liblzma/common/index.c
new file mode 100644
index 00000000..6816b37a
--- /dev/null
+++ b/src/liblzma/common/index.c
@@ -0,0 +1,140 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index.c
+/// \brief Handling of Index in Metadata
+//
+// 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"
+
+
+/**
+ * \brief Duplicates an Index list
+ *
+ * \return A copy of the Index list, or NULL if memory allocation
+ * failed or the original Index was empty.
+ */
+extern LZMA_API lzma_index *
+lzma_index_dup(const lzma_index *old_current, lzma_allocator *allocator)
+{
+ lzma_index *new_head = NULL;
+ lzma_index *new_current = NULL;
+
+ while (old_current != NULL) {
+ lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
+ if (i == NULL) {
+ lzma_index_free(new_head, allocator);
+ return NULL;
+ }
+
+ i->total_size = old_current->total_size;
+ i->uncompressed_size = old_current->uncompressed_size;
+ i->next = NULL;
+
+ if (new_head == NULL)
+ new_head = i;
+ else
+ new_current->next = i;
+
+ new_current = i;
+ old_current = old_current->next;
+ }
+
+ return new_head;
+}
+
+
+/**
+ * \brief Frees an Index list
+ *
+ * All Index Recors in the list are freed. This function is convenient when
+ * getting rid of lzma_metadata structures containing an Index.
+ */
+extern LZMA_API void
+lzma_index_free(lzma_index *i, lzma_allocator *allocator)
+{
+ while (i != NULL) {
+ lzma_index *tmp = i->next;
+ lzma_free(i, allocator);
+ i = tmp;
+ }
+
+ return;
+}
+
+
+/**
+ * \brief Calculates properties of an Index list
+ *
+ *
+ */
+extern LZMA_API lzma_ret
+lzma_index_count(const lzma_index *i, size_t *count,
+ lzma_vli *lzma_restrict total_size,
+ lzma_vli *lzma_restrict uncompressed_size)
+{
+ *count = 0;
+ *total_size = 0;
+ *uncompressed_size = 0;
+
+ while (i != NULL) {
+ if (i->total_size == LZMA_VLI_VALUE_UNKNOWN) {
+ *total_size = LZMA_VLI_VALUE_UNKNOWN;
+ } else if (i->total_size > LZMA_VLI_VALUE_MAX) {
+ return LZMA_PROG_ERROR;
+ } else if (*total_size != LZMA_VLI_VALUE_UNKNOWN) {
+ *total_size += i->total_size;
+ if (*total_size > LZMA_VLI_VALUE_MAX)
+ return LZMA_PROG_ERROR;
+ }
+
+ if (i->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN) {
+ *uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+ } else if (i->uncompressed_size > LZMA_VLI_VALUE_MAX) {
+ return LZMA_PROG_ERROR;
+ } else if (*uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ *uncompressed_size += i->uncompressed_size;
+ if (*uncompressed_size > LZMA_VLI_VALUE_MAX)
+ return LZMA_PROG_ERROR;
+ }
+
+ ++*count;
+ i = i->next;
+ }
+
+ // FIXME ?
+ if (*total_size == LZMA_VLI_VALUE_UNKNOWN
+ || *uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
+ return LZMA_HEADER_ERROR;
+
+ return LZMA_OK;
+}
+
+
+
+extern LZMA_API lzma_bool
+lzma_index_is_equal(const lzma_index *a, const lzma_index *b)
+{
+ while (a != NULL && b != NULL) {
+ if (a->total_size != b->total_size || a->uncompressed_size
+ != b->uncompressed_size)
+ return false;
+
+ a = a->next;
+ b = b->next;
+ }
+
+ return a == b;
+}
diff --git a/src/liblzma/common/info.c b/src/liblzma/common/info.c
new file mode 100644
index 00000000..2a59a029
--- /dev/null
+++ b/src/liblzma/common/info.c
@@ -0,0 +1,823 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file info.c
+/// \brief Collects and verifies integrity of Stream size information
+//
+// 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"
+
+
+struct lzma_info_s {
+ struct {
+ /// Known Size of Header Metadata Block; here's some
+ /// special things:
+ /// - LZMA_VLI_VALUE_UNKNOWN indicates that we don't know
+ /// if Header Metadata Block is present.
+ /// - 0 indicates that Header Metadata Block is not present.
+ lzma_vli header_metadata_size;
+
+ /// Known Total Size of the Data Blocks in the Stream
+ lzma_vli total_size;
+
+ /// Known Uncompressed Size of the Data Blocks in the Stream
+ lzma_vli uncompressed_size;
+
+ /// Known Size of Footer Metadata Block
+ lzma_vli footer_metadata_size;
+ } known;
+
+ struct {
+ /// Sum of Total Size fields stored to the Index so far
+ lzma_vli total_size;
+
+ /// Sum of Uncompressed Size fields stored to the Index so far
+ lzma_vli uncompressed_size;
+
+ /// First Index Record in the list, or NULL if Index is empty.
+ lzma_index *head;
+
+ /// Number of Index Records
+ size_t record_count;
+
+ /// Number of Index Records
+ size_t incomplete_count;
+
+ /// True when we know that no more Records will get added
+ /// to the Index.
+ bool is_final;
+ } index;
+
+ /// Start offset of the Stream. This is needed to calculate
+ /// lzma_info_iter.stream_offset.
+ lzma_vli stream_start_offset;
+
+ /// True if Index is present in Header Metadata Block
+ bool has_index_in_header_metadata;
+};
+
+
+//////////////////////
+// Create/Reset/End //
+//////////////////////
+
+static void
+index_init(lzma_info *info)
+{
+ info->index.total_size = 0;
+ info->index.uncompressed_size = 0;
+ info->index.head = NULL;
+ info->index.record_count = 0;
+ info->index.incomplete_count = 0;
+ info->index.is_final = false;
+ return;
+}
+
+
+static void
+info_init(lzma_info *info)
+{
+ info->known.header_metadata_size = LZMA_VLI_VALUE_UNKNOWN;
+ info->known.total_size = LZMA_VLI_VALUE_UNKNOWN;
+ info->known.uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+ info->known.footer_metadata_size = LZMA_VLI_VALUE_UNKNOWN;
+ info->stream_start_offset = 0;
+ info->has_index_in_header_metadata = false;
+
+ index_init(info);
+
+ return;
+}
+
+
+extern LZMA_API lzma_info *
+lzma_info_init(lzma_info *info, lzma_allocator *allocator)
+{
+ if (info == NULL)
+ info = lzma_alloc(sizeof(lzma_info), allocator);
+ else
+ lzma_index_free(info->index.head, allocator);
+
+ if (info != NULL)
+ info_init(info);
+
+ return info;
+}
+
+
+extern LZMA_API void
+lzma_info_free(lzma_info *info, lzma_allocator *allocator)
+{
+ lzma_index_free(info->index.head, allocator);
+ lzma_free(info, allocator);
+ return;
+}
+
+
+/////////
+// Set //
+/////////
+
+static lzma_ret
+set_size(lzma_vli new_size, lzma_vli *known_size, lzma_vli index_size,
+ bool forbid_zero)
+{
+ assert(new_size <= LZMA_VLI_VALUE_MAX);
+
+ lzma_ret ret = LZMA_OK;
+
+ if (forbid_zero && new_size == 0)
+ ret = LZMA_PROG_ERROR;
+ else if (index_size > new_size)
+ ret = LZMA_DATA_ERROR;
+ else if (*known_size == LZMA_VLI_VALUE_UNKNOWN)
+ *known_size = new_size;
+ else if (*known_size != new_size)
+ ret = LZMA_DATA_ERROR;
+
+ return ret;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_size_set(lzma_info *info, lzma_info_size type, lzma_vli size)
+{
+ if (size > LZMA_VLI_VALUE_MAX)
+ return LZMA_PROG_ERROR;
+
+ switch (type) {
+ case LZMA_INFO_STREAM_START:
+ info->stream_start_offset = size;
+ return LZMA_OK;
+
+ case LZMA_INFO_HEADER_METADATA:
+ return set_size(size, &info->known.header_metadata_size,
+ 0, false);
+
+ case LZMA_INFO_TOTAL:
+ return set_size(size, &info->known.total_size,
+ info->index.total_size, true);
+
+ case LZMA_INFO_UNCOMPRESSED:
+ return set_size(size, &info->known.uncompressed_size,
+ info->index.uncompressed_size, false);
+
+ case LZMA_INFO_FOOTER_METADATA:
+ return set_size(size, &info->known.footer_metadata_size,
+ 0, true);
+ }
+
+ return LZMA_PROG_ERROR;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_index_set(lzma_info *info, lzma_allocator *allocator,
+ lzma_index *i_new, lzma_bool eat_index)
+{
+ if (i_new == NULL)
+ return LZMA_PROG_ERROR;
+
+ lzma_index *i_old = info->index.head;
+
+ if (i_old != NULL) {
+ while (true) {
+ // If the new Index has fewer Records than the old one,
+ // the new Index cannot be valid.
+ if (i_new == NULL)
+ return LZMA_DATA_ERROR;
+
+ // The new Index must be complete i.e. no unknown
+ // values.
+ if (i_new->total_size > LZMA_VLI_VALUE_MAX
+ || i_new->uncompressed_size
+ > LZMA_VLI_VALUE_MAX) {
+ if (eat_index)
+ lzma_index_free(i_new, allocator);
+
+ return LZMA_PROG_ERROR;
+ }
+
+ // Compare the values from the new Index with the old
+ // Index. The old Index may be incomplete; in that
+ // case we
+ // - use the value from the new Index as is;
+ // - update the appropriate info->index.foo_size; and
+ // - decrease the count of incomplete Index Records.
+ bool was_incomplete = false;
+
+ if (i_old->total_size == LZMA_VLI_VALUE_UNKNOWN) {
+ assert(!info->index.is_final);
+ was_incomplete = true;
+
+ i_old->total_size = i_new->total_size;
+
+ if (lzma_vli_add(info->index.total_size,
+ i_new->total_size)) {
+ if (eat_index)
+ lzma_index_free(i_new,
+ allocator);
+
+ return LZMA_PROG_ERROR;
+ }
+ } else if (i_old->total_size != i_new->total_size) {
+ if (eat_index)
+ lzma_index_free(i_new, allocator);
+
+ return LZMA_DATA_ERROR;
+ }
+
+ if (i_old->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN) {
+ assert(!info->index.is_final);
+ was_incomplete = true;
+
+ i_old->uncompressed_size
+ = i_new->uncompressed_size;
+
+ if (lzma_vli_add(info->index.uncompressed_size,
+ i_new->uncompressed_size)) {
+ if (eat_index)
+ lzma_index_free(i_new,
+ allocator);
+
+ return LZMA_PROG_ERROR;
+ }
+ } else if (i_old->uncompressed_size
+ != i_new->uncompressed_size) {
+ if (eat_index)
+ lzma_index_free(i_new, allocator);
+
+ return LZMA_DATA_ERROR;
+ }
+
+ if (was_incomplete) {
+ assert(!info->index.is_final);
+ assert(info->index.incomplete_count > 0);
+ --info->index.incomplete_count;
+ }
+
+ // Get rid of *i_new. It's now identical with *i_old.
+ lzma_index *tmp = i_new->next;
+ if (eat_index)
+ lzma_free(i_new, allocator);
+
+ i_new = tmp;
+
+ // We want to leave i_old pointing to the last
+ // Index Record in the old Index. This way we can
+ // concatenate the possible new Records from i_new.
+ if (i_old->next == NULL)
+ break;
+
+ i_old = i_old->next;
+ }
+ }
+
+ assert(info->index.incomplete_count == 0);
+
+ // If Index was already known to be final, i_new must be NULL now.
+ // The new Index cannot contain more Records that we already have.
+ if (info->index.is_final) {
+ assert(info->index.head != NULL);
+
+ if (i_new != NULL) {
+ if (eat_index)
+ lzma_index_free(i_new, allocator);
+
+ return LZMA_DATA_ERROR;
+ }
+
+ return LZMA_OK;
+ }
+
+ // The rest of the new Index is merged to the old Index. Keep the
+ // current i_new pointer in available. We need it when merging the
+ // new Index with the old one, and if an error occurs so we can
+ // get rid of the broken part of the new Index.
+ lzma_index *i_start = i_new;
+ while (i_new != NULL) {
+ // The new Index must be complete i.e. no unknown values.
+ if (i_new->total_size > LZMA_VLI_VALUE_MAX
+ || i_new->uncompressed_size
+ > LZMA_VLI_VALUE_MAX) {
+ if (eat_index)
+ lzma_index_free(i_start, allocator);
+
+ return LZMA_PROG_ERROR;
+ }
+
+ // Update info->index.foo_sizes.
+ if (lzma_vli_add(info->index.total_size, i_new->total_size)
+ || lzma_vli_add(info->index.uncompressed_size,
+ i_new->uncompressed_size)) {
+ if (eat_index)
+ lzma_index_free(i_start, allocator);
+
+ return LZMA_PROG_ERROR;
+ }
+
+ ++info->index.record_count;
+ i_new = i_new->next;
+ }
+
+ // All the Records in the new Index are good, and info->index.foo_sizes
+ // were successfully updated.
+ if (lzma_info_index_finish(info) != LZMA_OK) {
+ if (eat_index)
+ lzma_index_free(i_start, allocator);
+
+ return LZMA_DATA_ERROR;
+ }
+
+ // The Index is ready to be merged. If we aren't supposed to eat
+ // the Index, make a copy of it first.
+ if (!eat_index && i_start != NULL) {
+ i_start = lzma_index_dup(i_start, allocator);
+ if (i_start == NULL)
+ return LZMA_MEM_ERROR;
+ }
+
+ // Concatenate the new Index with the old one. Note that it is
+ // possible that we don't have any old Index.
+ if (info->index.head == NULL)
+ info->index.head = i_start;
+ else
+ i_old->next = i_start;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_metadata_set(lzma_info *info, lzma_allocator *allocator,
+ lzma_metadata *metadata, lzma_bool is_header_metadata,
+ lzma_bool eat_index)
+{
+ // Validate *metadata.
+ if (!lzma_vli_is_valid(metadata->header_metadata_size)
+ || !lzma_vli_is_valid(metadata->total_size)
+ || !lzma_vli_is_valid(metadata->uncompressed_size)) {
+ if (eat_index) {
+ lzma_index_free(metadata->index, allocator);
+ metadata->index = NULL;
+ }
+
+ return LZMA_PROG_ERROR;
+ }
+
+ // Index
+ if (metadata->index != NULL) {
+ if (is_header_metadata)
+ info->has_index_in_header_metadata = true;
+
+ const lzma_ret ret = lzma_info_index_set(
+ info, allocator, metadata->index, eat_index);
+ if (ret != LZMA_OK)
+ return ret;
+
+ } else if (!is_header_metadata
+ && (metadata->total_size == LZMA_VLI_VALUE_UNKNOWN
+ || !info->has_index_in_header_metadata)) {
+ // Either Total Size or Index must be present in Footer
+ // Metadata Block. If Index is not present, it must have
+ // already been in the Header Metadata Block. Since we
+ // got here, these conditions weren't met.
+ return LZMA_DATA_ERROR;
+ }
+
+ // Size of Header Metadata
+ if (!is_header_metadata) {
+ // If it is marked unknown in Metadata, it means that
+ // it's not present.
+ const lzma_vli size = metadata->header_metadata_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ ? metadata->header_metadata_size : 0;
+ const lzma_ret ret = lzma_info_size_set(
+ info, LZMA_INFO_HEADER_METADATA, size);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ // Total Size
+ if (metadata->total_size != LZMA_VLI_VALUE_UNKNOWN) {
+ const lzma_ret ret = lzma_info_size_set(info,
+ LZMA_INFO_TOTAL, metadata->total_size);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ // Uncompressed Size
+ if (metadata->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ const lzma_ret ret = lzma_info_size_set(info,
+ LZMA_INFO_UNCOMPRESSED,
+ metadata->uncompressed_size);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ return LZMA_OK;
+}
+
+
+/////////
+// Get //
+/////////
+
+extern LZMA_API lzma_vli
+lzma_info_size_get(const lzma_info *info, lzma_info_size type)
+{
+ switch (type) {
+ case LZMA_INFO_STREAM_START:
+ return info->stream_start_offset;
+
+ case LZMA_INFO_HEADER_METADATA:
+ return info->known.header_metadata_size;
+
+ case LZMA_INFO_TOTAL:
+ return info->known.total_size;
+
+ case LZMA_INFO_UNCOMPRESSED:
+ return info->known.uncompressed_size;
+
+ case LZMA_INFO_FOOTER_METADATA:
+ return info->known.footer_metadata_size;
+ }
+
+ return LZMA_VLI_VALUE_UNKNOWN;
+}
+
+
+extern LZMA_API lzma_index *
+lzma_info_index_get(lzma_info *info, lzma_bool detach)
+{
+ lzma_index *i = info->index.head;
+
+ if (detach)
+ index_init(info);
+
+ return i;
+}
+
+
+extern LZMA_API size_t
+lzma_info_index_count_get(const lzma_info *info)
+{
+ return info->index.record_count;
+}
+
+
+/////////////////
+// Incremental //
+/////////////////
+
+enum {
+ ITER_INFO,
+ ITER_INDEX,
+ ITER_RESERVED_1,
+ ITER_RESERVED_2,
+};
+
+
+#define iter_info ((lzma_info *)(iter->internal[ITER_INFO]))
+
+#define iter_index ((lzma_index *)(iter->internal[ITER_INDEX]))
+
+
+extern LZMA_API void
+lzma_info_iter_begin(lzma_info *info, lzma_info_iter *iter)
+{
+ *iter = (lzma_info_iter){
+ .total_size = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_size = LZMA_VLI_VALUE_UNKNOWN,
+ .stream_offset = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_offset = LZMA_VLI_VALUE_UNKNOWN,
+ .internal = { info, NULL, NULL, NULL },
+ };
+
+ return;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_iter_next(lzma_info_iter *iter, lzma_allocator *allocator)
+{
+ // FIXME debug remove
+ lzma_info *info = iter_info;
+ (void)info;
+
+ if (iter_index == NULL) {
+ // The first call after lzma_info_iter_begin().
+ if (iter_info->known.header_metadata_size
+ == LZMA_VLI_VALUE_UNKNOWN)
+ iter->stream_offset = LZMA_VLI_VALUE_UNKNOWN;
+ else if (lzma_vli_sum3(iter->stream_offset,
+ iter_info->stream_start_offset,
+ LZMA_STREAM_HEADER_SIZE,
+ iter_info->known.header_metadata_size))
+ return LZMA_PROG_ERROR;
+
+ iter->uncompressed_offset = 0;
+
+ if (iter_info->index.head != NULL) {
+ // The first Index Record has already been allocated.
+ iter->internal[ITER_INDEX] = iter_info->index.head;
+ iter->total_size = iter_index->total_size;
+ iter->uncompressed_size
+ = iter_index->uncompressed_size;
+ return LZMA_OK;
+ }
+ } else {
+ // Update iter->*_offsets.
+ if (iter->stream_offset != LZMA_VLI_VALUE_UNKNOWN) {
+ if (iter_index->total_size == LZMA_VLI_VALUE_UNKNOWN)
+ iter->stream_offset = LZMA_VLI_VALUE_UNKNOWN;
+ else if (lzma_vli_add(iter->stream_offset,
+ iter_index->total_size))
+ return LZMA_DATA_ERROR;
+ }
+
+ if (iter->uncompressed_offset != LZMA_VLI_VALUE_UNKNOWN) {
+ if (iter_index->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN)
+ iter->uncompressed_offset
+ = LZMA_VLI_VALUE_UNKNOWN;
+ else if (lzma_vli_add(iter->uncompressed_offset,
+ iter_index->uncompressed_size))
+ return LZMA_DATA_ERROR;
+ }
+
+ if (iter_index->next != NULL) {
+ // The next Record has already been allocated.
+ iter->internal[ITER_INDEX] = iter_index->next;
+ iter->total_size = iter_index->total_size;
+ iter->uncompressed_size
+ = iter_index->uncompressed_size;
+ return LZMA_OK;
+ }
+ }
+
+ // Don't add new Records to a final Index.
+ if (iter_info->index.is_final)
+ return LZMA_DATA_ERROR;
+
+ // Allocate and initialize a new Index Record.
+ lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
+ if (i == NULL)
+ return LZMA_MEM_ERROR;
+
+ i->total_size = LZMA_VLI_VALUE_UNKNOWN;
+ i->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+ i->next = NULL;
+
+ iter->total_size = LZMA_VLI_VALUE_UNKNOWN;
+ iter->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+
+ // Decide where to put the new Index Record.
+ if (iter_info->index.head == NULL)
+ iter_info->index.head = i;
+
+ if (iter_index != NULL)
+ iter_index->next = i;
+
+ iter->internal[ITER_INDEX] = i;
+
+ ++iter_info->index.record_count;
+ ++iter_info->index.incomplete_count;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_iter_set(lzma_info_iter *iter,
+ lzma_vli total_size, lzma_vli uncompressed_size)
+{
+ // FIXME debug remove
+ lzma_info *info = iter_info;
+ (void)info;
+
+ if (iter_index == NULL || !lzma_vli_is_valid(total_size)
+ || !lzma_vli_is_valid(uncompressed_size))
+ return LZMA_PROG_ERROR;
+
+ const bool was_incomplete = iter_index->total_size
+ == LZMA_VLI_VALUE_UNKNOWN
+ || iter_index->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN;
+
+ if (total_size != LZMA_VLI_VALUE_UNKNOWN) {
+ if (iter_index->total_size == LZMA_VLI_VALUE_UNKNOWN) {
+ iter_index->total_size = total_size;
+
+ if (lzma_vli_add(iter_info->index.total_size,
+ total_size)
+ || iter_info->index.total_size
+ > iter_info->known.total_size)
+ return LZMA_DATA_ERROR;
+
+ } else if (iter_index->total_size != total_size) {
+ return LZMA_DATA_ERROR;
+ }
+ }
+
+ if (uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
+ if (iter_index->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN) {
+ iter_index->uncompressed_size = uncompressed_size;
+
+ if (lzma_vli_add(iter_info->index.uncompressed_size,
+ uncompressed_size)
+ || iter_info->index.uncompressed_size
+ > iter_info->known.uncompressed_size)
+ return LZMA_DATA_ERROR;
+
+ } else if (iter_index->uncompressed_size
+ != uncompressed_size) {
+ return LZMA_DATA_ERROR;
+ }
+ }
+
+ // Check if the new information we got managed to finish this
+ // Index Record. If so, update the count of incomplete Index Records.
+ if (was_incomplete && iter_index->total_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && iter_index->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ assert(iter_info->index.incomplete_count > 0);
+ --iter_info->index.incomplete_count;
+ }
+
+ // Make sure that the known sizes are now available in *iter.
+ iter->total_size = iter_index->total_size;
+ iter->uncompressed_size = iter_index->uncompressed_size;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_index_finish(lzma_info *info)
+{
+ if (info->index.record_count == 0 || info->index.incomplete_count > 0
+ || lzma_info_size_set(info, LZMA_INFO_TOTAL,
+ info->index.total_size)
+ || lzma_info_size_set(info, LZMA_INFO_UNCOMPRESSED,
+ info->index.uncompressed_size))
+ return LZMA_DATA_ERROR;
+
+ info->index.is_final = true;
+
+ return LZMA_OK;
+}
+
+
+//////////////
+// Locating //
+//////////////
+
+extern LZMA_API lzma_vli
+lzma_info_metadata_locate(const lzma_info *info, lzma_bool is_header_metadata)
+{
+ bool error = false;
+ lzma_vli size = 0;
+
+ if (info->known.header_metadata_size == LZMA_VLI_VALUE_UNKNOWN) {
+ // We don't know if Header Metadata Block is present, thus
+ // we cannot locate it either.
+ //
+ // Well, you could say that just assume that it is present.
+ // I'm not sure if this is useful. But it can be useful to
+ // be able to use this function and get LZMA_VLI_VALUE_UNKNOWN
+ // to detect that Header Metadata Block wasn't present.
+ error = true;
+ } else if (is_header_metadata) {
+ error = lzma_vli_sum(size, info->stream_start_offset,
+ LZMA_STREAM_HEADER_SIZE);
+ } else if (!info->index.is_final) {
+ // Since we don't know if we have all the Index Records yet,
+ // we cannot know where the Footer Metadata Block is.
+ error = true;
+ } else {
+ error = lzma_vli_sum4(size, info->stream_start_offset,
+ LZMA_STREAM_HEADER_SIZE,
+ info->known.header_metadata_size,
+ info->known.total_size);
+ }
+
+ return error ? LZMA_VLI_VALUE_UNKNOWN : size;
+}
+
+
+extern LZMA_API uint32_t
+lzma_info_metadata_alignment_get(
+ const lzma_info *info, lzma_bool is_header_metadata)
+{
+ uint32_t alignment;
+
+ if (is_header_metadata) {
+ alignment = info->stream_start_offset
+ + LZMA_STREAM_HEADER_SIZE;
+ } else {
+ alignment = info->stream_start_offset + LZMA_STREAM_HEADER_SIZE
+ + info->known.header_metadata_size
+ + info->known.total_size;
+ }
+
+ return alignment;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_info_iter_locate(lzma_info_iter *iter, lzma_allocator *allocator,
+ lzma_vli uncompressed_offset, lzma_bool allow_alloc)
+{
+ if (iter == NULL || uncompressed_offset > LZMA_VLI_VALUE_MAX)
+ return LZMA_PROG_ERROR;
+
+ // Quick check in case Index is final.
+ if (iter_info->index.is_final) {
+ assert(iter_info->known.uncompressed_size
+ == iter_info->index.uncompressed_size);
+ if (uncompressed_offset >= iter_info->index.uncompressed_size)
+ return LZMA_DATA_ERROR;
+ }
+
+ // TODO: Optimize so that it uses existing info from *iter when
+ // seeking forward.
+
+ // Initialize *iter
+ if (iter_info->known.header_metadata_size != LZMA_VLI_VALUE_UNKNOWN) {
+ if (lzma_vli_sum3(iter->stream_offset,
+ iter_info->stream_start_offset,
+ LZMA_STREAM_HEADER_SIZE,
+ iter_info->known.header_metadata_size))
+ return LZMA_PROG_ERROR;
+ } else {
+ // We don't know the Size of Header Metadata Block, thus
+ // we cannot calculate the Stream offset either.
+ iter->stream_offset = LZMA_VLI_VALUE_UNKNOWN;
+ }
+
+ iter->uncompressed_offset = 0;
+
+ // If we have no Index Records, it's obvious that we need to
+ // add a new one.
+ if (iter_info->index.head == NULL) {
+ assert(!iter_info->index.is_final);
+ if (!allow_alloc)
+ return LZMA_DATA_ERROR;
+
+ return lzma_info_iter_next(iter, allocator);
+ }
+
+ // Locate an appropriate Index Record.
+ lzma_index *i = iter_info->index.head;
+ while (true) {
+ // - If Uncompressed Size in the Record is unknown,
+ // we have no chance to search further.
+ // - If the next Record would go past the requested offset,
+ // we have found our target Data Block.
+ if (i->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN
+ || iter->uncompressed_offset
+ + i->uncompressed_size > uncompressed_offset) {
+ iter->total_size = i->total_size;
+ iter->uncompressed_size = i->uncompressed_size;
+ iter->internal[ITER_INDEX] = i;
+ return LZMA_OK;
+ }
+
+ // Update the stream offset. It may be unknown if we didn't
+ // know the size of Header Metadata Block.
+ if (iter->stream_offset != LZMA_VLI_VALUE_UNKNOWN)
+ if (lzma_vli_add(iter->stream_offset, i->total_size))
+ return LZMA_PROG_ERROR;
+
+ // Update the uncompressed offset. This cannot overflow since
+ // the Index is known to be valid.
+ iter->uncompressed_offset += i->uncompressed_size;
+
+ // Move to the next Block.
+ if (i->next == NULL) {
+ assert(!iter_info->index.is_final);
+ if (!allow_alloc)
+ return LZMA_DATA_ERROR;
+
+ iter->internal[ITER_INDEX] = i;
+ return lzma_info_iter_next(iter, allocator);
+ }
+
+ i = i->next;
+ }
+}
diff --git a/src/liblzma/common/init.c b/src/liblzma/common/init.c
new file mode 100644
index 00000000..fb377f5a
--- /dev/null
+++ b/src/liblzma/common/init.c
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file init.c
+/// \brief Static internal initializations
+///
+/// The initializations have been splitted to so many small files to prevent
+/// an application needing only decoder functions from statically linking
+/// also the encoder functions.
+//
+// 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_API void
+lzma_init(void)
+{
+#ifdef HAVE_ENCODER
+ lzma_init_encoder();
+#endif
+
+#ifdef HAVE_DECODER
+ lzma_init_decoder();
+#endif
+
+ return;
+}
diff --git a/src/liblzma/common/init_decoder.c b/src/liblzma/common/init_decoder.c
new file mode 100644
index 00000000..2d61b451
--- /dev/null
+++ b/src/liblzma/common/init_decoder.c
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file init_decoder.c
+/// \brief Static internal initializations
+//
+// 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_API void
+lzma_init_decoder(void)
+{
+ // So far there's no decoder-specific stuff to initialize.
+
+#ifdef HAVE_CHECK
+ lzma_init_check();
+#endif
+
+ return;
+}
diff --git a/src/liblzma/common/init_encoder.c b/src/liblzma/common/init_encoder.c
new file mode 100644
index 00000000..4d3da506
--- /dev/null
+++ b/src/liblzma/common/init_encoder.c
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file init_encoder.c
+/// \brief Static internal initializations
+//
+// 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 "range_encoder.h"
+#include "lzma_encoder.h"
+
+
+extern LZMA_API void
+lzma_init_encoder(void)
+{
+ static bool already_initialized = false;
+ if (already_initialized)
+ return;
+
+#ifdef HAVE_CHECK
+ lzma_init_check();
+#endif
+
+// FIXME TODO Create precalculated tables.
+#if defined(HAVE_ENCODER) && defined(HAVE_FILTER_LZMA)
+ lzma_rc_init();
+ lzma_fastpos_init();
+#endif
+
+ already_initialized = true;
+ return;
+}
diff --git a/src/liblzma/common/memory_limitter.c b/src/liblzma/common/memory_limitter.c
new file mode 100644
index 00000000..19cdefc2
--- /dev/null
+++ b/src/liblzma/common/memory_limitter.c
@@ -0,0 +1,200 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file memory_limitter.c
+/// \brief Limitting memory usage
+//
+// 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"
+
+
+/// Rounds an unsigned integer upwards to the next multiple.
+#define my_ceil(num, multiple) \
+ ((num) + (((multiple) - ((num) % (multiple))) % (multiple)))
+
+
+/// Rounds upwards to the next multiple of 2 * sizeof(void*).
+/// malloc() tends to align allocations this way.
+#define malloc_ceil(num) my_ceil(num, 2 * sizeof(void *))
+
+
+typedef struct lzma_memlimit_list_s lzma_memlimit_list;
+struct lzma_memlimit_list_s {
+ lzma_memlimit_list *next;
+ void *ptr;
+ size_t size;
+};
+
+
+struct lzma_memlimit_s {
+ size_t used;
+ size_t limit;
+ lzma_memlimit_list *list;
+};
+
+
+extern LZMA_API lzma_memlimit *
+lzma_memlimit_create(size_t limit)
+{
+ if (limit < sizeof(lzma_memlimit))
+ return NULL;
+
+ lzma_memlimit *mem = malloc(sizeof(lzma_memlimit));
+
+ if (mem != NULL) {
+ mem->used = sizeof(lzma_memlimit);
+ mem->limit = limit;
+ mem->list = NULL;
+ }
+
+ return mem;
+}
+
+
+extern LZMA_API void
+lzma_memlimit_set(lzma_memlimit *mem, size_t limit)
+{
+ mem->limit = limit;
+ return;
+}
+
+
+extern LZMA_API size_t
+lzma_memlimit_get(const lzma_memlimit *mem)
+{
+ return mem->limit;
+}
+
+
+extern LZMA_API size_t
+lzma_memlimit_used(const lzma_memlimit *mem)
+{
+ return mem->used;
+}
+
+
+extern LZMA_API void
+lzma_memlimit_end(lzma_memlimit *mem, lzma_bool free_allocated)
+{
+ if (mem == NULL)
+ return;
+
+ lzma_memlimit_list *record = mem->list;
+ while (record != NULL) {
+ if (free_allocated)
+ free(record->ptr);
+
+ lzma_memlimit_list *tmp = record;
+ record = record->next;
+ free(tmp);
+ }
+
+ free(mem);
+
+ return;
+}
+
+
+extern LZMA_API void *
+lzma_memlimit_alloc(lzma_memlimit *mem, size_t nmemb, size_t size)
+{
+ // While liblzma always sets nmemb to one, do this multiplication
+ // to make these functions usable e.g. with zlib and libbzip2.
+ // Making sure that this doesn't overflow is up to the application.
+ size *= nmemb;
+
+ // Some malloc() implementations return NULL on malloc(0). We like
+ // to get a non-NULL value.
+ if (size == 0)
+ size = 1;
+
+ // Calculate how much memory we are going to allocate in reality.
+ // TODO: We should add some rough estimate how much malloc() needs
+ // for its internal structures.
+ const size_t total_size = malloc_ceil(size)
+ + malloc_ceil(sizeof(lzma_memlimit_list));
+
+ // Integer overflow protection
+ if (SIZE_MAX - size <= total_size)
+ return NULL;
+
+ if (mem->limit < mem->used || mem->limit - mem->used < total_size)
+ return NULL;
+
+ lzma_memlimit_list *record = malloc(sizeof(lzma_memlimit_list));
+ void *ptr = malloc(size);
+
+ if (record == NULL || ptr == NULL) {
+ free(record);
+ free(ptr);
+ return NULL;
+ }
+
+ // Add the new entry to the beginning of the list. This should be
+ // more efficient when freeing memory, because usually it is
+ // "last allocated, first freed".
+ record->next = mem->list;
+ record->ptr = ptr;
+ record->size = total_size;
+
+ mem->list = record;
+ mem->used += total_size;
+
+ return ptr;
+}
+
+
+extern LZMA_API void
+lzma_memlimit_detach(lzma_memlimit *mem, void *ptr)
+{
+ if (ptr == NULL || mem->list == NULL)
+ return;
+
+ lzma_memlimit_list *record = mem->list;
+ lzma_memlimit_list *prev = NULL;
+
+ while (record->ptr != ptr) {
+ prev = record;
+ record = record->next;
+ if (record == NULL)
+ return;
+ }
+
+ if (prev != NULL)
+ prev->next = record->next;
+ else
+ mem->list = record->next;
+
+ assert(mem->used >= record->size);
+ mem->used -= record->size;
+
+ free(record);
+
+ return;
+}
+
+
+extern LZMA_API void
+lzma_memlimit_free(lzma_memlimit *mem, void *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ lzma_memlimit_detach(mem, ptr);
+
+ free(ptr);
+
+ return;
+}
diff --git a/src/liblzma/common/memory_usage.c b/src/liblzma/common/memory_usage.c
new file mode 100644
index 00000000..b6f27957
--- /dev/null
+++ b/src/liblzma/common/memory_usage.c
@@ -0,0 +1,113 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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_COPY:
+ 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/metadata_decoder.c b/src/liblzma/common/metadata_decoder.c
new file mode 100644
index 00000000..f2ac6c1d
--- /dev/null
+++ b/src/liblzma/common/metadata_decoder.c
@@ -0,0 +1,555 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file metadata_decoder.c
+/// \brief Decodes metadata stored in Metadata Blocks
+//
+// 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 "metadata_decoder.h"
+#include "block_decoder.h"
+
+
+/// Maximum size of a single Extra Record. Again, this is mostly to make
+/// sure that the parsed lzma_vli fits into size_t. Still, maybe this should
+/// be smaller.
+#define EXTRA_SIZE_MAX (SIZE_MAX / 4)
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_FLAGS,
+ SEQ_HEADER_METADATA_SIZE,
+ SEQ_TOTAL_SIZE,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_INDEX_COUNT,
+ SEQ_INDEX_ALLOC,
+ SEQ_INDEX_TOTAL_SIZE,
+ SEQ_INDEX_UNCOMPRESSED_SIZE,
+ SEQ_EXTRA_PREPARE,
+ SEQ_EXTRA_ALLOC,
+ SEQ_EXTRA_ID,
+ SEQ_EXTRA_SIZE,
+ SEQ_EXTRA_DATA_ALLOC,
+ SEQ_EXTRA_DATA_COPY,
+ SEQ_EXTRA_DUMMY_ALLOC,
+ SEQ_EXTRA_DUMMY_ID,
+ SEQ_EXTRA_DUMMY_SIZE,
+ SEQ_EXTRA_DUMMY_COPY,
+ } sequence;
+
+ /// Number of "things" left to be parsed. If we hit end of input
+ /// when this isn't zero, we have corrupt Metadata Block.
+ size_t todo_count;
+
+ /// Position in variable-length integers
+ size_t pos;
+
+ /// Temporary variable needed to decode variables whose type
+ /// is size_t instead of lzma_vli.
+ lzma_vli tmp;
+
+ /// Pointer to target structure to hold the parsed results.
+ lzma_metadata *metadata;
+
+ /// The Index Record we currently are parsing
+ lzma_index *index_current;
+
+ /// Number of Records in Index
+ size_t index_count;
+
+ /// Sum of Total Size fields in the Index
+ lzma_vli index_total_size;
+
+ /// Sum of Uncompressed Size fields in the Index
+ lzma_vli index_uncompressed_size;
+
+ /// True if Extra is present.
+ bool has_extra;
+
+ /// True if we have been requested to store the Extra to *metadata.
+ bool want_extra;
+
+ /// Pointer to the end of the Extra Record list.
+ lzma_extra *extra_tail;
+
+ /// Dummy Extra Record used when only verifying integrity of Extra
+ /// (not storing it to RAM).
+ lzma_extra extra_dummy;
+
+ /// Block decoder
+ lzma_next_coder block_decoder;
+
+ /// buffer[buffer_pos] is the next byte to process.
+ size_t buffer_pos;
+
+ /// buffer[buffer_size] is the first byte to not process.
+ size_t buffer_size;
+
+ /// Temporary buffer to which encoded Metadata is read before
+ /// it is parsed.
+ uint8_t buffer[LZMA_BUFFER_SIZE];
+};
+
+
+/// Reads a variable-length integer to coder->num.
+#define read_vli(num) \
+do { \
+ const lzma_ret ret = lzma_vli_decode( \
+ &num, &coder->pos, \
+ coder->buffer, &coder->buffer_pos, \
+ coder->buffer_size); \
+ if (ret != LZMA_STREAM_END) \
+ return ret; \
+ \
+ coder->pos = 0; \
+} while (0)
+
+
+static lzma_ret
+process(lzma_coder *coder, lzma_allocator *allocator)
+{
+ while (coder->buffer_pos < coder->buffer_size)
+ switch (coder->sequence) {
+ case SEQ_FLAGS:
+ // Reserved bits must be unset.
+ if (coder->buffer[coder->buffer_pos] & 0x70)
+ return LZMA_HEADER_ERROR;
+
+ // If Size of Header Metadata is present, prepare the
+ // variable for variable-length integer decoding. Otherwise
+ // set it to LZMA_VLI_VALUE_UNKNOWN to indicate that the
+ // field isn't present.
+ if (coder->buffer[coder->buffer_pos] & 0x01) {
+ coder->metadata->header_metadata_size = 0;
+ ++coder->todo_count;
+ }
+
+ if (coder->buffer[coder->buffer_pos] & 0x02) {
+ coder->metadata->total_size = 0;
+ ++coder->todo_count;
+ }
+
+ if (coder->buffer[coder->buffer_pos] & 0x04) {
+ coder->metadata->uncompressed_size = 0;
+ ++coder->todo_count;
+ }
+
+ if (coder->buffer[coder->buffer_pos] & 0x08) {
+ // Setting index_count to 1 is just to indicate that
+ // Index is present. The real size is parsed later.
+ coder->index_count = 1;
+ ++coder->todo_count;
+ }
+
+ coder->has_extra = (coder->buffer[coder->buffer_pos] & 0x80)
+ != 0;
+
+ ++coder->buffer_pos;
+ coder->sequence = SEQ_HEADER_METADATA_SIZE;
+ break;
+
+ case SEQ_HEADER_METADATA_SIZE:
+ if (coder->metadata->header_metadata_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ read_vli(coder->metadata->header_metadata_size);
+
+ if (coder->metadata->header_metadata_size == 0)
+ return LZMA_DATA_ERROR;
+
+ --coder->todo_count;
+ }
+
+ coder->sequence = SEQ_TOTAL_SIZE;
+ break;
+
+ case SEQ_TOTAL_SIZE:
+ if (coder->metadata->total_size != LZMA_VLI_VALUE_UNKNOWN) {
+ read_vli(coder->metadata->total_size);
+
+ if (coder->metadata->total_size == 0)
+ return LZMA_DATA_ERROR;
+
+ --coder->todo_count;
+ }
+
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ if (coder->metadata->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ read_vli(coder->metadata->uncompressed_size);
+ --coder->todo_count;
+ }
+
+ coder->sequence = SEQ_INDEX_COUNT;
+ break;
+
+ case SEQ_INDEX_COUNT:
+ if (coder->index_count == 0) {
+ coder->sequence = SEQ_EXTRA_PREPARE;
+ break;
+ }
+
+ read_vli(coder->tmp);
+
+ // Index must not be empty nor far too big (wouldn't fit
+ // in RAM).
+ if (coder->tmp == 0 || coder->tmp
+ >= SIZE_MAX / sizeof(lzma_index))
+ return LZMA_DATA_ERROR;
+
+ coder->index_count = (size_t)(coder->tmp);
+ coder->tmp = 0;
+
+ coder->sequence = SEQ_INDEX_ALLOC;
+ break;
+
+ case SEQ_INDEX_ALLOC: {
+ lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
+ if (i == NULL)
+ return LZMA_MEM_ERROR;
+
+ i->total_size = 0;
+ i->uncompressed_size = 0;
+ i->next = NULL;
+
+ if (coder->metadata->index == NULL)
+ coder->metadata->index = i;
+ else
+ coder->index_current->next = i;
+
+ coder->index_current = i;
+
+ coder->sequence = SEQ_INDEX_TOTAL_SIZE;
+ }
+
+ // Fall through
+
+ case SEQ_INDEX_TOTAL_SIZE: {
+ read_vli(coder->index_current->total_size);
+
+ coder->index_total_size += coder->index_current->total_size;
+ if (coder->index_total_size > LZMA_VLI_VALUE_MAX)
+ return LZMA_DATA_ERROR;
+
+ // No Block can have Total Size of zero bytes.
+ if (coder->index_current->total_size == 0)
+ return LZMA_DATA_ERROR;
+
+ if (--coder->index_count == 0) {
+ // If Total Size is present, it must match the sum
+ // of Total Sizes in Index.
+ if (coder->metadata->total_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && coder->metadata->total_size
+ != coder->index_total_size)
+ return LZMA_DATA_ERROR;
+
+ coder->index_current = coder->metadata->index;
+ coder->sequence = SEQ_INDEX_UNCOMPRESSED_SIZE;
+ } else {
+ coder->sequence = SEQ_INDEX_ALLOC;
+ }
+
+ break;
+ }
+
+ case SEQ_INDEX_UNCOMPRESSED_SIZE: {
+ read_vli(coder->index_current->uncompressed_size);
+
+ coder->index_uncompressed_size
+ += coder->index_current->uncompressed_size;
+ if (coder->index_uncompressed_size > LZMA_VLI_VALUE_MAX)
+ return LZMA_DATA_ERROR;
+
+ coder->index_current = coder->index_current->next;
+ if (coder->index_current == NULL) {
+ if (coder->metadata->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN
+ && coder->metadata->uncompressed_size
+ != coder->index_uncompressed_size)
+ return LZMA_DATA_ERROR;
+
+ --coder->todo_count;
+ coder->sequence = SEQ_EXTRA_PREPARE;
+ }
+
+ break;
+ }
+
+ case SEQ_EXTRA_PREPARE:
+ assert(coder->todo_count == 0);
+
+ // If we get here, we have at least one byte of input left.
+ // If "Extra is present" flag is unset in Metadata Flags,
+ // it means that there is some garbage and we return an error.
+ if (!coder->has_extra)
+ return LZMA_DATA_ERROR;
+
+ if (!coder->want_extra) {
+ coder->extra_tail = &coder->extra_dummy;
+ coder->sequence = SEQ_EXTRA_DUMMY_ALLOC;
+ break;
+ }
+
+ coder->sequence = SEQ_EXTRA_ALLOC;
+
+ // Fall through
+
+ case SEQ_EXTRA_ALLOC: {
+ lzma_extra *e = lzma_alloc(sizeof(lzma_extra), allocator);
+ if (e == NULL)
+ return LZMA_MEM_ERROR;
+
+ e->next = NULL;
+ e->id = 0;
+ e->size = 0;
+ e->data = NULL;
+
+ if (coder->metadata->extra == NULL)
+ coder->metadata->extra = e;
+ else
+ coder->extra_tail->next = e;
+
+ coder->extra_tail = e;
+
+ coder->todo_count = 1;
+ coder->sequence = SEQ_EXTRA_ID;
+ }
+
+ // Fall through
+
+ case SEQ_EXTRA_ID:
+ case SEQ_EXTRA_DUMMY_ID:
+ read_vli(coder->extra_tail->id);
+
+ if (coder->extra_tail->id == 0) {
+ coder->extra_tail->size = 0;
+ coder->extra_tail->data = NULL;
+ coder->todo_count = 0;
+ --coder->sequence;
+ } else {
+ ++coder->sequence;
+ }
+
+ break;
+
+ case SEQ_EXTRA_SIZE:
+ case SEQ_EXTRA_DUMMY_SIZE:
+ read_vli(coder->tmp);
+ ++coder->sequence;
+ break;
+
+ case SEQ_EXTRA_DATA_ALLOC: {
+ if (coder->tmp > EXTRA_SIZE_MAX)
+ return LZMA_DATA_ERROR;
+
+ coder->extra_tail->size = (size_t)(coder->tmp);
+ coder->tmp = 0;
+
+ uint8_t *d = lzma_alloc((size_t)(coder->extra_tail->size),
+ allocator);
+ if (d == NULL)
+ return LZMA_MEM_ERROR;
+
+ coder->extra_tail->data = d;
+ coder->sequence = SEQ_EXTRA_DATA_COPY;
+ }
+
+ // Fall through
+
+ case SEQ_EXTRA_DATA_COPY:
+ bufcpy(coder->buffer, &coder->buffer_pos, coder->buffer_size,
+ coder->extra_tail->data, &coder->pos,
+ (size_t)(coder->extra_tail->size));
+
+ if ((size_t)(coder->extra_tail->size) == coder->pos) {
+ coder->pos = 0;
+ coder->todo_count = 0;
+ coder->sequence = SEQ_EXTRA_ALLOC;
+ }
+
+ break;
+
+ case SEQ_EXTRA_DUMMY_ALLOC:
+ // Not really alloc, just initialize the dummy entry.
+ coder->extra_dummy = (lzma_extra){
+ .next = NULL,
+ .id = 0,
+ .size = 0,
+ .data = NULL,
+ };
+
+ coder->todo_count = 1;
+ coder->sequence = SEQ_EXTRA_DUMMY_ID;
+ break;
+
+ case SEQ_EXTRA_DUMMY_COPY: {
+ // Simply skip as many bytes as indicated by Extra Record Size.
+ // We don't check lzma_extra_size_max because we don't
+ // allocate any memory to hold the data.
+ const size_t in_avail = coder->buffer_size - coder->buffer_pos;
+ const size_t skip = MIN((lzma_vli)(in_avail), coder->tmp);
+ coder->buffer_pos += skip;
+ coder->tmp -= skip;
+
+ if (coder->tmp == 0) {
+ coder->todo_count = 0;
+ coder->sequence = SEQ_EXTRA_DUMMY_ALLOC;
+ }
+
+ break;
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+metadata_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 lzma_attribute((unused)),
+ size_t *restrict out_pos lzma_attribute((unused)),
+ size_t out_size lzma_attribute((unused)),
+ lzma_action action lzma_attribute((unused)))
+{
+ bool end_was_reached = false;
+
+ while (true) {
+ // Fill the buffer if it is empty.
+ if (coder->buffer_pos == coder->buffer_size) {
+ coder->buffer_pos = 0;
+ coder->buffer_size = 0;
+
+ const lzma_ret ret = coder->block_decoder.code(
+ coder->block_decoder.coder, allocator,
+ in, in_pos, in_size, coder->buffer,
+ &coder->buffer_size, LZMA_BUFFER_SIZE,
+ LZMA_RUN);
+
+ switch (ret) {
+ case LZMA_OK:
+ // Return immediatelly if we got no new data.
+ if (coder->buffer_size == 0)
+ return LZMA_OK;
+
+ break;
+
+ case LZMA_STREAM_END:
+ end_was_reached = true;
+ break;
+
+ default:
+ return ret;
+ }
+ }
+
+ // Process coder->buffer.
+ const lzma_ret ret = process(coder, allocator);
+ if (ret != LZMA_OK)
+ return ret;
+
+ // On success, process() eats all the input.
+ assert(coder->buffer_pos == coder->buffer_size);
+
+ if (end_was_reached) {
+ // Check that the sequence is not in the
+ // middle of anything.
+ if (coder->todo_count != 0)
+ return LZMA_DATA_ERROR;
+
+ return LZMA_STREAM_END;
+ }
+ }
+}
+
+
+static void
+metadata_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+metadata_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options, lzma_metadata *metadata,
+ bool want_extra)
+{
+ if (options == NULL || metadata == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &metadata_decode;
+ next->end = &metadata_decoder_end;
+ next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
+ }
+
+ metadata->header_metadata_size = LZMA_VLI_VALUE_UNKNOWN;
+ metadata->total_size = LZMA_VLI_VALUE_UNKNOWN;
+ metadata->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+ metadata->index = NULL;
+ metadata->extra = NULL;
+
+ next->coder->sequence = SEQ_FLAGS;
+ next->coder->todo_count = 0;
+ next->coder->pos = 0;
+ next->coder->tmp = 0;
+ next->coder->metadata = metadata;
+ next->coder->index_current = NULL;
+ next->coder->index_count = 0;
+ next->coder->index_total_size = 0;
+ next->coder->index_uncompressed_size = 0;
+ next->coder->want_extra = want_extra;
+ next->coder->extra_tail = NULL;
+ next->coder->buffer_pos = 0;
+ next->coder->buffer_size = 0;
+
+ return lzma_block_decoder_init(
+ &next->coder->block_decoder, allocator, options);
+}
+
+
+extern lzma_ret
+lzma_metadata_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options, lzma_metadata *metadata,
+ bool want_extra)
+{
+ lzma_next_coder_init(metadata_decoder_init, next, allocator,
+ options, metadata, want_extra);
+}
+
+
+extern LZMA_API lzma_ret
+lzma_metadata_decoder(lzma_stream *strm, lzma_options_block *options,
+ lzma_metadata *metadata, lzma_bool want_extra)
+{
+ lzma_next_strm_init(strm, lzma_metadata_decoder_init,
+ options, metadata, want_extra);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/metadata_decoder.h b/src/liblzma/common/metadata_decoder.h
new file mode 100644
index 00000000..1fba2179
--- /dev/null
+++ b/src/liblzma/common/metadata_decoder.h
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file metadata_decoder.h
+/// \brief Decodes metadata stored in Metadata Blocks
+//
+// 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_METADATA_DECODER_H
+#define LZMA_METADATA_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_metadata_decoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options, lzma_metadata *metadata,
+ bool want_extra);
+
+#endif
diff --git a/src/liblzma/common/metadata_encoder.c b/src/liblzma/common/metadata_encoder.c
new file mode 100644
index 00000000..17587c5c
--- /dev/null
+++ b/src/liblzma/common/metadata_encoder.c
@@ -0,0 +1,436 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file metadata_encoder.c
+/// \brief Encodes metadata to be stored into Metadata Blocks
+//
+// 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 "metadata_encoder.h"
+#include "block_encoder.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_FLAGS,
+ SEQ_HEADER_METADATA_SIZE,
+ SEQ_TOTAL_SIZE,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_INDEX_COUNT,
+ SEQ_INDEX_TOTAL,
+ SEQ_INDEX_UNCOMPRESSED,
+ SEQ_EXTRA_ID,
+ SEQ_EXTRA_SIZE,
+ SEQ_EXTRA_DATA,
+ SEQ_END,
+ } sequence;
+
+ /// Position in variable-length integers
+ size_t pos;
+
+ /// Local copy of the Metadata structure. Note that we keep
+ /// a copy only of the main structure, not Index or Extra Records.
+ lzma_metadata metadata;
+
+ /// Number of Records in Index
+ size_t index_count;
+
+ /// Index Record currently being processed
+ const lzma_index *index_current;
+
+ /// Block encoder for the encoded Metadata
+ lzma_next_coder block_encoder;
+
+ /// True once everything except compression has been done.
+ bool end_was_reached;
+
+ /// buffer[buffer_pos] is the first byte that needs to be compressed.
+ size_t buffer_pos;
+
+ /// buffer[buffer_size] is the next position where a byte will be
+ /// written by process().
+ size_t buffer_size;
+
+ /// Temporary buffer to which encoded Metadata is written before
+ /// it is compressed.
+ uint8_t buffer[LZMA_BUFFER_SIZE];
+};
+
+
+#define write_vli(num) \
+do { \
+ const lzma_ret ret = lzma_vli_encode(num, &coder->pos, 1, \
+ coder->buffer, &coder->buffer_size, \
+ LZMA_BUFFER_SIZE); \
+ if (ret != LZMA_STREAM_END) \
+ return ret; \
+ coder->pos = 0; \
+} while (0)
+
+
+static lzma_ret
+process(lzma_coder *coder)
+{
+ while (coder->buffer_size < LZMA_BUFFER_SIZE)
+ switch (coder->sequence) {
+ case SEQ_FLAGS:
+ coder->buffer[coder->buffer_size] = 0;
+
+ if (coder->metadata.header_metadata_size
+ != LZMA_VLI_VALUE_UNKNOWN)
+ coder->buffer[coder->buffer_size] |= 0x01;
+
+ if (coder->metadata.total_size != LZMA_VLI_VALUE_UNKNOWN)
+ coder->buffer[coder->buffer_size] |= 0x02;
+
+ if (coder->metadata.uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN)
+ coder->buffer[coder->buffer_size] |= 0x04;
+
+ if (coder->index_count > 0)
+ coder->buffer[coder->buffer_size] |= 0x08;
+
+ if (coder->metadata.extra != NULL)
+ coder->buffer[coder->buffer_size] |= 0x80;
+
+ ++coder->buffer_size;
+ coder->sequence = SEQ_HEADER_METADATA_SIZE;
+ break;
+
+ case SEQ_HEADER_METADATA_SIZE:
+ if (coder->metadata.header_metadata_size
+ != LZMA_VLI_VALUE_UNKNOWN)
+ write_vli(coder->metadata.header_metadata_size);
+
+ coder->sequence = SEQ_TOTAL_SIZE;
+ break;
+
+ case SEQ_TOTAL_SIZE:
+ if (coder->metadata.total_size != LZMA_VLI_VALUE_UNKNOWN)
+ write_vli(coder->metadata.total_size);
+
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ if (coder->metadata.uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN)
+ write_vli(coder->metadata.uncompressed_size);
+
+ coder->sequence = SEQ_INDEX_COUNT;
+ break;
+
+ case SEQ_INDEX_COUNT:
+ if (coder->index_count == 0) {
+ if (coder->metadata.extra == NULL) {
+ coder->sequence = SEQ_END;
+ return LZMA_STREAM_END;
+ }
+
+ coder->sequence = SEQ_EXTRA_ID;
+ break;
+ }
+
+ write_vli(coder->index_count);
+ coder->sequence = SEQ_INDEX_TOTAL;
+ break;
+
+ case SEQ_INDEX_TOTAL:
+ write_vli(coder->index_current->total_size);
+
+ coder->index_current = coder->index_current->next;
+ if (coder->index_current == NULL) {
+ coder->index_current = coder->metadata.index;
+ coder->sequence = SEQ_INDEX_UNCOMPRESSED;
+ }
+
+ break;
+
+ case SEQ_INDEX_UNCOMPRESSED:
+ write_vli(coder->index_current->uncompressed_size);
+
+ coder->index_current = coder->index_current->next;
+ if (coder->index_current != NULL)
+ break;
+
+ if (coder->metadata.extra != NULL) {
+ coder->sequence = SEQ_EXTRA_ID;
+ break;
+ }
+
+ coder->sequence = SEQ_END;
+ return LZMA_STREAM_END;
+
+ case SEQ_EXTRA_ID: {
+ const lzma_ret ret = lzma_vli_encode(
+ coder->metadata.extra->id, &coder->pos, 1,
+ coder->buffer, &coder->buffer_size,
+ LZMA_BUFFER_SIZE);
+ switch (ret) {
+ case LZMA_OK:
+ break;
+
+ case LZMA_STREAM_END:
+ coder->pos = 0;
+
+ // Handle the special ID 0.
+ if (coder->metadata.extra->id == 0) {
+ coder->metadata.extra
+ = coder->metadata.extra->next;
+ if (coder->metadata.extra == NULL) {
+ coder->sequence = SEQ_END;
+ return LZMA_STREAM_END;
+ }
+
+ coder->sequence = SEQ_EXTRA_ID;
+
+ } else {
+ coder->sequence = SEQ_EXTRA_SIZE;
+ }
+
+ break;
+
+ default:
+ return ret;
+ }
+
+ break;
+ }
+
+ case SEQ_EXTRA_SIZE:
+ if (coder->metadata.extra->size >= (lzma_vli)(SIZE_MAX))
+ return LZMA_HEADER_ERROR;
+
+ write_vli(coder->metadata.extra->size);
+ coder->sequence = SEQ_EXTRA_DATA;
+ break;
+
+ case SEQ_EXTRA_DATA:
+ bufcpy(coder->metadata.extra->data, &coder->pos,
+ coder->metadata.extra->size,
+ coder->buffer, &coder->buffer_size,
+ LZMA_BUFFER_SIZE);
+
+ if ((size_t)(coder->metadata.extra->size) == coder->pos) {
+ coder->metadata.extra = coder->metadata.extra->next;
+ if (coder->metadata.extra == NULL) {
+ coder->sequence = SEQ_END;
+ return LZMA_STREAM_END;
+ }
+
+ coder->pos = 0;
+ coder->sequence = SEQ_EXTRA_ID;
+ }
+
+ break;
+
+ case SEQ_END:
+ // Everything is encoded. Let the compression code finish
+ // its work now.
+ return LZMA_STREAM_END;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+metadata_encode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *restrict in lzma_attribute((unused)),
+ size_t *restrict in_pos lzma_attribute((unused)),
+ size_t in_size lzma_attribute((unused)), uint8_t *restrict out,
+ size_t *restrict out_pos, size_t out_size,
+ lzma_action action lzma_attribute((unused)))
+{
+ while (!coder->end_was_reached) {
+ // Flush coder->buffer if it isn't empty.
+ if (coder->buffer_size > 0) {
+ const lzma_ret ret = coder->block_encoder.code(
+ coder->block_encoder.coder, allocator,
+ coder->buffer, &coder->buffer_pos,
+ coder->buffer_size,
+ out, out_pos, out_size, LZMA_RUN);
+ if (coder->buffer_pos < coder->buffer_size
+ || ret != LZMA_OK)
+ return ret;
+
+ coder->buffer_pos = 0;
+ coder->buffer_size = 0;
+ }
+
+ const lzma_ret ret = process(coder);
+
+ switch (ret) {
+ case LZMA_OK:
+ break;
+
+ case LZMA_STREAM_END:
+ coder->end_was_reached = true;
+ break;
+
+ default:
+ return ret;
+ }
+ }
+
+ // Finish
+ return coder->block_encoder.code(coder->block_encoder.coder, allocator,
+ coder->buffer, &coder->buffer_pos, coder->buffer_size,
+ out, out_pos, out_size, LZMA_FINISH);
+}
+
+
+static void
+metadata_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->block_encoder, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+metadata_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options, const lzma_metadata *metadata)
+{
+ if (options == NULL || metadata == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &metadata_encode;
+ next->end = &metadata_encoder_end;
+ next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
+ }
+
+ next->coder->sequence = SEQ_FLAGS;
+ next->coder->pos = 0;
+ next->coder->metadata = *metadata;
+ next->coder->index_count = 0;
+ next->coder->index_current = metadata->index;
+ next->coder->end_was_reached = false;
+ next->coder->buffer_pos = 0;
+ next->coder->buffer_size = 0;
+
+ // Count and validate the Index Records.
+ {
+ const lzma_index *i = metadata->index;
+ while (i != NULL) {
+ if (i->total_size > LZMA_VLI_VALUE_MAX
+ || i->uncompressed_size
+ > LZMA_VLI_VALUE_MAX)
+ return LZMA_PROG_ERROR;
+
+ ++next->coder->index_count;
+ i = i->next;
+ }
+ }
+
+ // Initialize the Block encoder.
+ return lzma_block_encoder_init(
+ &next->coder->block_encoder, allocator, options);
+}
+
+
+extern lzma_ret
+lzma_metadata_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options, const lzma_metadata *metadata)
+{
+ lzma_next_coder_init(metadata_encoder_init, next, allocator,
+ options, metadata);
+}
+
+
+extern LZMA_API lzma_ret
+lzma_metadata_encoder(lzma_stream *strm, lzma_options_block *options,
+ const lzma_metadata *metadata)
+{
+ lzma_next_strm_init(strm, metadata_encoder_init, options, metadata);
+
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_vli
+lzma_metadata_size(const lzma_metadata *metadata)
+{
+ lzma_vli size = 1; // Metadata Flags
+
+ // Validate header_metadata_size, total_size, and uncompressed_size.
+ if (!lzma_vli_is_valid(metadata->header_metadata_size)
+ || !lzma_vli_is_valid(metadata->total_size)
+ || !lzma_vli_is_valid(metadata->uncompressed_size))
+ return 0;
+
+ // Add the sizes of these three fields.
+ if (metadata->header_metadata_size != LZMA_VLI_VALUE_UNKNOWN)
+ size += lzma_vli_size(metadata->header_metadata_size);
+
+ if (metadata->total_size != LZMA_VLI_VALUE_UNKNOWN)
+ size += lzma_vli_size(metadata->total_size);
+
+ if (metadata->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
+ size += lzma_vli_size(metadata->uncompressed_size);
+
+ // Index
+ if (metadata->index != NULL) {
+ const lzma_index *i = metadata->index;
+ size_t count = 1;
+
+ do {
+ const size_t x = lzma_vli_size(i->total_size);
+ const size_t y = lzma_vli_size(i->uncompressed_size);
+ if (x == 0 || y == 0)
+ return 0;
+
+ size += x + y;
+ ++count;
+ i = i->next;
+
+ } while (i != NULL);
+
+ const size_t tmp = lzma_vli_size(count);
+ if (tmp == 0)
+ return 0;
+
+ size += tmp;
+ }
+
+ // Extra
+ {
+ const lzma_extra *e = metadata->extra;
+ while (e != NULL) {
+ // Validate the numbers.
+ if (e->id > LZMA_VLI_VALUE_MAX
+ || e->size >= (lzma_vli)(SIZE_MAX))
+ return 0;
+
+ // Add the sizes.
+ size += lzma_vli_size(e->id);
+ if (e->id != 0) {
+ size += lzma_vli_size(e->size);
+ size += e->size;
+ }
+
+ e = e->next;
+ }
+ }
+
+ return size;
+}
diff --git a/src/liblzma/common/metadata_encoder.h b/src/liblzma/common/metadata_encoder.h
new file mode 100644
index 00000000..20357fe6
--- /dev/null
+++ b/src/liblzma/common/metadata_encoder.h
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file metadata_encoder.h
+/// \brief Encodes metadata to be stored into Metadata Blocks
+//
+// 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_METADATA_ENCODER_H
+#define LZMA_METADATA_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_metadata_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_options_block *options, const lzma_metadata *metadata);
+
+#endif
diff --git a/src/liblzma/common/next_coder.c b/src/liblzma/common/next_coder.c
new file mode 100644
index 00000000..c10fe24d
--- /dev/null
+++ b/src/liblzma/common/next_coder.c
@@ -0,0 +1,65 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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
new file mode 100644
index 00000000..394903bc
--- /dev/null
+++ b/src/liblzma/common/raw_common.c
@@ -0,0 +1,175 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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"
+
+
+/// \brief Prepares the filter chain
+///
+/// Prepares the filter chain by setting uncompressed sizes for each filter,
+/// and adding implicit Subblock filter when needed.
+///
+/// \return true if error occurred, false on success.
+///
+static bool
+prepare(lzma_vli *id, lzma_vli *uncompressed_size, bool implicit)
+{
+ bool needs_end_of_input = false;
+
+ switch (id[0]) {
+ case LZMA_FILTER_COPY:
+ 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:
+ uncompressed_size[1] = uncompressed_size[0];
+ needs_end_of_input = true;
+ break;
+
+ case LZMA_FILTER_SUBBLOCK:
+ case LZMA_FILTER_LZMA:
+ // These change the size of the data unpredictably.
+ uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
+ break;
+
+ case LZMA_FILTER_SUBBLOCK_HELPER:
+ uncompressed_size[1] = uncompressed_size[0];
+ break;
+
+ default:
+ // Unknown filter.
+ return true;
+ }
+
+ // Is this the last filter in the chain?
+ if (id[1] == LZMA_VLI_VALUE_UNKNOWN) {
+ if (!needs_end_of_input || !implicit || uncompressed_size[0]
+ != LZMA_VLI_VALUE_UNKNOWN)
+ return false;
+
+ // Add implicit Subblock filter.
+ id[1] = LZMA_FILTER_SUBBLOCK;
+ uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
+ id[2] = LZMA_VLI_VALUE_UNKNOWN;
+ }
+
+ return prepare(id + 1, uncompressed_size + 1, implicit);
+}
+
+
+extern lzma_ret
+lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_options_filter *options, lzma_vli uncompressed_size,
+ lzma_init_function (*get_function)(lzma_vli id),
+ bool allow_implicit, bool is_encoder)
+{
+ if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
+ return LZMA_PROG_ERROR;
+
+ // Count the number of filters in the chain.
+ size_t count = 0;
+ while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
+ ++count;
+
+ // Allocate enough space from the stack for IDs and uncompressed
+ // sizes. We need two extra: possible implicit Subblock and end
+ // of array indicator.
+ lzma_vli ids[count + 2];
+ lzma_vli uncompressed_sizes[count + 2];
+ bool using_implicit = false;
+
+ uncompressed_sizes[0] = uncompressed_size;
+
+ if (count == 0) {
+ if (!allow_implicit)
+ return LZMA_PROG_ERROR;
+
+ count = 1;
+ using_implicit = true;
+
+ // Special case: no filters were specified, so an implicit
+ // Copy or Subblock filter is used.
+ if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
+ ids[0] = LZMA_FILTER_SUBBLOCK;
+ else
+ ids[0] = LZMA_FILTER_COPY;
+
+ ids[1] = LZMA_VLI_VALUE_UNKNOWN;
+
+ } else {
+ // Prepare the ids[] and uncompressed_sizes[].
+ for (size_t i = 0; i < count; ++i)
+ ids[i] = options[i].id;
+
+ ids[count] = LZMA_VLI_VALUE_UNKNOWN;
+
+ if (prepare(ids, uncompressed_sizes, allow_implicit))
+ return LZMA_HEADER_ERROR;
+
+ // Check if implicit Subblock filter was added.
+ if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
+ assert(ids[count] == LZMA_FILTER_SUBBLOCK);
+ ++count;
+ using_implicit = true;
+ }
+ }
+
+ // Set the filter functions, and copy uncompressed sizes and options.
+ 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(ids[i]);
+ if (filters[j].init == NULL)
+ return LZMA_HEADER_ERROR;
+
+ filters[j].options = options[i].options;
+ filters[j].uncompressed_size = uncompressed_sizes[i];
+ }
+
+ if (using_implicit)
+ filters[0].options = NULL;
+
+ } else {
+ for (size_t i = 0; i < count; ++i) {
+ filters[i].init = get_function(ids[i]);
+ if (filters[i].init == NULL)
+ return LZMA_HEADER_ERROR;
+
+ filters[i].options = options[i].options;
+ filters[i].uncompressed_size = uncompressed_sizes[i];
+ }
+
+ if (using_implicit)
+ filters[count - 1].options = NULL;
+ }
+
+ // 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_common.h b/src/liblzma/common/raw_common.h
new file mode 100644
index 00000000..172223cb
--- /dev/null
+++ b/src/liblzma/common/raw_common.h
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file raw_common.h
+/// \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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RAW_COMMON_H
+#define LZMA_RAW_COMMON_H
+
+#include "common.h"
+
+extern lzma_ret lzma_raw_coder_init(lzma_next_coder *next,
+ lzma_allocator *allocator,
+ const lzma_options_filter *options, lzma_vli uncompressed_size,
+ lzma_init_function (*get_function)(lzma_vli id),
+ bool allow_implicit, bool is_encoder);
+
+#endif
diff --git a/src/liblzma/common/raw_decoder.c b/src/liblzma/common/raw_decoder.c
new file mode 100644
index 00000000..a11cb5c4
--- /dev/null
+++ b/src/liblzma/common/raw_decoder.c
@@ -0,0 +1,127 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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 "copy_coder.h"
+#include "simple_coder.h"
+#include "subblock_decoder.h"
+#include "subblock_decoder_helper.h"
+#include "delta_coder.h"
+#include "lzma_decoder.h"
+#include "metadata_decoder.h"
+
+
+static lzma_init_function
+get_function(lzma_vli id)
+{
+ switch (id) {
+#ifdef HAVE_FILTER_COPY
+ case LZMA_FILTER_COPY:
+ return &lzma_copy_decoder_init;
+#endif
+
+#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,
+ lzma_vli uncompressed_size, bool allow_implicit)
+{
+ const lzma_ret ret = lzma_raw_coder_init(next, allocator,
+ options, uncompressed_size, &get_function,
+ allow_implicit, 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,
+ lzma_vli uncompressed_size, lzma_bool allow_implicit)
+{
+ 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, uncompressed_size,
+ &get_function, allow_implicit, 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
new file mode 100644
index 00000000..9d48074b
--- /dev/null
+++ b/src/liblzma/common/raw_decoder.h
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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,
+ lzma_vli uncompressed_size, bool implicit);
+
+#endif
diff --git a/src/liblzma/common/raw_encoder.c b/src/liblzma/common/raw_encoder.c
new file mode 100644
index 00000000..c2cd0a51
--- /dev/null
+++ b/src/liblzma/common/raw_encoder.c
@@ -0,0 +1,124 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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 "copy_coder.h"
+#include "simple_coder.h"
+#include "subblock_encoder.h"
+#include "delta_coder.h"
+#include "lzma_encoder.h"
+
+
+static lzma_init_function
+get_function(lzma_vli id)
+{
+ switch (id) {
+#ifdef HAVE_FILTER_COPY
+ case LZMA_FILTER_COPY:
+ return &lzma_copy_encoder_init;
+#endif
+
+#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,
+ lzma_vli uncompressed_size, bool allow_implicit)
+{
+ // lzma_raw_coder_init() accesses get_function() via function pointer,
+ // because this way linker doesn't statically link both encoder and
+ // decoder functions if user needs only encoder or decoder.
+ const lzma_ret ret = lzma_raw_coder_init(next, allocator,
+ options, uncompressed_size, &get_function,
+ allow_implicit, 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,
+ lzma_vli uncompressed_size, lzma_bool allow_implicit)
+{
+ 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, uncompressed_size,
+ &get_function, allow_implicit, 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
new file mode 100644
index 00000000..b0aab61a
--- /dev/null
+++ b/src/liblzma/common/raw_encoder.h
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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,
+ lzma_vli uncompressed_size, bool allow_implicit);
+
+#endif
diff --git a/src/liblzma/common/stream_common.c b/src/liblzma/common/stream_common.c
new file mode 100644
index 00000000..121a6674
--- /dev/null
+++ b/src/liblzma/common/stream_common.c
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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_common.h b/src/liblzma/common/stream_common.h
new file mode 100644
index 00000000..b2f37f37
--- /dev/null
+++ b/src/liblzma/common/stream_common.h
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_common.h
+/// \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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_STREAM_COMMON_H
+#define LZMA_STREAM_COMMON_H
+
+#include "common.h"
+
+extern const uint8_t lzma_header_magic[6];
+extern const uint8_t lzma_footer_magic[2];
+
+#endif
diff --git a/src/liblzma/common/stream_decoder.c b/src/liblzma/common/stream_decoder.c
new file mode 100644
index 00000000..d8000c3d
--- /dev/null
+++ b/src/liblzma/common/stream_decoder.c
@@ -0,0 +1,454 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_decoder.c
+/// \brief Decodes .lzma Streams
+//
+// 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"
+#include "check.h"
+#include "stream_flags_decoder.h"
+#include "block_decoder.h"
+#include "metadata_decoder.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_STREAM_HEADER_CODE,
+ SEQ_BLOCK_HEADER_INIT,
+ SEQ_BLOCK_HEADER_CODE,
+ SEQ_METADATA_CODE,
+ SEQ_DATA_CODE,
+ SEQ_STREAM_TAIL_INIT,
+ SEQ_STREAM_TAIL_CODE,
+ } sequence;
+
+ /// Position in variable-length integers and in some other things.
+ size_t pos;
+
+ /// Block or Metadata decoder. This takes little memory and the same
+ /// data structure can be used to decode every Block Header, so it's
+ /// a good idea to have a separate lzma_next_coder structure for it.
+ lzma_next_coder block_decoder;
+
+ /// Block Header decoder; this is separate
+ lzma_next_coder block_header_decoder;
+
+ lzma_options_block block_options;
+
+ /// Information about the sizes of the Blocks
+ lzma_info *info;
+
+ /// Current Block in *info
+ lzma_info_iter iter;
+
+ /// Number of bytes not yet processed from Data Blocks in the Stream.
+ /// This can be LZMA_VLI_VALUE_UNKNOWN. If it is known, it is
+ /// decremented while decoding and verified to match the reality.
+ lzma_vli total_left;
+
+ /// Like uncompressed_left above but for uncompressed data from
+ /// Data Blocks.
+ lzma_vli uncompressed_left;
+
+ /// Stream Flags from Stream Header
+ lzma_stream_flags header_flags;
+
+ /// Stream Flags from Stream tail
+ lzma_stream_flags tail_flags;
+
+ /// Decoder for Stream Header and Stream tail. This takes very
+ /// little memory and the same data structure can be used for
+ /// both Header and tail, so it's a good idea to have a separate
+ /// lzma_next_coder structure for it.
+ lzma_next_coder flags_decoder;
+
+ /// Temporary destination for the decoded Metadata.
+ lzma_metadata metadata;
+
+ /// Pointer to application-supplied pointer where to store the list
+ /// of Extra Records from the Header Metadata Block.
+ lzma_extra **header_extra;
+
+ /// Same as above but Footer Metadata Block
+ lzma_extra **footer_extra;
+};
+
+
+static lzma_ret
+metadata_init(lzma_coder *coder, lzma_allocator *allocator)
+{
+ assert(coder->metadata.index == NULL);
+ assert(coder->metadata.extra == NULL);
+
+ // Single-Block Streams don't have Metadata Blocks.
+ if (!coder->header_flags.is_multi)
+ return LZMA_DATA_ERROR;
+
+ coder->block_options.total_limit = LZMA_VLI_VALUE_UNKNOWN;
+
+ // Limit the Uncompressed Size of a Metadata Block. This is to
+ // prevent security issues where input file would have very huge
+ // Metadata.
+ //
+ // FIXME: Hardcoded constant is ugly. Maybe we should provide
+ // some way to specify this from the application.
+ coder->block_options.uncompressed_limit = LZMA_VLI_C(1) << 23;
+
+ lzma_info_size size_type;
+ bool want_extra;
+
+ // If we haven't decoded any Data Blocks yet, this is Header
+ // Metadata Block.
+ if (lzma_info_index_count_get(coder->info) == 0) {
+ coder->block_options.has_backward_size = false;
+ coder->block_options.handle_padding = true;
+ size_type = LZMA_INFO_HEADER_METADATA;
+ want_extra = coder->header_extra != NULL;
+ } else {
+ if (lzma_info_index_finish(coder->info))
+ return LZMA_DATA_ERROR;
+
+ coder->block_options.has_backward_size = true;
+ coder->block_options.handle_padding = false;
+ size_type = LZMA_INFO_FOOTER_METADATA;
+ want_extra = coder->footer_extra != NULL;
+ }
+
+ coder->block_options.has_uncompressed_size_in_footer = false;
+ coder->block_options.total_size = lzma_info_size_get(
+ coder->info, size_type);
+
+ coder->sequence = SEQ_METADATA_CODE;
+
+ return lzma_metadata_decoder_init(&coder->block_decoder, allocator,
+ &coder->block_options, &coder->metadata, want_extra);
+}
+
+
+static lzma_ret
+data_init(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_ret ret = lzma_info_iter_next(&coder->iter, allocator);
+ if (ret != LZMA_OK)
+ return ret;
+
+ ret = lzma_info_iter_set(&coder->iter, LZMA_VLI_VALUE_UNKNOWN,
+ coder->block_options.uncompressed_size);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->block_options.total_size = coder->iter.total_size;
+ coder->block_options.uncompressed_size = coder->iter.uncompressed_size;
+ coder->block_options.total_limit = coder->total_left;
+ coder->block_options.uncompressed_limit = coder->uncompressed_left;
+
+ if (coder->header_flags.is_multi) {
+ coder->block_options.has_uncompressed_size_in_footer = false;
+ coder->block_options.has_backward_size = false;
+ coder->block_options.handle_padding = true;
+ } else {
+ coder->block_options.has_uncompressed_size_in_footer
+ = coder->iter.uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN;
+ coder->block_options.has_backward_size = true;
+ coder->block_options.handle_padding = false;
+ }
+
+ coder->sequence = SEQ_DATA_CODE;
+
+ return lzma_block_decoder_init(&coder->block_decoder, allocator,
+ &coder->block_options);
+}
+
+
+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,
+ size_t *restrict out_pos, size_t out_size, lzma_action action)
+{
+ while (*out_pos < out_size && (*in_pos < in_size
+ || coder->sequence == SEQ_DATA_CODE))
+ switch (coder->sequence) {
+ case SEQ_STREAM_HEADER_CODE: {
+ const lzma_ret ret = coder->flags_decoder.code(
+ coder->flags_decoder.coder,
+ allocator, in, in_pos, in_size,
+ NULL, NULL, 0, LZMA_RUN);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ coder->sequence = SEQ_BLOCK_HEADER_INIT;
+
+ // 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.
+ lzma_check tmp;
+ if (lzma_check_init(&tmp, coder->header_flags.check))
+ return LZMA_UNSUPPORTED_CHECK;
+
+ break;
+ }
+
+ case SEQ_BLOCK_HEADER_INIT: {
+ coder->block_options.check = coder->header_flags.check;
+ coder->block_options.has_crc32 = coder->header_flags.has_crc32;
+
+ const lzma_ret ret = lzma_block_header_decoder_init(
+ &coder->block_header_decoder, allocator,
+ &coder->block_options);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_BLOCK_HEADER_CODE;
+ }
+
+ // Fall through
+
+ case SEQ_BLOCK_HEADER_CODE: {
+ lzma_ret ret = coder->block_header_decoder.code(
+ coder->block_header_decoder.coder,
+ allocator, in, in_pos, in_size,
+ NULL, NULL, 0, LZMA_RUN);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (coder->block_options.is_metadata)
+ ret = metadata_init(coder, allocator);
+ else
+ ret = data_init(coder, allocator);
+
+ if (ret != LZMA_OK)
+ return ret;
+
+ break;
+ }
+
+ case SEQ_METADATA_CODE: {
+ lzma_ret ret = coder->block_decoder.code(
+ coder->block_decoder.coder, allocator,
+ in, in_pos, in_size, NULL, NULL, 0, LZMA_RUN);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ const bool is_header_metadata = lzma_info_index_count_get(
+ coder->info) == 0;
+
+ if (is_header_metadata) {
+ if (coder->header_extra != NULL) {
+ *coder->header_extra = coder->metadata.extra;
+ coder->metadata.extra = NULL;
+ }
+
+ if (lzma_info_size_set(coder->info,
+ LZMA_INFO_HEADER_METADATA,
+ coder->block_options.total_size)
+ != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ coder->sequence = SEQ_BLOCK_HEADER_INIT;
+ } else {
+ if (coder->footer_extra != NULL) {
+ *coder->footer_extra = coder->metadata.extra;
+ coder->metadata.extra = NULL;
+ }
+
+ coder->sequence = SEQ_STREAM_TAIL_INIT;
+ }
+
+ assert(coder->metadata.extra == NULL);
+
+ ret = lzma_info_metadata_set(coder->info, allocator,
+ &coder->metadata, is_header_metadata, true);
+ if (ret != LZMA_OK)
+ return ret;
+
+ // Intialize coder->total_size and coder->uncompressed_size
+ // from Header Metadata.
+ if (is_header_metadata) {
+ coder->total_left = lzma_info_size_get(
+ coder->info, LZMA_INFO_TOTAL);
+ coder->uncompressed_left = lzma_info_size_get(
+ coder->info, LZMA_INFO_UNCOMPRESSED);
+ }
+
+ break;
+ }
+
+ case SEQ_DATA_CODE: {
+ lzma_ret ret = coder->block_decoder.code(
+ coder->block_decoder.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ action);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ ret = lzma_info_iter_set(&coder->iter,
+ coder->block_options.total_size,
+ coder->block_options.uncompressed_size);
+ if (ret != LZMA_OK)
+ return ret;
+
+ // These won't overflow since lzma_info_iter_set() succeeded.
+ if (coder->total_left != LZMA_VLI_VALUE_UNKNOWN)
+ coder->total_left -= coder->block_options.total_size;
+ if (coder->uncompressed_left != LZMA_VLI_VALUE_UNKNOWN)
+ coder->uncompressed_left -= coder->block_options
+ .uncompressed_size;
+
+ if (!coder->header_flags.is_multi) {
+ ret = lzma_info_index_finish(coder->info);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_STREAM_TAIL_INIT;
+ break;
+ }
+
+ coder->sequence = SEQ_BLOCK_HEADER_INIT;
+ break;
+ }
+
+ case SEQ_STREAM_TAIL_INIT: {
+ lzma_ret ret = lzma_info_index_finish(coder->info);
+ if (ret != LZMA_OK)
+ return ret;
+
+ ret = lzma_stream_tail_decoder_init(&coder->flags_decoder,
+ allocator, &coder->tail_flags);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_STREAM_TAIL_CODE;
+ }
+
+ // Fall through
+
+ case SEQ_STREAM_TAIL_CODE: {
+ const lzma_ret ret = coder->flags_decoder.code(
+ coder->flags_decoder.coder, allocator,
+ in, in_pos, in_size, NULL, NULL, 0, LZMA_RUN);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ if (!lzma_stream_flags_is_equal(
+ coder->header_flags, coder->tail_flags))
+ return LZMA_DATA_ERROR;
+
+ return LZMA_STREAM_END;
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->block_decoder, allocator);
+ lzma_next_coder_end(&coder->block_header_decoder, allocator);
+ lzma_next_coder_end(&coder->flags_decoder, allocator);
+ lzma_info_free(coder->info, allocator);
+ lzma_index_free(coder->metadata.index, allocator);
+ lzma_extra_free(coder->metadata.extra, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_extra **header, lzma_extra **footer)
+{
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &stream_decode;
+ next->end = &stream_decoder_end;
+
+ next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
+ next->coder->block_header_decoder = LZMA_NEXT_CODER_INIT;
+ next->coder->info = NULL;
+ next->coder->flags_decoder = LZMA_NEXT_CODER_INIT;
+ next->coder->metadata.index = NULL;
+ next->coder->metadata.extra = NULL;
+ } else {
+ lzma_index_free(next->coder->metadata.index, allocator);
+ next->coder->metadata.index = NULL;
+
+ lzma_extra_free(next->coder->metadata.extra, allocator);
+ next->coder->metadata.extra = NULL;
+ }
+
+ next->coder->info = lzma_info_init(next->coder->info, allocator);
+ if (next->coder->info == NULL)
+ return LZMA_MEM_ERROR;
+
+ lzma_info_iter_begin(next->coder->info, &next->coder->iter);
+
+ // Initialize Stream Header decoder.
+ return_if_error(lzma_stream_header_decoder_init(
+ &next->coder->flags_decoder, allocator,
+ &next->coder->header_flags));
+
+ // Reset the *foo_extra pointers to NULL. This way the caller knows
+ // if there were no Extra Records. (We don't support appending
+ // Records to Extra list.)
+ if (header != NULL)
+ *header = NULL;
+ if (footer != NULL)
+ *footer = NULL;
+
+ // Reset some variables.
+ next->coder->sequence = SEQ_STREAM_HEADER_CODE;
+ next->coder->pos = 0;
+ next->coder->uncompressed_left = LZMA_VLI_VALUE_UNKNOWN;
+ next->coder->total_left = LZMA_VLI_VALUE_UNKNOWN;
+ next->coder->header_extra = header;
+ next->coder->footer_extra = footer;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_extra **header, lzma_extra **footer)
+{
+ lzma_next_coder_init(
+ stream_decoder_init, next, allocator, header, footer);
+}
+
+
+extern LZMA_API lzma_ret
+lzma_stream_decoder(lzma_stream *strm,
+ lzma_extra **header, lzma_extra **footer)
+{
+ lzma_next_strm_init(strm, stream_decoder_init, header, footer);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/stream_encoder_multi.c b/src/liblzma/common/stream_encoder_multi.c
new file mode 100644
index 00000000..5955f858
--- /dev/null
+++ b/src/liblzma/common/stream_encoder_multi.c
@@ -0,0 +1,460 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_encoder_multi.c
+/// \brief Encodes Multi-Block .lzma files
+//
+// 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"
+#include "block_encoder.h"
+#include "metadata_encoder.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_STREAM_HEADER_COPY,
+ SEQ_HEADER_METADATA_INIT,
+ SEQ_HEADER_METADATA_COPY,
+ SEQ_HEADER_METADATA_CODE,
+ SEQ_DATA_INIT,
+ SEQ_DATA_COPY,
+ SEQ_DATA_CODE,
+ SEQ_FOOTER_METADATA_INIT,
+ SEQ_FOOTER_METADATA_COPY,
+ SEQ_FOOTER_METADATA_CODE,
+ SEQ_STREAM_FOOTER_INIT,
+ SEQ_STREAM_FOOTER_COPY,
+ } sequence;
+
+ /// Block or Metadata encoder
+ lzma_next_coder next;
+
+ /// Options for the Block encoder
+ lzma_options_block block_options;
+
+ /// Information about the Stream
+ lzma_info *info;
+
+ /// Information about the current Data Block
+ lzma_info_iter iter;
+
+ /// Pointer to user-supplied options structure. We don't write to
+ /// it, only read instructions from the application, thus this is
+ /// const even though the user-supplied pointer from
+ /// lzma_options_filter structure isn't.
+ const lzma_options_stream *stream_options;
+
+ /// Stream Header or Stream Footer in encoded form
+ uint8_t *header;
+ size_t header_pos;
+ size_t header_size;
+};
+
+
+typedef enum {
+ BLOCK_HEADER_METADATA,
+ BLOCK_DATA,
+ BLOCK_FOOTER_METADATA,
+} block_type;
+
+
+static lzma_ret
+block_header_encode(lzma_coder *coder, lzma_allocator *allocator,
+ lzma_vli uncompressed_size, block_type type)
+{
+ assert(coder->header == NULL);
+
+ coder->block_options = (lzma_options_block){
+ .check = coder->stream_options->check,
+ .has_crc32 = coder->stream_options->has_crc32,
+ .has_eopm = true,
+ .is_metadata = type != BLOCK_DATA,
+ .has_uncompressed_size_in_footer = false,
+ .has_backward_size = type == BLOCK_FOOTER_METADATA,
+ .handle_padding = false,
+ .total_size = LZMA_VLI_VALUE_UNKNOWN,
+ .compressed_size = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_size = uncompressed_size,
+ .compressed_reserve = 0,
+ .uncompressed_reserve = 0,
+ .total_limit = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_limit = LZMA_VLI_VALUE_UNKNOWN,
+ .padding = LZMA_BLOCK_HEADER_PADDING_AUTO,
+ };
+
+ if (type == BLOCK_DATA) {
+ memcpy(coder->block_options.filters,
+ coder->stream_options->filters,
+ sizeof(coder->stream_options->filters));
+ coder->block_options.alignment = coder->iter.stream_offset;
+ } else {
+ memcpy(coder->block_options.filters,
+ coder->stream_options->metadata_filters,
+ sizeof(coder->stream_options->filters));
+ coder->block_options.alignment
+ = lzma_info_metadata_alignment_get(
+ coder->info, type == BLOCK_HEADER_METADATA);
+ }
+
+ lzma_ret ret = lzma_block_header_size(&coder->block_options);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->header_size = coder->block_options.header_size;
+ coder->header = lzma_alloc(coder->header_size, allocator);
+ if (coder->header == NULL)
+ return LZMA_MEM_ERROR;
+
+ ret = lzma_block_header_encode(coder->header, &coder->block_options);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->header_pos = 0;
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+metadata_encoder_init(lzma_coder *coder, lzma_allocator *allocator,
+ lzma_metadata *metadata, block_type type)
+{
+ lzma_ret ret = lzma_info_metadata_set(coder->info, allocator,
+ metadata, type == BLOCK_HEADER_METADATA, false);
+ if (ret != LZMA_OK)
+ return ret;
+
+ const lzma_vli metadata_size = lzma_metadata_size(metadata);
+ if (metadata_size == 0)
+ return LZMA_PROG_ERROR;
+
+ ret = block_header_encode(coder, allocator, metadata_size, type);
+ if (ret != LZMA_OK)
+ return ret;
+
+ return lzma_metadata_encoder_init(&coder->next, allocator,
+ &coder->block_options, metadata);
+}
+
+
+static lzma_ret
+data_encoder_init(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_ret ret = lzma_info_iter_next(&coder->iter, allocator);
+ if (ret != LZMA_OK)
+ return ret;
+
+ ret = block_header_encode(coder, allocator,
+ LZMA_VLI_VALUE_UNKNOWN, BLOCK_DATA);
+ if (ret != LZMA_OK)
+ return ret;
+
+ return lzma_block_encoder_init(&coder->next, allocator,
+ &coder->block_options);
+}
+
+
+static lzma_ret
+stream_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)
+{
+ // Main loop
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_STREAM_HEADER_COPY:
+ case SEQ_HEADER_METADATA_COPY:
+ case SEQ_DATA_COPY:
+ case SEQ_FOOTER_METADATA_COPY:
+ case SEQ_STREAM_FOOTER_COPY:
+ bufcpy(coder->header, &coder->header_pos, coder->header_size,
+ out, out_pos, out_size);
+ if (coder->header_pos < coder->header_size)
+ return LZMA_OK;
+
+ lzma_free(coder->header, allocator);
+ coder->header = NULL;
+
+ switch (coder->sequence) {
+ case SEQ_STREAM_HEADER_COPY:
+ // Write Header Metadata Block if we have Extra for it
+ // or known Uncompressed Size.
+ if (coder->stream_options->header != NULL
+ || coder->stream_options
+ ->uncompressed_size
+ != LZMA_VLI_VALUE_UNKNOWN) {
+ coder->sequence = SEQ_HEADER_METADATA_INIT;
+ } else {
+ // Mark that Header Metadata Block doesn't
+ // exist.
+ if (lzma_info_size_set(coder->info,
+ LZMA_INFO_HEADER_METADATA, 0)
+ != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ coder->sequence = SEQ_DATA_INIT;
+ }
+ break;
+
+ case SEQ_HEADER_METADATA_COPY:
+ case SEQ_DATA_COPY:
+ case SEQ_FOOTER_METADATA_COPY:
+ ++coder->sequence;
+ break;
+
+ case SEQ_STREAM_FOOTER_COPY:
+ return LZMA_STREAM_END;
+
+ default:
+ assert(0);
+ }
+
+ break;
+
+ case SEQ_HEADER_METADATA_INIT: {
+ lzma_metadata metadata = {
+ .header_metadata_size = LZMA_VLI_VALUE_UNKNOWN,
+ .total_size = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_size = coder->stream_options
+ ->uncompressed_size,
+ .index = NULL,
+ .extra = coder->stream_options->header,
+ };
+
+ const lzma_ret ret = metadata_encoder_init(coder, allocator,
+ &metadata, BLOCK_HEADER_METADATA);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_HEADER_METADATA_COPY;
+ break;
+ }
+
+ case SEQ_FOOTER_METADATA_INIT: {
+ lzma_metadata metadata = {
+ .header_metadata_size
+ = lzma_info_size_get(coder->info,
+ LZMA_INFO_HEADER_METADATA),
+ .total_size = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_size = LZMA_VLI_VALUE_UNKNOWN,
+ .index = lzma_info_index_get(coder->info, false),
+ .extra = coder->stream_options->footer,
+ };
+
+ const lzma_ret ret = metadata_encoder_init(coder, allocator,
+ &metadata, BLOCK_FOOTER_METADATA);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_FOOTER_METADATA_COPY;
+ break;
+ }
+
+ case SEQ_HEADER_METADATA_CODE:
+ case SEQ_FOOTER_METADATA_CODE: {
+ size_t dummy = 0;
+ lzma_ret ret = coder->next.code(coder->next.coder,
+ allocator, NULL, &dummy, 0,
+ out, out_pos, out_size, LZMA_RUN);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ ret = lzma_info_size_set(coder->info,
+ coder->sequence == SEQ_HEADER_METADATA_CODE
+ ? LZMA_INFO_HEADER_METADATA
+ : LZMA_INFO_FOOTER_METADATA,
+ coder->block_options.total_size);
+ if (ret != LZMA_OK)
+ return ret;
+
+ ++coder->sequence;
+ break;
+ }
+
+ case SEQ_DATA_INIT: {
+ // Don't create an empty Block unless it would be
+ // the only Data Block.
+ if (*in_pos == in_size) {
+ if (action != LZMA_FINISH)
+ return LZMA_OK;
+
+ if (lzma_info_index_count_get(coder->info) != 0) {
+ if (lzma_info_index_finish(coder->info))
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_FOOTER_METADATA_INIT;
+ break;
+ }
+ }
+
+ const lzma_ret ret = data_encoder_init(coder, allocator);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_DATA_COPY;
+ break;
+ }
+
+ case SEQ_DATA_CODE: {
+ static const lzma_action convert[4] = {
+ LZMA_RUN,
+ LZMA_SYNC_FLUSH,
+ LZMA_FINISH,
+ LZMA_FINISH,
+ };
+
+ lzma_ret ret = coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, convert[action]);
+ if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
+ return ret;
+
+ ret = lzma_info_iter_set(&coder->iter,
+ coder->block_options.total_size,
+ coder->block_options.uncompressed_size);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_DATA_INIT;
+ break;
+ }
+
+ case SEQ_STREAM_FOOTER_INIT: {
+ assert(coder->header == NULL);
+
+ lzma_stream_flags flags = {
+ .check = coder->stream_options->check,
+ .has_crc32 = coder->stream_options->has_crc32,
+ .is_multi = true,
+ };
+
+ coder->header = lzma_alloc(LZMA_STREAM_TAIL_SIZE, allocator);
+ if (coder->header == NULL)
+ return LZMA_MEM_ERROR;
+
+ const lzma_ret ret = lzma_stream_tail_encode(
+ coder->header, &flags);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->header_size = LZMA_STREAM_TAIL_SIZE;
+ coder->header_pos = 0;
+
+ coder->sequence = SEQ_STREAM_FOOTER_COPY;
+ break;
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->next, allocator);
+ lzma_info_free(coder->info, allocator);
+ lzma_free(coder->header, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+stream_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_options_stream *options)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &stream_encode;
+ next->end = &stream_encoder_end;
+
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ next->coder->info = NULL;
+ } else {
+ lzma_free(next->coder->header, allocator);
+ }
+
+ next->coder->header = NULL;
+
+ next->coder->info = lzma_info_init(next->coder->info, allocator);
+ if (next->coder->info == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->coder->sequence = SEQ_STREAM_HEADER_COPY;
+ next->coder->stream_options = options;
+
+ // Encode Stream Flags
+ {
+ lzma_stream_flags flags = {
+ .check = options->check,
+ .has_crc32 = options->has_crc32,
+ .is_multi = true,
+ };
+
+ next->coder->header = lzma_alloc(LZMA_STREAM_HEADER_SIZE,
+ allocator);
+ if (next->coder->header == NULL)
+ return LZMA_MEM_ERROR;
+
+ return_if_error(lzma_stream_header_encode(
+ next->coder->header, &flags));
+
+ next->coder->header_pos = 0;
+ next->coder->header_size = LZMA_STREAM_HEADER_SIZE;
+ }
+
+ if (lzma_info_size_set(next->coder->info, LZMA_INFO_STREAM_START,
+ options->alignment) != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ lzma_info_iter_begin(next->coder->info, &next->coder->iter);
+
+ return LZMA_OK;
+}
+
+
+/*
+extern lzma_ret
+lzma_stream_encoder_multi_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_options_stream *options)
+{
+ lzma_next_coder_init(stream_encoder_init, next, allocator, options);
+}
+*/
+
+
+extern LZMA_API lzma_ret
+lzma_stream_encoder_multi(
+ lzma_stream *strm, const lzma_options_stream *options)
+{
+ lzma_next_strm_init(strm, stream_encoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+ strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/stream_encoder_single.c b/src/liblzma/common/stream_encoder_single.c
new file mode 100644
index 00000000..e8efd004
--- /dev/null
+++ b/src/liblzma/common/stream_encoder_single.c
@@ -0,0 +1,220 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_encoder_single.c
+/// \brief Encodes Single-Block .lzma files
+//
+// 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"
+#include "block_encoder.h"
+
+
+struct lzma_coder_s {
+ /// Uncompressed Size, Backward Size, and Footer Magic Bytes are
+ /// part of Block in the file format specification, but it is simpler
+ /// to implement them as part of Stream.
+ enum {
+ SEQ_HEADERS,
+ SEQ_DATA,
+ SEQ_FOOTER,
+ } sequence;
+
+ /// Block encoder
+ lzma_next_coder block_encoder;
+
+ /// Block encoder options
+ lzma_options_block block_options;
+
+ /// Stream Flags; we need to have these in this struct so that we
+ /// can encode Stream Footer.
+ lzma_stream_flags stream_flags;
+
+ /// Stream Header + Block Header, or Stream Footer
+ uint8_t *header;
+ size_t header_pos;
+ size_t header_size;
+};
+
+
+static lzma_ret
+stream_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 *out_pos,
+ size_t out_size, lzma_action action)
+{
+ // NOTE: We don't check if the amount of input is in the proper limits,
+ // because the Block encoder will do it for us.
+
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_HEADERS:
+ bufcpy(coder->header, &coder->header_pos, coder->header_size,
+ out, out_pos, out_size);
+
+ if (coder->header_pos == coder->header_size) {
+ coder->header_pos = 0;
+ coder->sequence = SEQ_DATA;
+ }
+
+ break;
+
+ case SEQ_DATA: {
+ lzma_ret ret = coder->block_encoder.code(
+ coder->block_encoder.coder, allocator,
+ in, in_pos, in_size,
+ out, out_pos, out_size, action);
+ if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
+ return ret;
+
+ assert(*in_pos == in_size);
+
+ assert(coder->header_size >= LZMA_STREAM_TAIL_SIZE);
+ coder->header_size = LZMA_STREAM_TAIL_SIZE;
+
+ ret = lzma_stream_tail_encode(
+ coder->header, &coder->stream_flags);
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_FOOTER;
+ break;
+ }
+
+ case SEQ_FOOTER:
+ bufcpy(coder->header, &coder->header_pos, coder->header_size,
+ out, out_pos, out_size);
+
+ return coder->header_pos == coder->header_size
+ ? LZMA_STREAM_END : LZMA_OK;
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_coder_end(&coder->block_encoder, allocator);
+ lzma_free(coder->header, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+stream_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_options_stream *options)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &stream_encode;
+ next->end = &stream_encoder_end;
+ next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
+ } else {
+ // Free the previous buffer, if any.
+ lzma_free(next->coder->header, allocator);
+ }
+
+ // At this point, next->coder->header points to nothing useful.
+ next->coder->header = NULL;
+
+ // Basic initializations
+ next->coder->sequence = SEQ_HEADERS;
+ next->coder->header_pos = 0;
+
+ // Initialize next->coder->stream_flags.
+ next->coder->stream_flags = (lzma_stream_flags){
+ .check = options->check,
+ .has_crc32 = options->has_crc32,
+ .is_multi = false,
+ };
+
+ // Initialize next->coder->block_options.
+ next->coder->block_options = (lzma_options_block){
+ .check = options->check,
+ .has_crc32 = options->has_crc32,
+ .has_eopm = options->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN,
+ .is_metadata = false,
+ .has_uncompressed_size_in_footer = options->uncompressed_size
+ == LZMA_VLI_VALUE_UNKNOWN,
+ .has_backward_size = true,
+ .handle_padding = false,
+ .compressed_size = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_size = options->uncompressed_size,
+ .compressed_reserve = 0,
+ .uncompressed_reserve = 0,
+ .total_size = LZMA_VLI_VALUE_UNKNOWN,
+ .total_limit = LZMA_VLI_VALUE_UNKNOWN,
+ .uncompressed_limit = LZMA_VLI_VALUE_UNKNOWN,
+ .padding = LZMA_BLOCK_HEADER_PADDING_AUTO,
+ .alignment = options->alignment + LZMA_STREAM_HEADER_SIZE,
+ };
+ memcpy(next->coder->block_options.filters, options->filters,
+ sizeof(options->filters));
+
+ return_if_error(lzma_block_header_size(&next->coder->block_options));
+
+ // Encode Stream Flags and Block Header into next->coder->header.
+ next->coder->header_size = (size_t)(LZMA_STREAM_HEADER_SIZE)
+ + next->coder->block_options.header_size;
+ next->coder->header = lzma_alloc(next->coder->header_size, allocator);
+ if (next->coder->header == NULL)
+ return LZMA_MEM_ERROR;
+
+ return_if_error(lzma_stream_header_encode(next->coder->header,
+ &next->coder->stream_flags));
+
+ return_if_error(lzma_block_header_encode(
+ next->coder->header + LZMA_STREAM_HEADER_SIZE,
+ &next->coder->block_options));
+
+ // Initialize the Block encoder.
+ return lzma_block_encoder_init(&next->coder->block_encoder, allocator,
+ &next->coder->block_options);
+}
+
+
+/*
+extern lzma_ret
+lzma_stream_encoder_single_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_options_stream *options)
+{
+ lzma_next_coder_init(stream_encoder_init, allocator, options);
+}
+*/
+
+
+extern LZMA_API lzma_ret
+lzma_stream_encoder_single(
+ lzma_stream *strm, const lzma_options_stream *options)
+{
+ lzma_next_strm_init(strm, stream_encoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/stream_flags_decoder.c b/src/liblzma/common/stream_flags_decoder.c
new file mode 100644
index 00000000..d9c847ac
--- /dev/null
+++ b/src/liblzma/common/stream_flags_decoder.c
@@ -0,0 +1,258 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_decoder.c
+/// \brief Decodes Stream Header and tail from .lzma files
+//
+// 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_flags_decoder.h"
+#include "stream_common.h"
+
+
+////////////
+// Common //
+////////////
+
+struct lzma_coder_s {
+ enum {
+ SEQ_HEADER_MAGIC,
+ SEQ_HEADER_FLAGS,
+ SEQ_HEADER_CRC32,
+
+ SEQ_FOOTER_FLAGS,
+ SEQ_FOOTER_MAGIC,
+ } sequence;
+
+ size_t pos;
+ uint32_t crc32;
+
+ lzma_stream_flags *options;
+};
+
+
+static void
+stream_header_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static bool
+stream_flags_decode(const uint8_t *in, lzma_stream_flags *options)
+{
+ // Reserved bits must be unset.
+ if (*in & 0xE0)
+ return true;
+
+ options->check = *in & 0x07;
+ options->has_crc32 = (*in & 0x08) != 0;
+ options->is_multi = (*in & 0x10) != 0;
+
+ return false;
+}
+
+
+////////////
+// Header //
+////////////
+
+static lzma_ret
+stream_header_decode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((unused)),
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
+ size_t *restrict out_pos lzma_attribute((unused)),
+ size_t out_size lzma_attribute((unused)),
+ lzma_action action lzma_attribute((unused)))
+{
+ while (*in_pos < in_size)
+ switch (coder->sequence) {
+ case SEQ_HEADER_MAGIC:
+ if (in[*in_pos] != lzma_header_magic[coder->pos])
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+
+ if (++coder->pos == sizeof(lzma_header_magic)) {
+ coder->pos = 0;
+ coder->sequence = SEQ_HEADER_FLAGS;
+ }
+
+ break;
+
+ case SEQ_HEADER_FLAGS:
+ if (stream_flags_decode(in + *in_pos, coder->options))
+ return LZMA_HEADER_ERROR;
+
+ coder->crc32 = lzma_crc32(in + *in_pos, 1, 0);
+
+ ++*in_pos;
+ coder->sequence = SEQ_HEADER_CRC32;
+ break;
+
+ case SEQ_HEADER_CRC32:
+ if (in[*in_pos] != ((coder->crc32 >> (coder->pos * 8)) & 0xFF))
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+
+ if (++coder->pos == 4)
+ return LZMA_STREAM_END;
+
+ break;
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+stream_header_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_stream_flags *options)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+ }
+
+ // Set the function pointers unconditionally, because they may
+ // have been pointing to footer decoder too.
+ next->code = &stream_header_decode;
+ next->end = &stream_header_decoder_end;
+
+ next->coder->sequence = SEQ_HEADER_MAGIC;
+ next->coder->pos = 0;
+ next->coder->crc32 = 0;
+ next->coder->options = options;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_stream_header_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_stream_flags *options)
+{
+ lzma_next_coder_init(
+ stream_header_decoder_init, next, allocator, options);
+}
+
+
+extern LZMA_API lzma_ret
+lzma_stream_header_decoder(lzma_stream *strm, lzma_stream_flags *options)
+{
+ lzma_next_strm_init(strm, stream_header_decoder_init, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+
+ return LZMA_OK;
+}
+
+
+//////////
+// Tail //
+//////////
+
+static lzma_ret
+stream_tail_decode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((unused)),
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
+ size_t *restrict out_pos lzma_attribute((unused)),
+ size_t out_size lzma_attribute((unused)),
+ lzma_action action lzma_attribute((unused)))
+{
+ while (*in_pos < in_size)
+ switch (coder->sequence) {
+ case SEQ_FOOTER_FLAGS:
+ if (stream_flags_decode(in + *in_pos, coder->options))
+ return LZMA_HEADER_ERROR;
+
+ ++*in_pos;
+ coder->sequence = SEQ_FOOTER_MAGIC;
+ break;
+
+ case SEQ_FOOTER_MAGIC:
+ if (in[*in_pos] != lzma_footer_magic[coder->pos])
+ return LZMA_DATA_ERROR;
+
+ ++*in_pos;
+
+ if (++coder->pos == sizeof(lzma_footer_magic))
+ return LZMA_STREAM_END;
+
+ break;
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+stream_tail_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_stream_flags *options)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+ }
+
+ // Set the function pointers unconditionally, because they may
+ // have been pointing to footer decoder too.
+ next->code = &stream_tail_decode;
+ next->end = &stream_header_decoder_end;
+
+ next->coder->sequence = SEQ_FOOTER_FLAGS;
+ next->coder->pos = 0;
+ next->coder->options = options;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_stream_tail_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_stream_flags *options)
+{
+ lzma_next_coder_init2(next, allocator, stream_header_decoder_init,
+ stream_tail_decoder_init, allocator, options);
+}
+
+
+extern LZMA_API lzma_ret
+lzma_stream_tail_decoder(lzma_stream *strm, lzma_stream_flags *options)
+{
+ lzma_next_strm_init2(strm, stream_header_decoder_init,
+ stream_tail_decoder_init, strm->allocator, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/stream_flags_decoder.h b/src/liblzma/common/stream_flags_decoder.h
new file mode 100644
index 00000000..e4b8e3c5
--- /dev/null
+++ b/src/liblzma/common/stream_flags_decoder.h
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_decoder.h
+/// \brief Decodes Stream Header and Footer from .lzma files
+//
+// 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_STREAM_FLAGS_DECODER_H
+#define LZMA_STREAM_FLAGS_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_stream_header_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_stream_flags *options);
+
+extern lzma_ret lzma_stream_tail_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_stream_flags *options);
+
+#endif
diff --git a/src/liblzma/common/stream_flags_encoder.c b/src/liblzma/common/stream_flags_encoder.c
new file mode 100644
index 00000000..55468580
--- /dev/null
+++ b/src/liblzma/common/stream_flags_encoder.c
@@ -0,0 +1,75 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_encoder.c
+/// \brief Encodes Stream Header and Footer for .lzma files
+//
+// 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"
+
+
+static bool
+stream_flags_encode(uint8_t *flags_byte, const lzma_stream_flags *options)
+{
+ // Check type
+ if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX)
+ return true;
+
+ *flags_byte = options->check;
+
+ // Usage of CRC32 in Block Headers
+ if (options->has_crc32)
+ *flags_byte |= 0x08;
+
+ // Single- or Multi-Block
+ if (options->is_multi)
+ *flags_byte |= 0x10;
+
+ return false;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_stream_header_encode(uint8_t *out, const lzma_stream_flags *options)
+{
+ // Magic
+ memcpy(out, lzma_header_magic, sizeof(lzma_header_magic));
+
+ // Stream Flags
+ if (stream_flags_encode(out + sizeof(lzma_header_magic), options))
+ return LZMA_PROG_ERROR;;
+
+ // CRC32 of the Stream Header
+ const uint32_t crc = lzma_crc32(out + sizeof(lzma_header_magic), 1, 0);
+
+ for (size_t i = 0; i < 4; ++i)
+ out[sizeof(lzma_header_magic) + 1 + i] = crc >> (i * 8);
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API lzma_ret
+lzma_stream_tail_encode(uint8_t *out, const lzma_stream_flags *options)
+{
+ // Stream Flags
+ if (stream_flags_encode(out, options))
+ return LZMA_PROG_ERROR;
+
+ // Magic
+ memcpy(out + 1, lzma_footer_magic, sizeof(lzma_footer_magic));
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/sysdefs.h b/src/liblzma/common/sysdefs.h
new file mode 120000
index 00000000..c6cb6768
--- /dev/null
+++ b/src/liblzma/common/sysdefs.h
@@ -0,0 +1 @@
+../../common/sysdefs.h \ No newline at end of file
diff --git a/src/liblzma/common/version.c b/src/liblzma/common/version.c
new file mode 100644
index 00000000..dffec7ff
--- /dev/null
+++ b/src/liblzma/common/version.c
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \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
new file mode 100644
index 00000000..2b89c1a7
--- /dev/null
+++ b/src/liblzma/common/vli_decoder.c
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file vli_decoder.c
+/// \brief Decodes variable-length integers
+//
+// 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_API lzma_ret
+lzma_vli_decode(lzma_vli *restrict vli, size_t *restrict vli_pos,
+ const uint8_t *restrict in, size_t *restrict in_pos,
+ size_t in_size)
+{
+ if (*vli > LZMA_VLI_VALUE_MAX || *vli_pos >= 9
+ || (*vli >> (7 * *vli_pos)) != 0)
+ return LZMA_PROG_ERROR;
+
+ if (*in_pos >= in_size)
+ return LZMA_BUF_ERROR;
+
+ if (*vli_pos == 0) {
+ *vli_pos = 1;
+
+ if (in[*in_pos] <= 0x7F) {
+ // Single-byte integer
+ *vli = in[*in_pos];
+ ++*in_pos;
+ return LZMA_STREAM_END;
+ }
+
+ *vli = in[*in_pos] & 0x7F;
+ ++*in_pos;
+ }
+
+ while (*in_pos < in_size) {
+ // Read in the next byte.
+ *vli |= (lzma_vli)(in[*in_pos] & 0x7F) << (*vli_pos * 7);
+ ++*vli_pos;
+
+ // Check if this is the last byte of a multibyte integer.
+ if (in[*in_pos] & 0x80) {
+ ++*in_pos;
+ return LZMA_STREAM_END;
+ }
+
+ // Limit variable-length representation to nine bytes.
+ if (*vli_pos == 9)
+ return LZMA_DATA_ERROR;
+
+ // Increment input position only when the byte was accepted.
+ ++*in_pos;
+ }
+
+ return LZMA_OK;
+}
diff --git a/src/liblzma/common/vli_encoder.c b/src/liblzma/common/vli_encoder.c
new file mode 100644
index 00000000..1ecdb0d2
--- /dev/null
+++ b/src/liblzma/common/vli_encoder.c
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file vli_encoder.c
+/// \brief Encodes variable-length integers
+//
+// 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_API lzma_ret
+lzma_vli_encode(lzma_vli vli, size_t *restrict vli_pos, size_t vli_size,
+ uint8_t *restrict out, size_t *restrict out_pos,
+ size_t out_size)
+{
+ if (vli > LZMA_VLI_VALUE_MAX || *vli_pos >= 9 || vli_size > 9
+ || (vli != 0 && (vli >> (7 * *vli_pos)) == 0))
+ return LZMA_PROG_ERROR;
+
+ if (*out_pos >= out_size)
+ return LZMA_BUF_ERROR;
+
+ if (*vli_pos == 0) {
+ *vli_pos = 1;
+
+ if (vli <= 0x7F && *vli_pos >= vli_size) {
+ // Single-byte integer
+ out[(*out_pos)++] = vli;
+ return LZMA_STREAM_END;
+ }
+
+ // First byte of a multibyte integer
+ out[(*out_pos)++] = (vli & 0x7F) | 0x80;
+ }
+
+ while (*out_pos < out_size) {
+ const lzma_vli b = vli >> (7 * *vli_pos);
+ ++*vli_pos;
+
+ if (b <= 0x7F && *vli_pos >= vli_size) {
+ // Last byte of a multibyte integer
+ out[(*out_pos)++] = (b & 0xFF) | 0x80;
+ return LZMA_STREAM_END;
+ }
+
+ // Middle byte of a multibyte integer
+ out[(*out_pos)++] = b & 0x7F;
+ }
+
+ // vli is not yet completely written out.
+ return LZMA_OK;
+}
+
+
+extern LZMA_API size_t
+lzma_vli_size(lzma_vli vli)
+{
+ if (vli > LZMA_VLI_VALUE_MAX)
+ return 0;
+
+ size_t i = 0;
+ do {
+ vli >>= 7;
+ ++i;
+ } while (vli != 0);
+
+ assert(i <= 9);
+ return i;
+}
diff --git a/src/liblzma/common/vli_reverse_decoder.c b/src/liblzma/common/vli_reverse_decoder.c
new file mode 100644
index 00000000..68ca6a42
--- /dev/null
+++ b/src/liblzma/common/vli_reverse_decoder.c
@@ -0,0 +1,55 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file vli_reverse_decoder.c
+/// \brief Decodes variable-length integers starting at end of the buffer
+//
+// 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_API lzma_ret
+lzma_vli_reverse_decode(lzma_vli *vli, const uint8_t *in, size_t *in_size)
+{
+ if (*in_size == 0)
+ return LZMA_BUF_ERROR;
+
+ size_t i = *in_size - 1;
+ *vli = in[i] & 0x7F;
+
+ if (!(in[i] & 0x80)) {
+ *in_size = i;
+ return LZMA_OK;
+ }
+
+ const size_t end = *in_size > LZMA_VLI_BYTES_MAX
+ ? *in_size - LZMA_VLI_BYTES_MAX : 0;
+
+ do {
+ if (i-- == end) {
+ if (*in_size < LZMA_VLI_BYTES_MAX)
+ return LZMA_BUF_ERROR;
+
+ return LZMA_DATA_ERROR;
+ }
+
+ *vli <<= 7;
+ *vli = in[i] & 0x7F;
+
+ } while (!(in[i] & 0x80));
+
+ *in_size = i;
+ return LZMA_OK;
+}