aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/lzma/lzma_encoder_private.h
blob: 0feaf26a1962fb9651ec1e3d3b38576b2a33d72d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
///////////////////////////////////////////////////////////////////////////////
//
/// \file       lzma_encoder_private.h
/// \brief      Private definitions for 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.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef LZMA_LZMA_ENCODER_PRIVATE_H
#define LZMA_LZMA_ENCODER_PRIVATE_H

#include "lzma_encoder.h"
#include "lzma_common.h"
#include "lz_encoder.h"
#include "range_encoder.h"

// We need space for about two encoding loops, because there is no check
// for available buffer space before end of payload marker gets written.
// 2*26 bytes should be enough for this... but Lasse isn't very sure about
// the exact value. 64 bytes certainly is enough. :-)
#if LZMA_LZ_TEMP_SIZE < 64
#	error LZMA_LZ_TEMP_SIZE is too small.
#endif


#define move_pos(num) \
do { \
	assert((int32_t)(num) >= 0); \
	if ((num) != 0) { \
		coder->additional_offset += num; \
		coder->lz.skip(&coder->lz, num); \
	} \
} while (0)


typedef struct {
	probability choice;
	probability choice2;
	probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
	probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
	probability high[LEN_HIGH_SYMBOLS];

	uint32_t prices[POS_STATES_MAX][LEN_SYMBOLS];
	uint32_t table_size;
	uint32_t counters[POS_STATES_MAX];

} lzma_length_encoder;


typedef struct {
	lzma_lzma_state state;

	bool prev_1_is_char;
	bool prev_2;

	uint32_t pos_prev_2;
	uint32_t back_prev_2;

	uint32_t price;
	uint32_t pos_prev;  // pos_next;
	uint32_t back_prev;

	uint32_t backs[4];

} lzma_optimal;


struct lzma_coder_s {
	// Next coder in the chain
	lzma_next_coder next;

	// In window and match finder
	lzma_lz_encoder lz;

	// Range encoder
	lzma_range_encoder rc;

	// State
	lzma_lzma_state state;
	uint8_t previous_byte;
	uint32_t rep_distances[REP_DISTANCES];

	// Misc
	uint32_t match_distances[MATCH_MAX_LEN * 2 + 2 + 1];
	uint32_t num_distance_pairs;
	uint32_t additional_offset;
	uint32_t now_pos; // Lowest 32 bits are enough here.
	bool best_compression;           ///< True when LZMA_MODE_BEST is used
	bool is_initialized;

	// Literal encoder
	lzma_literal_coder *literal_coder;

	// Bit encoders
	probability is_match[STATES][POS_STATES_MAX];
	probability is_rep[STATES];
	probability is_rep0[STATES];
	probability is_rep1[STATES];
	probability is_rep2[STATES];
	probability is_rep0_long[STATES][POS_STATES_MAX];
	probability pos_encoders[FULL_DISTANCES - END_POS_MODEL_INDEX];

	// Bit Tree Encoders
	probability pos_slot_encoder[LEN_TO_POS_STATES][1 << POS_SLOT_BITS];
	probability pos_align_encoder[1 << ALIGN_BITS];

	// Length encoders
	lzma_length_encoder match_len_encoder;
	lzma_length_encoder rep_len_encoder;

	// Optimal
	lzma_optimal optimum[OPTS];
	uint32_t optimum_end_index;
	uint32_t optimum_current_index;
	uint32_t longest_match_length;
	bool longest_match_was_found;

	// Prices
	uint32_t pos_slot_prices[LEN_TO_POS_STATES][DIST_TABLE_SIZE_MAX];
	uint32_t distances_prices[LEN_TO_POS_STATES][FULL_DISTANCES];
	uint32_t align_prices[ALIGN_TABLE_SIZE];
	uint32_t align_price_count;
	uint32_t dist_table_size;
	uint32_t match_price_count;

	// LZMA specific settings
	uint32_t dictionary_size;        ///< Size in bytes
	uint32_t fast_bytes;
	uint32_t pos_state_bits;
	uint32_t pos_mask;         ///< (1 << pos_state_bits) - 1
};


extern void lzma_length_encoder_update_table(lzma_length_encoder *lencoder,
		const uint32_t pos_state);

extern bool lzma_lzma_encode(lzma_coder *coder, uint8_t *restrict out,
		size_t *restrict out_pos, size_t out_size);

extern void lzma_get_optimum(lzma_coder *restrict coder,
		uint32_t *restrict back_res, uint32_t *restrict len_res);

extern void lzma_get_optimum_fast(lzma_coder *restrict coder,
		uint32_t *restrict back_res, uint32_t *restrict len_res);


// NOTE: Don't add 'restrict'.
static inline void
lzma_read_match_distances(lzma_coder *coder,
		uint32_t *len_res, uint32_t *num_distance_pairs)
{
	*len_res = 0;

	coder->lz.get_matches(&coder->lz, coder->match_distances);

	*num_distance_pairs = coder->match_distances[0];

	if (*num_distance_pairs > 0) {
		*len_res = coder->match_distances[*num_distance_pairs - 1];
		assert(*len_res <= MATCH_MAX_LEN);

		if (*len_res == coder->fast_bytes) {
			uint32_t offset = *len_res - 1;
			const uint32_t distance = coder->match_distances[
					*num_distance_pairs] + 1;
			uint32_t limit = MATCH_MAX_LEN - *len_res;

			assert(offset + limit < coder->lz.keep_size_after);
			assert(coder->lz.read_pos <= coder->lz.write_pos);

			// If we are close to end of the stream, we may need
			// to limit the length of the match.
			if (coder->lz.write_pos - coder->lz.read_pos
					< offset + limit)
				limit = coder->lz.write_pos
					- (coder->lz.read_pos + offset);

			offset += coder->lz.read_pos;
			uint32_t i = 0;
			while (i < limit && coder->lz.buffer[offset + i]
					== coder->lz.buffer[
						offset + i - distance])
				++i;

			*len_res += i;
		}
	}

	++coder->additional_offset;

	return;
}

#endif