aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/stream_encoder_single.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/liblzma/common/stream_encoder_single.c')
-rw-r--r--src/liblzma/common/stream_encoder_single.c220
1 files changed, 220 insertions, 0 deletions
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;
+}