Path: blob/master/Utilities/cmliblzma/liblzma/common/microlzma_encoder.c
3153 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file microlzma_encoder.c5/// \brief Encode into MicroLZMA format6//7// Author: Lasse Collin8//9///////////////////////////////////////////////////////////////////////////////1011#include "lzma_encoder.h"121314typedef struct {15/// LZMA1 encoder16lzma_next_coder lzma;1718/// LZMA properties byte (lc/lp/pb)19uint8_t props;20} lzma_microlzma_coder;212223static lzma_ret24microlzma_encode(void *coder_ptr, const lzma_allocator *allocator,25const uint8_t *restrict in, size_t *restrict in_pos,26size_t in_size, uint8_t *restrict out,27size_t *restrict out_pos, size_t out_size, lzma_action action)28{29lzma_microlzma_coder *coder = coder_ptr;3031// Remember *out_pos so that we can overwrite the first byte with32// the LZMA properties byte.33const size_t out_start = *out_pos;3435// Remember *in_pos so that we can set it based on how many36// uncompressed bytes were actually encoded.37const size_t in_start = *in_pos;3839// Set the output size limit based on the available output space.40// We know that the encoder supports set_out_limit() so41// LZMA_OPTIONS_ERROR isn't possible. LZMA_BUF_ERROR is possible42// but lzma_code() has an assertion to not allow it to be returned43// from here and I don't want to change that for now, so44// LZMA_BUF_ERROR becomes LZMA_PROG_ERROR.45uint64_t uncomp_size;46if (coder->lzma.set_out_limit(coder->lzma.coder,47&uncomp_size, out_size - *out_pos) != LZMA_OK)48return LZMA_PROG_ERROR;4950// set_out_limit fails if this isn't true.51assert(out_size - *out_pos >= 6);5253// Encode as much as possible.54const lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,55in, in_pos, in_size, out, out_pos, out_size, action);5657if (ret != LZMA_STREAM_END) {58if (ret == LZMA_OK) {59assert(0);60return LZMA_PROG_ERROR;61}6263return ret;64}6566// The first output byte is bitwise-negation of the properties byte.67// We know that there is space for this byte because set_out_limit68// and the actual encoding succeeded.69out[out_start] = (uint8_t)(~coder->props);7071// The LZMA encoder likely read more input than it was able to encode.72// Set *in_pos based on uncomp_size.73assert(uncomp_size <= in_size - in_start);74*in_pos = in_start + (size_t)(uncomp_size);7576return ret;77}787980static void81microlzma_encoder_end(void *coder_ptr, const lzma_allocator *allocator)82{83lzma_microlzma_coder *coder = coder_ptr;84lzma_next_end(&coder->lzma, allocator);85lzma_free(coder, allocator);86return;87}888990static lzma_ret91microlzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,92const lzma_options_lzma *options)93{94lzma_next_coder_init(µlzma_encoder_init, next, allocator);9596lzma_microlzma_coder *coder = next->coder;9798if (coder == NULL) {99coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);100if (coder == NULL)101return LZMA_MEM_ERROR;102103next->coder = coder;104next->code = µlzma_encode;105next->end = µlzma_encoder_end;106107coder->lzma = LZMA_NEXT_CODER_INIT;108}109110// Encode the properties byte. Bitwise-negation of it will be the111// first output byte.112if (lzma_lzma_lclppb_encode(options, &coder->props))113return LZMA_OPTIONS_ERROR;114115// Initialize the LZMA encoder.116const lzma_filter_info filters[2] = {117{118.id = LZMA_FILTER_LZMA1,119.init = &lzma_lzma_encoder_init,120.options = (void *)(options),121}, {122.init = NULL,123}124};125126return lzma_next_filter_init(&coder->lzma, allocator, filters);127}128129130extern LZMA_API(lzma_ret)131lzma_microlzma_encoder(lzma_stream *strm, const lzma_options_lzma *options)132{133lzma_next_strm_init(microlzma_encoder_init, strm, options);134135strm->internal->supported_actions[LZMA_FINISH] = true;136137return LZMA_OK;138139}140141142