aboutsummaryrefslogblamecommitdiff
path: root/src/liblzma/lzma/lzma_encoder_init.c
blob: d7807529888bf6f5dbd33a9c5d28b2c4bb2cbca4 (plain) (tree)




















































































































































































































































                                                                                
///////////////////////////////////////////////////////////////////////////////
//
/// \file       lzma_encoder_init.c
/// \brief      Creating, resetting and destroying the LZMA encoder
//
//  Copyright (C) 1999-2006 Igor Pavlov
//  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 "lzma_encoder_private.h"


uint8_t lzma_fastpos[1 << 11];

extern void
lzma_fastpos_init(void)
{
	static const uint8_t fast_slots = 22;

	int c = 2;
	lzma_fastpos[0] = 0;
	lzma_fastpos[1] = 1;

	for (uint8_t slot_fast = 2; slot_fast < fast_slots; ++slot_fast) {
		const uint32_t k = (1 << ((slot_fast >> 1) - 1));

		for (uint32_t j = 0; j < k; ++j, ++c)
			lzma_fastpos[c] = slot_fast;
	}

	return;
}


/// \brief      Initializes the length encoder
static void
length_encoder_reset(lzma_length_encoder *lencoder,
		const uint32_t num_pos_states, const uint32_t table_size)
{
	// NLength::CPriceTableEncoder::SetTableSize()
	lencoder->table_size = table_size;

	// NLength::CEncoder::Init()
	bit_reset(lencoder->choice);
	bit_reset(lencoder->choice2);

	for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state) {
		bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);
		bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);
	}

	bittree_reset(lencoder->high, LEN_HIGH_BITS);

	// NLength::CPriceTableEncoder::UpdateTables()
	for (size_t pos_state = 0; pos_state < num_pos_states; ++pos_state)
		lzma_length_encoder_update_table(lencoder, pos_state);

	return;
}


static void
lzma_lzma_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
	lzma_lz_encoder_end(&coder->lz, allocator);
	lzma_literal_end(&coder->literal_coder, allocator);
	lzma_free(coder, allocator);
	return;
}


extern lzma_ret
lzma_lzma_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
		const lzma_filter_info *filters)
{
	if (next->coder == NULL) {
		next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
		if (next->coder == NULL)
			return LZMA_MEM_ERROR;

		next->coder->next = LZMA_NEXT_CODER_INIT;
		next->coder->lz = LZMA_LZ_ENCODER_INIT;
		next->coder->literal_coder = NULL;
	}

	// Validate options that aren't validated elsewhere.
	const lzma_options_lzma *options = filters[0].options;
	if (options->pos_bits > LZMA_POS_BITS_MAX
			|| options->fast_bytes < LZMA_FAST_BYTES_MIN
			|| options->fast_bytes > LZMA_FAST_BYTES_MAX) {
		lzma_lzma_encoder_end(next->coder, allocator);
		return LZMA_HEADER_ERROR;
	}

	// Set compression mode.
	switch (options->mode) {
		case LZMA_MODE_FAST:
			next->coder->best_compression = false;
			break;

		case LZMA_MODE_BEST:
			next->coder->best_compression = true;
			break;

		default:
			lzma_lzma_encoder_end(next->coder, allocator);
			return LZMA_HEADER_ERROR;
	}

	// Initialize literal coder.
	{
		const lzma_ret ret = lzma_literal_init(
				&next->coder->literal_coder, allocator,
				options->literal_context_bits,
				options->literal_pos_bits);
		if (ret != LZMA_OK) {
			lzma_lzma_encoder_end(next->coder, allocator);
			return ret;
		}
	}

	// Initialize LZ encoder.
	{
		const lzma_ret ret = lzma_lz_encoder_reset(
				&next->coder->lz, allocator, &lzma_lzma_encode,
				filters[0].uncompressed_size,
				options->dictionary_size, OPTS,
				options->fast_bytes, MATCH_MAX_LEN + 1 + OPTS,
				options->match_finder,
				options->match_finder_cycles,
				options->preset_dictionary,
				options->preset_dictionary_size);
		if (ret != LZMA_OK) {
			lzma_lzma_encoder_end(next->coder, allocator);
			return ret;
		}
	}

	// Set dist_table_size.
	{
		// Round the dictionary size up to next 2^n.
		uint32_t log_size;
		for (log_size = 0; (UINT32_C(1) << log_size)
				< options->dictionary_size; ++log_size) ;

		next->coder->dist_table_size = log_size * 2;
	}

	// Misc FIXME desc
	next->coder->dictionary_size = options->dictionary_size;
	next->coder->pos_mask = (1U << options->pos_bits) - 1;
	next->coder->fast_bytes = options->fast_bytes;

	// Range coder
	rc_reset(next->coder->rc);

	// State
	next->coder->state = 0;
	next->coder->previous_byte = 0;
	for (size_t i = 0; i < REP_DISTANCES; ++i)
		next->coder->rep_distances[i] = 0;

	// Bit encoders
	for (size_t i = 0; i < STATES; ++i) {
		for (size_t j = 0; j <= next->coder->pos_mask; ++j) {
			bit_reset(next->coder->is_match[i][j]);
			bit_reset(next->coder->is_rep0_long[i][j]);
		}

		bit_reset(next->coder->is_rep[i]);
		bit_reset(next->coder->is_rep0[i]);
		bit_reset(next->coder->is_rep1[i]);
		bit_reset(next->coder->is_rep2[i]);
	}

	for (size_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
		bit_reset(next->coder->pos_encoders[i]);

	// Bit tree encoders
	for (size_t i = 0; i < LEN_TO_POS_STATES; ++i)
		bittree_reset(next->coder->pos_slot_encoder[i], POS_SLOT_BITS);

	bittree_reset(next->coder->pos_align_encoder, ALIGN_BITS);

	// Length encoders
	length_encoder_reset(&next->coder->len_encoder, 1U << options->pos_bits,
			options->fast_bytes + 1 - MATCH_MIN_LEN);

	length_encoder_reset(&next->coder->rep_match_len_encoder,
			1U << options->pos_bits,
			next->coder->fast_bytes + 1 - MATCH_MIN_LEN);

	// Misc
	next->coder->longest_match_was_found = false;
	next->coder->optimum_end_index = 0;
	next->coder->optimum_current_index = 0;
	next->coder->additional_offset = 0;

	next->coder->now_pos = 0;
	next->coder->is_initialized = false;

	// Initialize the next decoder in the chain, if any.
	{
		const lzma_ret ret = lzma_next_filter_init(&next->coder->next,
				allocator, filters + 1);
		if (ret != LZMA_OK) {
			lzma_lzma_encoder_end(next->coder, allocator);
			return ret;
		}
	}

	// Initialization successful. Set the function pointers.
	next->code = &lzma_lz_encode;
	next->end = &lzma_lzma_encoder_end;

	return LZMA_OK;
}


extern bool
lzma_lzma_encode_properties(const lzma_options_lzma *options, uint8_t *byte)
{
	if (options->literal_context_bits > LZMA_LITERAL_CONTEXT_BITS_MAX
			|| options->literal_pos_bits
				> LZMA_LITERAL_POS_BITS_MAX
			|| options->pos_bits > LZMA_POS_BITS_MAX)
		return true;

	*byte = (options->pos_bits * 5 + options->literal_pos_bits) * 9
			+ options->literal_context_bits;
	assert(*byte <= (4 * 5 + 4) * 9 + 8);

	return false;
}