123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- // SPDX-License-Identifier: 0BSD
- ///////////////////////////////////////////////////////////////////////////////
- //
- /// \file microlzma_encoder.c
- /// \brief Encode into MicroLZMA format
- //
- // Author: Lasse Collin
- //
- ///////////////////////////////////////////////////////////////////////////////
- #include "lzma_encoder.h"
- typedef struct {
- /// LZMA1 encoder
- lzma_next_coder lzma;
- /// LZMA properties byte (lc/lp/pb)
- uint8_t props;
- } lzma_microlzma_coder;
- static lzma_ret
- microlzma_encode(void *coder_ptr, const lzma_allocator *allocator,
- const uint8_t *restrict in, size_t *restrict in_pos,
- size_t in_size, uint8_t *restrict out,
- size_t *restrict out_pos, size_t out_size, lzma_action action)
- {
- lzma_microlzma_coder *coder = coder_ptr;
- // Remember *out_pos so that we can overwrite the first byte with
- // the LZMA properties byte.
- const size_t out_start = *out_pos;
- // Remember *in_pos so that we can set it based on how many
- // uncompressed bytes were actually encoded.
- const size_t in_start = *in_pos;
- // Set the output size limit based on the available output space.
- // We know that the encoder supports set_out_limit() so
- // LZMA_OPTIONS_ERROR isn't possible. LZMA_BUF_ERROR is possible
- // but lzma_code() has an assertion to not allow it to be returned
- // from here and I don't want to change that for now, so
- // LZMA_BUF_ERROR becomes LZMA_PROG_ERROR.
- uint64_t uncomp_size;
- if (coder->lzma.set_out_limit(coder->lzma.coder,
- &uncomp_size, out_size - *out_pos) != LZMA_OK)
- return LZMA_PROG_ERROR;
- // set_out_limit fails if this isn't true.
- assert(out_size - *out_pos >= 6);
- // Encode as much as possible.
- const lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
- in, in_pos, in_size, out, out_pos, out_size, action);
- if (ret != LZMA_STREAM_END) {
- if (ret == LZMA_OK) {
- assert(0);
- return LZMA_PROG_ERROR;
- }
- return ret;
- }
- // The first output byte is bitwise-negation of the properties byte.
- // We know that there is space for this byte because set_out_limit
- // and the actual encoding succeeded.
- out[out_start] = (uint8_t)(~coder->props);
- // The LZMA encoder likely read more input than it was able to encode.
- // Set *in_pos based on uncomp_size.
- assert(uncomp_size <= in_size - in_start);
- *in_pos = in_start + (size_t)(uncomp_size);
- return ret;
- }
- static void
- microlzma_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
- {
- lzma_microlzma_coder *coder = coder_ptr;
- lzma_next_end(&coder->lzma, allocator);
- lzma_free(coder, allocator);
- return;
- }
- static lzma_ret
- microlzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
- const lzma_options_lzma *options)
- {
- lzma_next_coder_init(µlzma_encoder_init, next, allocator);
- lzma_microlzma_coder *coder = next->coder;
- if (coder == NULL) {
- coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
- if (coder == NULL)
- return LZMA_MEM_ERROR;
- next->coder = coder;
- next->code = µlzma_encode;
- next->end = µlzma_encoder_end;
- coder->lzma = LZMA_NEXT_CODER_INIT;
- }
- // Encode the properties byte. Bitwise-negation of it will be the
- // first output byte.
- if (lzma_lzma_lclppb_encode(options, &coder->props))
- return LZMA_OPTIONS_ERROR;
- // Initialize the LZMA encoder.
- const lzma_filter_info filters[2] = {
- {
- .id = LZMA_FILTER_LZMA1,
- .init = &lzma_lzma_encoder_init,
- .options = (void *)(options),
- }, {
- .init = NULL,
- }
- };
- return lzma_next_filter_init(&coder->lzma, allocator, filters);
- }
- extern LZMA_API(lzma_ret)
- lzma_microlzma_encoder(lzma_stream *strm, const lzma_options_lzma *options)
- {
- lzma_next_strm_init(microlzma_encoder_init, strm, options);
- strm->internal->supported_actions[LZMA_FINISH] = true;
- return LZMA_OK;
- }
|