Path: blob/master/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.c
3156 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file lzma_encoder.c5/// \brief LZMA encoder6///7// Authors: Igor Pavlov8// Lasse Collin9//10///////////////////////////////////////////////////////////////////////////////1112#include "lzma2_encoder.h"13#include "lzma_encoder_private.h"14#include "fastpos.h"151617/////////////18// Literal //19/////////////2021static inline void22literal_matched(lzma_range_encoder *rc, probability *subcoder,23uint32_t match_byte, uint32_t symbol)24{25uint32_t offset = 0x100;26symbol += UINT32_C(1) << 8;2728do {29match_byte <<= 1;30const uint32_t match_bit = match_byte & offset;31const uint32_t subcoder_index32= offset + match_bit + (symbol >> 8);33const uint32_t bit = (symbol >> 7) & 1;34rc_bit(rc, &subcoder[subcoder_index], bit);3536symbol <<= 1;37offset &= ~(match_byte ^ symbol);3839} while (symbol < (UINT32_C(1) << 16));40}414243static inline void44literal(lzma_lzma1_encoder *coder, lzma_mf *mf, uint32_t position)45{46// Locate the literal byte to be encoded and the subcoder.47const uint8_t cur_byte = mf->buffer[48mf->read_pos - mf->read_ahead];49probability *subcoder = literal_subcoder(coder->literal,50coder->literal_context_bits, coder->literal_mask,51position, mf->buffer[mf->read_pos - mf->read_ahead - 1]);5253if (is_literal_state(coder->state)) {54// Previous LZMA-symbol was a literal. Encode a normal55// literal without a match byte.56update_literal_normal(coder->state);57rc_bittree(&coder->rc, subcoder, 8, cur_byte);58} else {59// Previous LZMA-symbol was a match. Use the last byte of60// the match as a "match byte". That is, compare the bits61// of the current literal and the match byte.62update_literal_matched(coder->state);63const uint8_t match_byte = mf->buffer[64mf->read_pos - coder->reps[0] - 165- mf->read_ahead];66literal_matched(&coder->rc, subcoder, match_byte, cur_byte);67}68}697071//////////////////72// Match length //73//////////////////7475static void76length_update_prices(lzma_length_encoder *lc, const uint32_t pos_state)77{78const uint32_t table_size = lc->table_size;79lc->counters[pos_state] = table_size;8081const uint32_t a0 = rc_bit_0_price(lc->choice);82const uint32_t a1 = rc_bit_1_price(lc->choice);83const uint32_t b0 = a1 + rc_bit_0_price(lc->choice2);84const uint32_t b1 = a1 + rc_bit_1_price(lc->choice2);85uint32_t *const prices = lc->prices[pos_state];8687uint32_t i;88for (i = 0; i < table_size && i < LEN_LOW_SYMBOLS; ++i)89prices[i] = a0 + rc_bittree_price(lc->low[pos_state],90LEN_LOW_BITS, i);9192for (; i < table_size && i < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; ++i)93prices[i] = b0 + rc_bittree_price(lc->mid[pos_state],94LEN_MID_BITS, i - LEN_LOW_SYMBOLS);9596for (; i < table_size; ++i)97prices[i] = b1 + rc_bittree_price(lc->high, LEN_HIGH_BITS,98i - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS);99100return;101}102103104static inline void105length(lzma_range_encoder *rc, lzma_length_encoder *lc,106const uint32_t pos_state, uint32_t len, const bool fast_mode)107{108assert(len <= MATCH_LEN_MAX);109len -= MATCH_LEN_MIN;110111if (len < LEN_LOW_SYMBOLS) {112rc_bit(rc, &lc->choice, 0);113rc_bittree(rc, lc->low[pos_state], LEN_LOW_BITS, len);114} else {115rc_bit(rc, &lc->choice, 1);116len -= LEN_LOW_SYMBOLS;117118if (len < LEN_MID_SYMBOLS) {119rc_bit(rc, &lc->choice2, 0);120rc_bittree(rc, lc->mid[pos_state], LEN_MID_BITS, len);121} else {122rc_bit(rc, &lc->choice2, 1);123len -= LEN_MID_SYMBOLS;124rc_bittree(rc, lc->high, LEN_HIGH_BITS, len);125}126}127128// Only getoptimum uses the prices so don't update the table when129// in fast mode.130if (!fast_mode)131if (--lc->counters[pos_state] == 0)132length_update_prices(lc, pos_state);133}134135136///////////137// Match //138///////////139140static inline void141match(lzma_lzma1_encoder *coder, const uint32_t pos_state,142const uint32_t distance, const uint32_t len)143{144update_match(coder->state);145146length(&coder->rc, &coder->match_len_encoder, pos_state, len,147coder->fast_mode);148149const uint32_t dist_slot = get_dist_slot(distance);150const uint32_t dist_state = get_dist_state(len);151rc_bittree(&coder->rc, coder->dist_slot[dist_state],152DIST_SLOT_BITS, dist_slot);153154if (dist_slot >= DIST_MODEL_START) {155const uint32_t footer_bits = (dist_slot >> 1) - 1;156const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;157const uint32_t dist_reduced = distance - base;158159if (dist_slot < DIST_MODEL_END) {160// Careful here: base - dist_slot - 1 can be -1, but161// rc_bittree_reverse starts at probs[1], not probs[0].162rc_bittree_reverse(&coder->rc,163coder->dist_special + base - dist_slot - 1,164footer_bits, dist_reduced);165} else {166rc_direct(&coder->rc, dist_reduced >> ALIGN_BITS,167footer_bits - ALIGN_BITS);168rc_bittree_reverse(169&coder->rc, coder->dist_align,170ALIGN_BITS, dist_reduced & ALIGN_MASK);171++coder->align_price_count;172}173}174175coder->reps[3] = coder->reps[2];176coder->reps[2] = coder->reps[1];177coder->reps[1] = coder->reps[0];178coder->reps[0] = distance;179++coder->match_price_count;180}181182183////////////////////184// Repeated match //185////////////////////186187static inline void188rep_match(lzma_lzma1_encoder *coder, const uint32_t pos_state,189const uint32_t rep, const uint32_t len)190{191if (rep == 0) {192rc_bit(&coder->rc, &coder->is_rep0[coder->state], 0);193rc_bit(&coder->rc,194&coder->is_rep0_long[coder->state][pos_state],195len != 1);196} else {197const uint32_t distance = coder->reps[rep];198rc_bit(&coder->rc, &coder->is_rep0[coder->state], 1);199200if (rep == 1) {201rc_bit(&coder->rc, &coder->is_rep1[coder->state], 0);202} else {203rc_bit(&coder->rc, &coder->is_rep1[coder->state], 1);204rc_bit(&coder->rc, &coder->is_rep2[coder->state],205rep - 2);206207if (rep == 3)208coder->reps[3] = coder->reps[2];209210coder->reps[2] = coder->reps[1];211}212213coder->reps[1] = coder->reps[0];214coder->reps[0] = distance;215}216217if (len == 1) {218update_short_rep(coder->state);219} else {220length(&coder->rc, &coder->rep_len_encoder, pos_state, len,221coder->fast_mode);222update_long_rep(coder->state);223}224}225226227//////////228// Main //229//////////230231static void232encode_symbol(lzma_lzma1_encoder *coder, lzma_mf *mf,233uint32_t back, uint32_t len, uint32_t position)234{235const uint32_t pos_state = position & coder->pos_mask;236237if (back == UINT32_MAX) {238// Literal i.e. eight-bit byte239assert(len == 1);240rc_bit(&coder->rc,241&coder->is_match[coder->state][pos_state], 0);242literal(coder, mf, position);243} else {244// Some type of match245rc_bit(&coder->rc,246&coder->is_match[coder->state][pos_state], 1);247248if (back < REPS) {249// It's a repeated match i.e. the same distance250// has been used earlier.251rc_bit(&coder->rc, &coder->is_rep[coder->state], 1);252rep_match(coder, pos_state, back, len);253} else {254// Normal match255rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);256match(coder, pos_state, back - REPS, len);257}258}259260assert(mf->read_ahead >= len);261mf->read_ahead -= len;262}263264265static bool266encode_init(lzma_lzma1_encoder *coder, lzma_mf *mf)267{268assert(mf_position(mf) == 0);269assert(coder->uncomp_size == 0);270271if (mf->read_pos == mf->read_limit) {272if (mf->action == LZMA_RUN)273return false; // We cannot do anything.274275// We are finishing (we cannot get here when flushing).276assert(mf->write_pos == mf->read_pos);277assert(mf->action == LZMA_FINISH);278} else {279// Do the actual initialization. The first LZMA symbol must280// always be a literal.281mf_skip(mf, 1);282mf->read_ahead = 0;283rc_bit(&coder->rc, &coder->is_match[0][0], 0);284rc_bittree(&coder->rc, coder->literal + 0, 8, mf->buffer[0]);285++coder->uncomp_size;286}287288// Initialization is done (except if empty file).289coder->is_initialized = true;290291return true;292}293294295static void296encode_eopm(lzma_lzma1_encoder *coder, uint32_t position)297{298const uint32_t pos_state = position & coder->pos_mask;299rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1);300rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);301match(coder, pos_state, UINT32_MAX, MATCH_LEN_MIN);302}303304305/// Number of bytes that a single encoding loop in lzma_lzma_encode() can306/// consume from the dictionary. This limit comes from lzma_lzma_optimum()307/// and may need to be updated if that function is significantly modified.308#define LOOP_INPUT_MAX (OPTS + 1)309310311extern lzma_ret312lzma_lzma_encode(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,313uint8_t *restrict out, size_t *restrict out_pos,314size_t out_size, uint32_t limit)315{316// Initialize the stream if no data has been encoded yet.317if (!coder->is_initialized && !encode_init(coder, mf))318return LZMA_OK;319320// Encode pending output bytes from the range encoder.321// At the start of the stream, encode_init() encodes one literal.322// Later there can be pending output only with LZMA1 because LZMA2323// ensures that there is always enough output space. Thus when using324// LZMA2, rc_encode() calls in this function will always return false.325if (rc_encode(&coder->rc, out, out_pos, out_size)) {326// We don't get here with LZMA2.327assert(limit == UINT32_MAX);328return LZMA_OK;329}330331// If the range encoder was flushed in an earlier call to this332// function but there wasn't enough output buffer space, those333// bytes would have now been encoded by the above rc_encode() call334// and the stream has now been finished. This can only happen with335// LZMA1 as LZMA2 always provides enough output buffer space.336if (coder->is_flushed) {337assert(limit == UINT32_MAX);338return LZMA_STREAM_END;339}340341while (true) {342// With LZMA2 we need to take care that compressed size of343// a chunk doesn't get too big.344// FIXME? Check if this could be improved.345if (limit != UINT32_MAX346&& (mf->read_pos - mf->read_ahead >= limit347|| *out_pos + rc_pending(&coder->rc)348>= LZMA2_CHUNK_MAX349- LOOP_INPUT_MAX))350break;351352// Check that there is some input to process.353if (mf->read_pos >= mf->read_limit) {354if (mf->action == LZMA_RUN)355return LZMA_OK;356357if (mf->read_ahead == 0)358break;359}360361// Get optimal match (repeat position and length).362// Value ranges for pos:363// - [0, REPS): repeated match364// - [REPS, UINT32_MAX):365// match at (pos - REPS)366// - UINT32_MAX: not a match but a literal367// Value ranges for len:368// - [MATCH_LEN_MIN, MATCH_LEN_MAX]369uint32_t len;370uint32_t back;371372if (coder->fast_mode)373lzma_lzma_optimum_fast(coder, mf, &back, &len);374else375lzma_lzma_optimum_normal(coder, mf, &back, &len,376(uint32_t)(coder->uncomp_size));377378encode_symbol(coder, mf, back, len,379(uint32_t)(coder->uncomp_size));380381// If output size limiting is active (out_limit != 0), check382// if encoding this LZMA symbol would make the output size383// exceed the specified limit.384if (coder->out_limit != 0 && rc_encode_dummy(385&coder->rc, coder->out_limit)) {386// The most recent LZMA symbol would make the output387// too big. Throw it away.388rc_forget(&coder->rc);389390// FIXME: Tell the LZ layer to not read more input as391// it would be waste of time. This doesn't matter if392// output-size-limited encoding is done with a single393// call though.394395break;396}397398// This symbol will be encoded so update the uncompressed size.399coder->uncomp_size += len;400401// Encode the LZMA symbol.402if (rc_encode(&coder->rc, out, out_pos, out_size)) {403// Once again, this can only happen with LZMA1.404assert(limit == UINT32_MAX);405return LZMA_OK;406}407}408409// Make the uncompressed size available to the application.410if (coder->uncomp_size_ptr != NULL)411*coder->uncomp_size_ptr = coder->uncomp_size;412413// LZMA2 doesn't use EOPM at LZMA level.414//415// Plain LZMA streams without EOPM aren't supported except when416// output size limiting is enabled.417if (coder->use_eopm)418encode_eopm(coder, (uint32_t)(coder->uncomp_size));419420// Flush the remaining bytes from the range encoder.421rc_flush(&coder->rc);422423// Copy the remaining bytes to the output buffer. If there424// isn't enough output space, we will copy out the remaining425// bytes on the next call to this function.426if (rc_encode(&coder->rc, out, out_pos, out_size)) {427// This cannot happen with LZMA2.428assert(limit == UINT32_MAX);429430coder->is_flushed = true;431return LZMA_OK;432}433434return LZMA_STREAM_END;435}436437438static lzma_ret439lzma_encode(void *coder, lzma_mf *restrict mf,440uint8_t *restrict out, size_t *restrict out_pos,441size_t out_size)442{443// Plain LZMA has no support for sync-flushing.444if (unlikely(mf->action == LZMA_SYNC_FLUSH))445return LZMA_OPTIONS_ERROR;446447return lzma_lzma_encode(coder, mf, out, out_pos, out_size, UINT32_MAX);448}449450451static lzma_ret452lzma_lzma_set_out_limit(453void *coder_ptr, uint64_t *uncomp_size, uint64_t out_limit)454{455// Minimum output size is 5 bytes but that cannot hold any output456// so we use 6 bytes.457if (out_limit < 6)458return LZMA_BUF_ERROR;459460lzma_lzma1_encoder *coder = coder_ptr;461coder->out_limit = out_limit;462coder->uncomp_size_ptr = uncomp_size;463coder->use_eopm = false;464return LZMA_OK;465}466467468////////////////////469// Initialization //470////////////////////471472static bool473is_options_valid(const lzma_options_lzma *options)474{475// Validate some of the options. LZ encoder validates nice_len too476// but we need a valid value here earlier.477return is_lclppb_valid(options)478&& options->nice_len >= MATCH_LEN_MIN479&& options->nice_len <= MATCH_LEN_MAX480&& (options->mode == LZMA_MODE_FAST481|| options->mode == LZMA_MODE_NORMAL);482}483484485static void486set_lz_options(lzma_lz_options *lz_options, const lzma_options_lzma *options)487{488// LZ encoder initialization does the validation for these so we489// don't need to validate here.490lz_options->before_size = OPTS;491lz_options->dict_size = options->dict_size;492lz_options->after_size = LOOP_INPUT_MAX;493lz_options->match_len_max = MATCH_LEN_MAX;494lz_options->nice_len = my_max(mf_get_hash_bytes(options->mf),495options->nice_len);496lz_options->match_finder = options->mf;497lz_options->depth = options->depth;498lz_options->preset_dict = options->preset_dict;499lz_options->preset_dict_size = options->preset_dict_size;500return;501}502503504static void505length_encoder_reset(lzma_length_encoder *lencoder,506const uint32_t num_pos_states, const bool fast_mode)507{508bit_reset(lencoder->choice);509bit_reset(lencoder->choice2);510511for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {512bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);513bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);514}515516bittree_reset(lencoder->high, LEN_HIGH_BITS);517518if (!fast_mode)519for (uint32_t pos_state = 0; pos_state < num_pos_states;520++pos_state)521length_update_prices(lencoder, pos_state);522523return;524}525526527extern lzma_ret528lzma_lzma_encoder_reset(lzma_lzma1_encoder *coder,529const lzma_options_lzma *options)530{531if (!is_options_valid(options))532return LZMA_OPTIONS_ERROR;533534coder->pos_mask = (1U << options->pb) - 1;535coder->literal_context_bits = options->lc;536coder->literal_mask = literal_mask_calc(options->lc, options->lp);537538// Range coder539rc_reset(&coder->rc);540541// State542coder->state = STATE_LIT_LIT;543for (size_t i = 0; i < REPS; ++i)544coder->reps[i] = 0;545546literal_init(coder->literal, options->lc, options->lp);547548// Bit encoders549for (size_t i = 0; i < STATES; ++i) {550for (size_t j = 0; j <= coder->pos_mask; ++j) {551bit_reset(coder->is_match[i][j]);552bit_reset(coder->is_rep0_long[i][j]);553}554555bit_reset(coder->is_rep[i]);556bit_reset(coder->is_rep0[i]);557bit_reset(coder->is_rep1[i]);558bit_reset(coder->is_rep2[i]);559}560561for (size_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)562bit_reset(coder->dist_special[i]);563564// Bit tree encoders565for (size_t i = 0; i < DIST_STATES; ++i)566bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);567568bittree_reset(coder->dist_align, ALIGN_BITS);569570// Length encoders571length_encoder_reset(&coder->match_len_encoder,5721U << options->pb, coder->fast_mode);573574length_encoder_reset(&coder->rep_len_encoder,5751U << options->pb, coder->fast_mode);576577// Price counts are incremented every time appropriate probabilities578// are changed. price counts are set to zero when the price tables579// are updated, which is done when the appropriate price counts have580// big enough value, and lzma_mf.read_ahead == 0 which happens at581// least every OPTS (a few thousand) possible price count increments.582//583// By resetting price counts to UINT32_MAX / 2, we make sure that the584// price tables will be initialized before they will be used (since585// the value is definitely big enough), and that it is OK to increment586// price counts without risk of integer overflow (since UINT32_MAX / 2587// is small enough). The current code doesn't increment price counts588// before initializing price tables, but it maybe done in future if589// we add support for saving the state between LZMA2 chunks.590coder->match_price_count = UINT32_MAX / 2;591coder->align_price_count = UINT32_MAX / 2;592593coder->opts_end_index = 0;594coder->opts_current_index = 0;595596return LZMA_OK;597}598599600extern lzma_ret601lzma_lzma_encoder_create(void **coder_ptr, const lzma_allocator *allocator,602lzma_vli id, const lzma_options_lzma *options,603lzma_lz_options *lz_options)604{605assert(id == LZMA_FILTER_LZMA1 || id == LZMA_FILTER_LZMA1EXT606|| id == LZMA_FILTER_LZMA2);607608// Allocate lzma_lzma1_encoder if it wasn't already allocated.609if (*coder_ptr == NULL) {610*coder_ptr = lzma_alloc(sizeof(lzma_lzma1_encoder), allocator);611if (*coder_ptr == NULL)612return LZMA_MEM_ERROR;613}614615lzma_lzma1_encoder *coder = *coder_ptr;616617// Set compression mode. Note that we haven't validated the options618// yet. Invalid options will get rejected by lzma_lzma_encoder_reset()619// call at the end of this function.620switch (options->mode) {621case LZMA_MODE_FAST:622coder->fast_mode = true;623break;624625case LZMA_MODE_NORMAL: {626coder->fast_mode = false;627628// Set dist_table_size.629// Round the dictionary size up to next 2^n.630//631// Currently the maximum encoder dictionary size632// is 1.5 GiB due to lz_encoder.c and here we need633// to be below 2 GiB to make the rounded up value634// fit in an uint32_t and avoid an infinite while-loop635// (and undefined behavior due to a too large shift).636// So do the same check as in LZ encoder,637// limiting to 1.5 GiB.638if (options->dict_size > (UINT32_C(1) << 30)639+ (UINT32_C(1) << 29))640return LZMA_OPTIONS_ERROR;641642uint32_t log_size = 0;643while ((UINT32_C(1) << log_size) < options->dict_size)644++log_size;645646coder->dist_table_size = log_size * 2;647648// Length encoders' price table size649const uint32_t nice_len = my_max(650mf_get_hash_bytes(options->mf),651options->nice_len);652653coder->match_len_encoder.table_size654= nice_len + 1 - MATCH_LEN_MIN;655coder->rep_len_encoder.table_size656= nice_len + 1 - MATCH_LEN_MIN;657break;658}659660default:661return LZMA_OPTIONS_ERROR;662}663664// We don't need to write the first byte as literal if there is665// a non-empty preset dictionary. encode_init() wouldn't even work666// if there is a non-empty preset dictionary, because encode_init()667// assumes that position is zero and previous byte is also zero.668coder->is_initialized = options->preset_dict != NULL669&& options->preset_dict_size > 0;670coder->is_flushed = false;671coder->uncomp_size = 0;672coder->uncomp_size_ptr = NULL;673674// Output size limiting is disabled by default.675coder->out_limit = 0;676677// Determine if end marker is wanted:678// - It is never used with LZMA2.679// - It is always used with LZMA_FILTER_LZMA1 (unless680// lzma_lzma_set_out_limit() is called later).681// - LZMA_FILTER_LZMA1EXT has a flag for it in the options.682coder->use_eopm = (id == LZMA_FILTER_LZMA1);683if (id == LZMA_FILTER_LZMA1EXT) {684// Check if unsupported flags are present.685if (options->ext_flags & ~LZMA_LZMA1EXT_ALLOW_EOPM)686return LZMA_OPTIONS_ERROR;687688coder->use_eopm = (options->ext_flags689& LZMA_LZMA1EXT_ALLOW_EOPM) != 0;690691// TODO? As long as there are no filters that change the size692// of the data, it is enough to look at lzma_stream.total_in693// after encoding has been finished to know the uncompressed694// size of the LZMA1 stream. But in the future there could be695// filters that change the size of the data and then total_in696// doesn't work as the LZMA1 stream size might be different697// due to another filter in the chain. The problem is simple698// to solve: Add another flag to ext_flags and then set699// coder->uncomp_size_ptr to the address stored in700// lzma_options_lzma.reserved_ptr2 (or _ptr1).701}702703set_lz_options(lz_options, options);704705return lzma_lzma_encoder_reset(coder, options);706}707708709static lzma_ret710lzma_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,711lzma_vli id, const void *options, lzma_lz_options *lz_options)712{713if (options == NULL)714return LZMA_PROG_ERROR;715716lz->code = &lzma_encode;717lz->set_out_limit = &lzma_lzma_set_out_limit;718return lzma_lzma_encoder_create(719&lz->coder, allocator, id, options, lz_options);720}721722723extern lzma_ret724lzma_lzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,725const lzma_filter_info *filters)726{727return lzma_lz_encoder_init(728next, allocator, filters, &lzma_encoder_init);729}730731732extern uint64_t733lzma_lzma_encoder_memusage(const void *options)734{735if (!is_options_valid(options))736return UINT64_MAX;737738lzma_lz_options lz_options;739set_lz_options(&lz_options, options);740741const uint64_t lz_memusage = lzma_lz_encoder_memusage(&lz_options);742if (lz_memusage == UINT64_MAX)743return UINT64_MAX;744745return (uint64_t)(sizeof(lzma_lzma1_encoder)) + lz_memusage;746}747748749extern bool750lzma_lzma_lclppb_encode(const lzma_options_lzma *options, uint8_t *byte)751{752if (!is_lclppb_valid(options))753return true;754755*byte = (options->pb * 5 + options->lp) * 9 + options->lc;756assert(*byte <= (4 * 5 + 4) * 9 + 8);757758return false;759}760761762#ifdef HAVE_ENCODER_LZMA1763extern lzma_ret764lzma_lzma_props_encode(const void *options, uint8_t *out)765{766if (options == NULL)767return LZMA_PROG_ERROR;768769const lzma_options_lzma *const opt = options;770771if (lzma_lzma_lclppb_encode(opt, out))772return LZMA_PROG_ERROR;773774write32le(out + 1, opt->dict_size);775776return LZMA_OK;777}778#endif779780781extern LZMA_API(lzma_bool)782lzma_mode_is_supported(lzma_mode mode)783{784return mode == LZMA_MODE_FAST || mode == LZMA_MODE_NORMAL;785}786787788