diff options
Diffstat (limited to 'src/liblzma/common/stream_encoder_single.c')
-rw-r--r-- | src/liblzma/common/stream_encoder_single.c | 220 |
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; +} |