1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync// LzmaEncoder.cs
2baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
3baa3858d3f5d128a5c8466b700098109edcad5f2repo syncusing System;
4baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
5baa3858d3f5d128a5c8466b700098109edcad5f2repo syncnamespace SevenZip.Compression.LZMA
6baa3858d3f5d128a5c8466b700098109edcad5f2repo sync{
7baa3858d3f5d128a5c8466b700098109edcad5f2repo sync	using RangeCoder;
8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync	public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
10baa3858d3f5d128a5c8466b700098109edcad5f2repo sync	{
11baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		enum EMatchFinderType
12baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			BT2,
14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			BT4,
15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		};
16baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		const UInt32 kIfinityPrice = 0xFFFFFFF;
18baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
19baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		static Byte[] g_FastPos = new Byte[1 << 11];
20baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
21baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		static Encoder()
22baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
23baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			const Byte kFastSlots = 22;
24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			int c = 2;
25baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			g_FastPos[0] = 0;
26baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			g_FastPos[1] = 1;
27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1));
30baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (UInt32 j = 0; j < k; j++, c++)
31baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					g_FastPos[c] = slotFast;
32baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
33baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
34baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		static UInt32 GetPosSlot(UInt32 pos)
36baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
37baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (pos < (1 << 11))
38baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return g_FastPos[pos];
39baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (pos < (1 << 21))
40baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return (UInt32)(g_FastPos[pos >> 10] + 20);
41baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return (UInt32)(g_FastPos[pos >> 20] + 40);
42baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
43baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
44baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		static UInt32 GetPosSlot2(UInt32 pos)
45baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
46baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (pos < (1 << 17))
47baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return (UInt32)(g_FastPos[pos >> 6] + 12);
48baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (pos < (1 << 27))
49baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return (UInt32)(g_FastPos[pos >> 16] + 32);
50baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return (UInt32)(g_FastPos[pos >> 26] + 52);
51baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
52baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
53baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		Base.State _state = new Base.State();
54baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		Byte _previousByte;
55baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] _repDistances = new UInt32[Base.kNumRepDistances];
56baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
57baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void BaseInit()
58baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
59baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_state.Init();
60baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_previousByte = 0;
61baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (UInt32 i = 0; i < Base.kNumRepDistances; i++)
62baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_repDistances[i] = 0;
63baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
64baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
65baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		const int kDefaultDictionaryLogSize = 22;
66baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		const UInt32 kNumFastBytesDefault = 0x20;
67baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
68baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		class LiteralEncoder
69baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
70baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public struct Encoder2
71baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
72baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				BitEncoder[] m_Encoders;
73baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
74baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				public void Create() { m_Encoders = new BitEncoder[0x300]; }
75baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
76baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); }
77baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
78baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol)
79baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
80baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					uint context = 1;
81baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					for (int i = 7; i >= 0; i--)
82baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
83baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						uint bit = (uint)((symbol >> i) & 1);
84baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						m_Encoders[context].Encode(rangeEncoder, bit);
85baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						context = (context << 1) | bit;
86baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
87baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
88baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
89baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)
90baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
91baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					uint context = 1;
92baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					bool same = true;
93baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					for (int i = 7; i >= 0; i--)
94baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
95baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						uint bit = (uint)((symbol >> i) & 1);
96baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						uint state = context;
97baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (same)
98baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
99baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							uint matchBit = (uint)((matchByte >> i) & 1);
100baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state += ((1 + matchBit) << 8);
101baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							same = (matchBit == bit);
102baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
103baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						m_Encoders[state].Encode(rangeEncoder, bit);
104baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						context = (context << 1) | bit;
105baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
106baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
107baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
108baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				public uint GetPrice(bool matchMode, byte matchByte, byte symbol)
109baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
110baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					uint price = 0;
111baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					uint context = 1;
112baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					int i = 7;
113baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (matchMode)
114baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
115baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						for (; i >= 0; i--)
116baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
117baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							uint matchBit = (uint)(matchByte >> i) & 1;
118baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							uint bit = (uint)(symbol >> i) & 1;
119baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit);
120baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							context = (context << 1) | bit;
121baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (matchBit != bit)
122baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
123baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								i--;
124baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								break;
125baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
126baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
127baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
128baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					for (; i >= 0; i--)
129baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
130baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						uint bit = (uint)(symbol >> i) & 1;
131baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						price += m_Encoders[context].GetPrice(bit);
132baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						context = (context << 1) | bit;
133baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
134baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					return price;
135baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
136baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
137baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
138baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Encoder2[] m_Coders;
139baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			int m_NumPrevBits;
140baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			int m_NumPosBits;
141baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			uint m_PosMask;
142baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
143baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void Create(int numPosBits, int numPrevBits)
144baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
145baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
146baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					return;
147baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				m_NumPosBits = numPosBits;
148baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				m_PosMask = ((uint)1 << numPosBits) - 1;
149baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				m_NumPrevBits = numPrevBits;
150baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
151baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				m_Coders = new Encoder2[numStates];
152baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (uint i = 0; i < numStates; i++)
153baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					m_Coders[i].Create();
154baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
155baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
156baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void Init()
157baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
158baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
159baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (uint i = 0; i < numStates; i++)
160baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					m_Coders[i].Init();
161baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
162baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
163baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte)
164baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{ return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; }
165baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
166baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
167baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		class LenEncoder
168baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
169baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder();
170baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder();
171baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
172baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
173baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits);
174baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
175baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public LenEncoder()
176baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
177baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
178baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
179baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits);
180baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits);
181baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
182baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
183baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
184baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void Init(UInt32 numPosStates)
185baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
186baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_choice.Init();
187baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_choice2.Init();
188baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (UInt32 posState = 0; posState < numPosStates; posState++)
189baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
190baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_lowCoder[posState].Init();
191baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_midCoder[posState].Init();
192baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
193baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_highCoder.Init();
194baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
195baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
196baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
197baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
198baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (symbol < Base.kNumLowLenSymbols)
199baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
200baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_choice.Encode(rangeEncoder, 0);
201baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_lowCoder[posState].Encode(rangeEncoder, symbol);
202baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
203baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				else
204baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
205baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					symbol -= Base.kNumLowLenSymbols;
206baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_choice.Encode(rangeEncoder, 1);
207baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (symbol < Base.kNumMidLenSymbols)
208baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
209baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_choice2.Encode(rangeEncoder, 0);
210baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_midCoder[posState].Encode(rangeEncoder, symbol);
211baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
212baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
213baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
214baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_choice2.Encode(rangeEncoder, 1);
215baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
216baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
217baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
218baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
219baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
220baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st)
221baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
222baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 a0 = _choice.GetPrice0();
223baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 a1 = _choice.GetPrice1();
224baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 b0 = a1 + _choice2.GetPrice0();
225baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 b1 = a1 + _choice2.GetPrice1();
226baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 i = 0;
227baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (i = 0; i < Base.kNumLowLenSymbols; i++)
228baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
229baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (i >= numSymbols)
230baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						return;
231baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
232baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
233baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
234baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
235baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (i >= numSymbols)
236baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						return;
237baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
238baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
239baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (; i < numSymbols; i++)
240baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
241baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
242baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		};
243baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
244baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
245baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
246baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		class LenPriceTableEncoder : LenEncoder
247baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
248baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax];
249baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 _tableSize;
250baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax];
251baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
252baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
253baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
254baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 GetPrice(UInt32 symbol, UInt32 posState)
255baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
256baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return _prices[posState * Base.kNumLenSymbols + symbol];
257baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
258baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
259baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			void UpdateTable(UInt32 posState)
260baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
261baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
262baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_counters[posState] = _tableSize;
263baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
264baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
265baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void UpdateTables(UInt32 numPosStates)
266baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
267baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (UInt32 posState = 0; posState < numPosStates; posState++)
268baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UpdateTable(posState);
269baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
270baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
271baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
272baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
273baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				base.Encode(rangeEncoder, symbol, posState);
274baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (--_counters[posState] == 0)
275baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UpdateTable(posState);
276baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
277baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
278baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
279baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		const UInt32 kNumOpts = 1 << 12;
280baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		class Optimal
281baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
282baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public Base.State State;
283baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
284baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public bool Prev1IsChar;
285baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public bool Prev2;
286baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
287baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 PosPrev2;
288baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 BackPrev2;
289baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
290baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 Price;
291baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 PosPrev;
292baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 BackPrev;
293baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
294baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 Backs0;
295baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 Backs1;
296baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 Backs2;
297baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public UInt32 Backs3;
298baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
299baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; }
300baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
301baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			public bool IsShortRep() { return (BackPrev == 0); }
302baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		};
303baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		Optimal[] _optimum = new Optimal[kNumOpts];
304baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		LZ.IMatchFinder _matchFinder = null;
305baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder();
306baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
307baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
308baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates];
309baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates];
310baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates];
311baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates];
312baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
313baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
314baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates];
315baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
316baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
317baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits);
318baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
319baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
320baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
321baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
322baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		LiteralEncoder _literalEncoder = new LiteralEncoder();
323baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
324baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2];
325baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
326baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _numFastBytes = kNumFastBytesDefault;
327baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _longestMatchLength;
328baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _numDistancePairs;
329baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
330baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _additionalOffset;
331baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
332baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _optimumEndIndex;
333baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _optimumCurrentIndex;
334baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
335baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		bool _longestMatchWasFound;
336baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
337baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)];
338baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits];
339baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize];
340baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _alignPriceCount;
341baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
342baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2);
343baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
344baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		int _posStateBits = 2;
345baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _posStateMask = (4 - 1);
346baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		int _numLiteralPosStateBits = 0;
347baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		int _numLiteralContextBits = 3;
348baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
349baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize);
350baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _dictionarySizePrev = 0xFFFFFFFF;
351baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _numFastBytesPrev = 0xFFFFFFFF;
352baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
353baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		Int64 nowPos64;
354baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		bool _finished;
355baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		System.IO.Stream _inStream;
356baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
357baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		EMatchFinderType _matchFinderType = EMatchFinderType.BT4;
358baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		bool _writeEndMark = false;
359baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
360baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		bool _needReleaseMFStream;
361baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
362baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void Create()
363baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
364baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_matchFinder == null)
365baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
366baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				LZ.BinTree bt = new LZ.BinTree();
367baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				int numHashBytes = 4;
368baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (_matchFinderType == EMatchFinderType.BT2)
369baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					numHashBytes = 2;
370baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				bt.SetType(numHashBytes);
371baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_matchFinder = bt;
372baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
373baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
374baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
375baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
376baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return;
377baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
378baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_dictionarySizePrev = _dictionarySize;
379baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_numFastBytesPrev = _numFastBytes;
380baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
381baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
382baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		public Encoder()
383baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
384baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (int i = 0; i < kNumOpts; i++)
385baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[i] = new Optimal();
386baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (int i = 0; i < Base.kNumLenToPosStates; i++)
387baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits);
388baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
389baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
390baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void SetWriteEndMarkerMode(bool writeEndMarker)
391baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
392baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_writeEndMark = writeEndMarker;
393baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
394baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
395baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void Init()
396baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
397baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			BaseInit();
398baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_rangeEncoder.Init();
399baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
400baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			uint i;
401baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (i = 0; i < Base.kNumStates; i++)
402baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
403baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (uint j = 0; j <= _posStateMask; j++)
404baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
405baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					uint complexState = (i << Base.kNumPosStatesBitsMax) + j;
406baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_isMatch[complexState].Init();
407baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_isRep0Long[complexState].Init();
408baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
409baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_isRep[i].Init();
410baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_isRepG0[i].Init();
411baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_isRepG1[i].Init();
412baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_isRepG2[i].Init();
413baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
414baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_literalEncoder.Init();
415baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (i = 0; i < Base.kNumLenToPosStates; i++)
416baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_posSlotEncoder[i].Init();
417baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
418baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_posEncoders[i].Init();
419baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
420baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_lenEncoder.Init((UInt32)1 << _posStateBits);
421baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_repMatchLenEncoder.Init((UInt32)1 << _posStateBits);
422baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
423baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_posAlignEncoder.Init();
424baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
425baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_longestMatchWasFound = false;
426baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimumEndIndex = 0;
427baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimumCurrentIndex = 0;
428baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_additionalOffset = 0;
429baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
430baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
431baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs)
432baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
433baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			lenRes = 0;
434baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			numDistancePairs = _matchFinder.GetMatches(_matchDistances);
435baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (numDistancePairs > 0)
436baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
437baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				lenRes = _matchDistances[numDistancePairs - 2];
438baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (lenRes == _numFastBytes)
439baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1],
440baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Base.kMatchMaxLen - lenRes);
441baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
442baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_additionalOffset++;
443baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
444baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
445baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
446baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void MovePos(UInt32 num)
447baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
448baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (num > 0)
449baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
450baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_matchFinder.Skip(num);
451baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_additionalOffset += num;
452baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
453baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
454baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
455baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 GetRepLen1Price(Base.State state, UInt32 posState)
456baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
457baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return _isRepG0[state.Index].GetPrice0() +
458baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0();
459baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
460baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
461baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState)
462baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
463baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 price;
464baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (repIndex == 0)
465baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
466baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				price = _isRepG0[state.Index].GetPrice0();
467baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
468baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
469baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			else
470baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
471baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				price = _isRepG0[state.Index].GetPrice1();
472baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (repIndex == 1)
473baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					price += _isRepG1[state.Index].GetPrice0();
474baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				else
475baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
476baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					price += _isRepG1[state.Index].GetPrice1();
477baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					price += _isRepG2[state.Index].GetPrice(repIndex - 2);
478baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
479baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
480baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return price;
481baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
482baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
483baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState)
484baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
485baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
486baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return price + GetPureRepPrice(repIndex, state, posState);
487baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
488baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
489baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState)
490baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
491baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 price;
492baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 lenToPosState = Base.GetLenToPosState(len);
493baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (pos < Base.kNumFullDistances)
494baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
495baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			else
496baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
497baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_alignPrices[pos & Base.kAlignMask];
498baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
499baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
500baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
501baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 Backward(out UInt32 backRes, UInt32 cur)
502baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
503baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimumEndIndex = cur;
504baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 posMem = _optimum[cur].PosPrev;
505baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 backMem = _optimum[cur].BackPrev;
506baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			do
507baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
508baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (_optimum[cur].Prev1IsChar)
509baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
510baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_optimum[posMem].MakeAsChar();
511baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_optimum[posMem].PosPrev = posMem - 1;
512baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_optimum[cur].Prev2)
513baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
514baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_optimum[posMem - 1].Prev1IsChar = false;
515baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
516baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
517baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
518baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
519baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 posPrev = posMem;
520baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 backCur = backMem;
521baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
522baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backMem = _optimum[posPrev].BackPrev;
523baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				posMem = _optimum[posPrev].PosPrev;
524baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
525baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[posPrev].BackPrev = backCur;
526baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[posPrev].PosPrev = cur;
527baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				cur = posPrev;
528baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
529baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			while (cur > 0);
530baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			backRes = _optimum[0].BackPrev;
531baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimumCurrentIndex = _optimum[0].PosPrev;
532baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return _optimumCurrentIndex;
533baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
534baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
535baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] reps = new UInt32[Base.kNumRepDistances];
536baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] repLens = new UInt32[Base.kNumRepDistances];
537baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
538baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
539baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 GetOptimum(UInt32 position, out UInt32 backRes)
540baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
541baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_optimumEndIndex != _optimumCurrentIndex)
542baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
543baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
544baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backRes = _optimum[_optimumCurrentIndex].BackPrev;
545baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
546baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return lenRes;
547baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
548baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimumCurrentIndex = _optimumEndIndex = 0;
549baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
550baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 lenMain, numDistancePairs;
551baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (!_longestMatchWasFound)
552baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
553baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				ReadMatchDistances(out lenMain, out numDistancePairs);
554baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
555baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			else
556baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
557baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				lenMain = _longestMatchLength;
558baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				numDistancePairs = _numDistancePairs;
559baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_longestMatchWasFound = false;
560baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
561baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
562baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
563baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (numAvailableBytes < 2)
564baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
565baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backRes = 0xFFFFFFFF;
566baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return 1;
567baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
568baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (numAvailableBytes > Base.kMatchMaxLen)
569baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				numAvailableBytes = Base.kMatchMaxLen;
570baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
571baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 repMaxIndex = 0;
572baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 i;
573baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (i = 0; i < Base.kNumRepDistances; i++)
574baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
575baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				reps[i] = _repDistances[i];
576baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
577baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (repLens[i] > repLens[repMaxIndex])
578baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					repMaxIndex = i;
579baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
580baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (repLens[repMaxIndex] >= _numFastBytes)
581baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
582baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backRes = repMaxIndex;
583baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 lenRes = repLens[repMaxIndex];
584baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				MovePos(lenRes - 1);
585baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return lenRes;
586baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
587baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
588baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (lenMain >= _numFastBytes)
589baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
590baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
591baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				MovePos(lenMain - 1);
592baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return lenMain;
593baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
594baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
595baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Byte currentByte = _matchFinder.GetIndexByte(0 - 1);
596baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1));
597baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
598baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
599baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
600baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backRes = (UInt32)0xFFFFFFFF;
601baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return 1;
602baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
603baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
604baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[0].State = _state;
605baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
606baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 posState = (position & _posStateMask);
607baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
608baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[1].Price = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
609baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), matchByte, currentByte);
610baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[1].MakeAsChar();
611baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
612baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
613baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
614baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
615baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (matchByte == currentByte)
616baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
617baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
618baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (shortRepPrice < _optimum[1].Price)
619baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
620baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_optimum[1].Price = shortRepPrice;
621baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_optimum[1].MakeAsShortRep();
622baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
623baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
624baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
625baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
626baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
627baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if(lenEnd < 2)
628baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
629baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				backRes = _optimum[1].BackPrev;
630baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return 1;
631baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
632baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
633baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[1].PosPrev = 0;
634baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
635baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[0].Backs0 = reps[0];
636baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[0].Backs1 = reps[1];
637baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[0].Backs2 = reps[2];
638baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_optimum[0].Backs3 = reps[3];
639baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
640baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 len = lenEnd;
641baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			do
642baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[len--].Price = kIfinityPrice;
643baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			while (len >= 2);
644baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
645baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (i = 0; i < Base.kNumRepDistances; i++)
646baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
647baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 repLen = repLens[i];
648baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (repLen < 2)
649baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					continue;
650baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
651baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				do
652baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
653baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
654baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Optimal optimum = _optimum[repLen];
655baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (curAndLenPrice < optimum.Price)
656baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
657baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.Price = curAndLenPrice;
658baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.PosPrev = 0;
659baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.BackPrev = i;
660baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.Prev1IsChar = false;
661baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
662baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
663baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				while (--repLen >= 2);
664baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
665baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
666baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
667baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
668baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
669baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (len <= lenMain)
670baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
671baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 offs = 0;
672baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				while (len > _matchDistances[offs])
673baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					offs += 2;
674baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (; ; len++)
675baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
676baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 distance = _matchDistances[offs + 1];
677baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
678baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Optimal optimum = _optimum[len];
679baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (curAndLenPrice < optimum.Price)
680baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
681baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.Price = curAndLenPrice;
682baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.PosPrev = 0;
683baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.BackPrev = distance + Base.kNumRepDistances;
684baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						optimum.Prev1IsChar = false;
685baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
686baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (len == _matchDistances[offs])
687baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
688baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						offs += 2;
689baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (offs == numDistancePairs)
690baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							break;
691baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
692baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
693baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
694baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
695baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 cur = 0;
696baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
697baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			while (true)
698baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
699baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				cur++;
700baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (cur == lenEnd)
701baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					return Backward(out backRes, cur);
702baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 newLen;
703baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				ReadMatchDistances(out newLen, out numDistancePairs);
704baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (newLen >= _numFastBytes)
705baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
706baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_numDistancePairs = numDistancePairs;
707baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_longestMatchLength = newLen;
708baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_longestMatchWasFound = true;
709baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					return Backward(out backRes, cur);
710baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
711baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				position++;
712baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 posPrev = _optimum[cur].PosPrev;
713baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				Base.State state;
714baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (_optimum[cur].Prev1IsChar)
715baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
716baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					posPrev--;
717baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_optimum[cur].Prev2)
718baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
719baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						state = _optimum[_optimum[cur].PosPrev2].State;
720baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
721baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state.UpdateRep();
722baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else
723baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state.UpdateMatch();
724baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
725baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
726baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						state = _optimum[posPrev].State;
727baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					state.UpdateChar();
728baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
729baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				else
730baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					state = _optimum[posPrev].State;
731baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (posPrev == cur - 1)
732baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
733baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_optimum[cur].IsShortRep())
734baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						state.UpdateShortRep();
735baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
736baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						state.UpdateChar();
737baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
738baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				else
739baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
740baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 pos;
741baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
742baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
743baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						posPrev = _optimum[cur].PosPrev2;
744baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						pos = _optimum[cur].BackPrev2;
745baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						state.UpdateRep();
746baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
747baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
748baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
749baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						pos = _optimum[cur].BackPrev;
750baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (pos < Base.kNumRepDistances)
751baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state.UpdateRep();
752baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else
753baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state.UpdateMatch();
754baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
755baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Optimal opt = _optimum[posPrev];
756baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (pos < Base.kNumRepDistances)
757baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
758baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (pos == 0)
759baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
760baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[0] = opt.Backs0;
761baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[1] = opt.Backs1;
762baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[2] = opt.Backs2;
763baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[3] = opt.Backs3;
764baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
765baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else if (pos == 1)
766baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
767baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[0] = opt.Backs1;
768baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[1] = opt.Backs0;
769baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[2] = opt.Backs2;
770baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[3] = opt.Backs3;
771baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
772baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else if (pos == 2)
773baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
774baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[0] = opt.Backs2;
775baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[1] = opt.Backs0;
776baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[2] = opt.Backs1;
777baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[3] = opt.Backs3;
778baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
779baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else
780baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
781baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[0] = opt.Backs3;
782baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[1] = opt.Backs0;
783baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[2] = opt.Backs1;
784baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							reps[3] = opt.Backs2;
785baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
786baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
787baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
788baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
789baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						reps[0] = (pos - Base.kNumRepDistances);
790baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						reps[1] = opt.Backs0;
791baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						reps[2] = opt.Backs1;
792baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						reps[3] = opt.Backs2;
793baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
794baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
795baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[cur].State = state;
796baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[cur].Backs0 = reps[0];
797baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[cur].Backs1 = reps[1];
798baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[cur].Backs2 = reps[2];
799baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_optimum[cur].Backs3 = reps[3];
800baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 curPrice = _optimum[cur].Price;
801baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
802baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				currentByte = _matchFinder.GetIndexByte(0 - 1);
803baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1));
804baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
805baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				posState = (position & _posStateMask);
806baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
807baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 curAnd1Price = curPrice +
808baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
809baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
810baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					GetPrice(!state.IsCharState(), matchByte, currentByte);
811baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
812baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				Optimal nextOptimum = _optimum[cur + 1];
813baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
814baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				bool nextIsChar = false;
815baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (curAnd1Price < nextOptimum.Price)
816baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
817baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					nextOptimum.Price = curAnd1Price;
818baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					nextOptimum.PosPrev = cur;
819baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					nextOptimum.MakeAsChar();
820baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					nextIsChar = true;
821baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
822baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
823baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
824baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
825baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
826baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (matchByte == currentByte &&
827baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					!(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
828baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
829baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
830baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (shortRepPrice <= nextOptimum.Price)
831baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
832baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						nextOptimum.Price = shortRepPrice;
833baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						nextOptimum.PosPrev = cur;
834baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						nextOptimum.MakeAsShortRep();
835baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						nextIsChar = true;
836baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
837baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
838baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
839baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
840baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull);
841baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				numAvailableBytes = numAvailableBytesFull;
842baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
843baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (numAvailableBytes < 2)
844baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					continue;
845baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (numAvailableBytes > _numFastBytes)
846baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					numAvailableBytes = _numFastBytes;
847baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (!nextIsChar && matchByte != currentByte)
848baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
849baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					// try Literal + rep0
850baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes);
851baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
852baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (lenTest2 >= 2)
853baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
854baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Base.State state2 = state;
855baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						state2.UpdateChar();
856baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 posStateNext = (position + 1) & _posStateMask;
857baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 nextRepMatchPrice = curAnd1Price +
858baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() +
859baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_isRep[state2.Index].GetPrice1();
860baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
861baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 offset = cur + 1 + lenTest2;
862baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							while (lenEnd < offset)
863baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_optimum[++lenEnd].Price = kIfinityPrice;
864baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
865baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								0, lenTest2, state2, posStateNext);
866baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							Optimal optimum = _optimum[offset];
867baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (curAndLenPrice < optimum.Price)
868baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
869baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								optimum.Price = curAndLenPrice;
870baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								optimum.PosPrev = cur + 1;
871baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								optimum.BackPrev = 0;
872baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								optimum.Prev1IsChar = true;
873baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								optimum.Prev2 = false;
874baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
875baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
876baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
877baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
878baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
879baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 startLen = 2; // speed optimization
880baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
881baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (UInt32 repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
882baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
883baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
884baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (lenTest < 2)
885baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						continue;
886baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 lenTestTemp = lenTest;
887baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					do
888baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
889baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						while (lenEnd < cur + lenTest)
890baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_optimum[++lenEnd].Price = kIfinityPrice;
891baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
892baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Optimal optimum = _optimum[cur + lenTest];
893baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (curAndLenPrice < optimum.Price)
894baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
895baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.Price = curAndLenPrice;
896baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.PosPrev = cur;
897baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.BackPrev = repIndex;
898baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.Prev1IsChar = false;
899baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
900baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
901baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					while(--lenTest >= 2);
902baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					lenTest = lenTestTemp;
903baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
904baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (repIndex == 0)
905baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						startLen = lenTest + 1;
906baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
907baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					// if (_maxMode)
908baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (lenTest < numAvailableBytesFull)
909baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
910baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
911baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t);
912baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (lenTest2 >= 2)
913baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
914baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							Base.State state2 = state;
915baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state2.UpdateRep();
916baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 posStateNext = (position + lenTest) & _posStateMask;
917baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 curAndLenCharPrice =
918baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
919baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									_isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
920baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									_literalEncoder.GetSubCoder(position + lenTest,
921baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									_matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true,
922baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									_matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))),
923baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									_matchFinder.GetIndexByte((Int32)lenTest - 1));
924baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							state2.UpdateChar();
925baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							posStateNext = (position + lenTest + 1) & _posStateMask;
926baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
927baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
928baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
929baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							// for(; lenTest2 >= 2; lenTest2--)
930baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
931baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								UInt32 offset = lenTest + 1 + lenTest2;
932baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								while(lenEnd < cur + offset)
933baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									_optimum[++lenEnd].Price = kIfinityPrice;
934baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
935baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								Optimal optimum = _optimum[cur + offset];
936baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								if (curAndLenPrice < optimum.Price)
937baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								{
938baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.Price = curAndLenPrice;
939baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.PosPrev = cur + lenTest + 1;
940baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.BackPrev = 0;
941baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.Prev1IsChar = true;
942baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.Prev2 = true;
943baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.PosPrev2 = cur;
944baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum.BackPrev2 = repIndex;
945baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								}
946baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
947baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
948baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
949baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
950baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
951baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (newLen > numAvailableBytes)
952baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
953baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					newLen = numAvailableBytes;
954baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
955baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_matchDistances[numDistancePairs] = newLen;
956baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					numDistancePairs += 2;
957baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
958baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (newLen >= startLen)
959baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
960baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
961baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					while (lenEnd < cur + newLen)
962baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_optimum[++lenEnd].Price = kIfinityPrice;
963baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
964baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					UInt32 offs = 0;
965baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					while (startLen > _matchDistances[offs])
966baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						offs += 2;
967baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
968baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					for (UInt32 lenTest = startLen; ; lenTest++)
969baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
970baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 curBack = _matchDistances[offs + 1];
971baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
972baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Optimal optimum = _optimum[cur + lenTest];
973baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (curAndLenPrice < optimum.Price)
974baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
975baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.Price = curAndLenPrice;
976baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.PosPrev = cur;
977baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.BackPrev = curBack + Base.kNumRepDistances;
978baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							optimum.Prev1IsChar = false;
979baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
980baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
981baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (lenTest == _matchDistances[offs])
982baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
983baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (lenTest < numAvailableBytesFull)
984baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
985baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
986baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t);
987baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								if (lenTest2 >= 2)
988baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								{
989baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									Base.State state2 = state;
990baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									state2.UpdateMatch();
991baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									UInt32 posStateNext = (position + lenTest) & _posStateMask;
992baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									UInt32 curAndLenCharPrice = curAndLenPrice +
993baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										_isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
994baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										_literalEncoder.GetSubCoder(position + lenTest,
995baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										_matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).
996baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										GetPrice(true,
997baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										_matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1),
998baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										_matchFinder.GetIndexByte((Int32)lenTest - 1));
999baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									state2.UpdateChar();
1000baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									posStateNext = (position + lenTest + 1) & _posStateMask;
1001baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
1002baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
1003baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1004baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									UInt32 offset = lenTest + 1 + lenTest2;
1005baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									while (lenEnd < cur + offset)
1006baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										_optimum[++lenEnd].Price = kIfinityPrice;
1007baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
1008baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									optimum = _optimum[cur + offset];
1009baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									if (curAndLenPrice < optimum.Price)
1010baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									{
1011baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.Price = curAndLenPrice;
1012baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.PosPrev = cur + lenTest + 1;
1013baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.BackPrev = 0;
1014baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.Prev1IsChar = true;
1015baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.Prev2 = true;
1016baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.PosPrev2 = cur;
1017baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										optimum.BackPrev2 = curBack + Base.kNumRepDistances;
1018baa3858d3f5d128a5c8466b700098109edcad5f2repo sync									}
1019baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								}
1020baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
1021baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							offs += 2;
1022baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (offs == numDistancePairs)
1023baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								break;
1024baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
1025baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1026baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1027baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1028baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1029baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1030baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		bool ChangePair(UInt32 smallDist, UInt32 bigDist)
1031baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1032baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			const int kDif = 7;
1033baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif));
1034baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1035baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1036baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void WriteEndMarker(UInt32 posState)
1037baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1038baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (!_writeEndMark)
1039baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return;
1040baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1041baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 1);
1042baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_isRep[_state.Index].Encode(_rangeEncoder, 0);
1043baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_state.UpdateMatch();
1044baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 len = Base.kMatchMinLen;
1045baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1046baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 posSlot = (1 << Base.kNumPosSlotBits) - 1;
1047baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 lenToPosState = Base.GetLenToPosState(len);
1048baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
1049baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			int footerBits = 30;
1050baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			UInt32 posReduced = (((UInt32)1) << footerBits) - 1;
1051baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
1052baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
1053baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1054baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1055baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void Flush(UInt32 nowPos)
1056baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1057baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			ReleaseMFStream();
1058baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			WriteEndMarker(nowPos & _posStateMask);
1059baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_rangeEncoder.FlushData();
1060baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_rangeEncoder.FlushStream();
1061baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1062baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1063baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished)
1064baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1065baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			inSize = 0;
1066baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			outSize = 0;
1067baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			finished = true;
1068baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1069baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_inStream != null)
1070baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1071baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_matchFinder.SetStream(_inStream);
1072baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_matchFinder.Init();
1073baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_needReleaseMFStream = true;
1074baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_inStream = null;
1075baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (_trainSize > 0)
1076baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_matchFinder.Skip(_trainSize);
1077baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1078baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1079baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_finished)
1080baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return;
1081baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_finished = true;
1082baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1083baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1084baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Int64 progressPosValuePrev = nowPos64;
1085baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (nowPos64 == 0)
1086baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1087baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (_matchFinder.GetNumAvailableBytes() == 0)
1088baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
1089baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Flush((UInt32)nowPos64);
1090baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					return;
1091baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1092baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 len, numDistancePairs; // it's not used
1093baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				ReadMatchDistances(out len, out numDistancePairs);
1094baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 posState = (UInt32)(nowPos64) & _posStateMask;
1095baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0);
1096baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_state.UpdateChar();
1097baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
1098baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
1099baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_previousByte = curByte;
1100baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_additionalOffset--;
1101baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				nowPos64++;
1102baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1103baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_matchFinder.GetNumAvailableBytes() == 0)
1104baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1105baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				Flush((UInt32)nowPos64);
1106baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				return;
1107baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1108baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			while (true)
1109baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1110baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 pos;
1111baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 len = GetOptimum((UInt32)nowPos64, out pos);
1112baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1113baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 posState = ((UInt32)nowPos64) & _posStateMask;
1114baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState;
1115baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (len == 1 && pos == 0xFFFFFFFF)
1116baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
1117baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_isMatch[complexState].Encode(_rangeEncoder, 0);
1118baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
1119baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte);
1120baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (!_state.IsCharState())
1121baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1122baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset));
1123baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
1124baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1125baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
1126baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						subCoder.Encode(_rangeEncoder, curByte);
1127baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_previousByte = curByte;
1128baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_state.UpdateChar();
1129baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1130baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				else
1131baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
1132baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_isMatch[complexState].Encode(_rangeEncoder, 1);
1133baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (pos < Base.kNumRepDistances)
1134baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1135baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_isRep[_state.Index].Encode(_rangeEncoder, 1);
1136baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (pos == 0)
1137baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
1138baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_isRepG0[_state.Index].Encode(_rangeEncoder, 0);
1139baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (len == 1)
1140baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_isRep0Long[complexState].Encode(_rangeEncoder, 0);
1141baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							else
1142baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_isRep0Long[complexState].Encode(_rangeEncoder, 1);
1143baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
1144baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else
1145baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
1146baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_isRepG0[_state.Index].Encode(_rangeEncoder, 1);
1147baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (pos == 1)
1148baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_isRepG1[_state.Index].Encode(_rangeEncoder, 0);
1149baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							else
1150baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
1151baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_isRepG1[_state.Index].Encode(_rangeEncoder, 1);
1152baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_isRepG2[_state.Index].Encode(_rangeEncoder, pos - 2);
1153baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
1154baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
1155baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (len == 1)
1156baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_state.UpdateShortRep();
1157baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						else
1158baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
1159baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1160baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_state.UpdateRep();
1161baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
1162baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 distance = _repDistances[pos];
1163baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (pos != 0)
1164baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
1165baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							for (UInt32 i = pos; i >= 1; i--)
1166baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_repDistances[i] = _repDistances[i - 1];
1167baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_repDistances[0] = distance;
1168baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
1169baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1170baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					else
1171baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1172baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_isRep[_state.Index].Encode(_rangeEncoder, 0);
1173baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_state.UpdateMatch();
1174baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1175baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						pos -= Base.kNumRepDistances;
1176baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 posSlot = GetPosSlot(pos);
1177baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 lenToPosState = Base.GetLenToPosState(len);
1178baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
1179baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1180baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (posSlot >= Base.kStartPosModelIndex)
1181baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						{
1182baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							int footerBits = (int)((posSlot >> 1) - 1);
1183baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
1184baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							UInt32 posReduced = pos - baseVal;
1185baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1186baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (posSlot < Base.kEndPosModelIndex)
1187baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders,
1188baa3858d3f5d128a5c8466b700098109edcad5f2repo sync										baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
1189baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							else
1190baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
1191baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
1192baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
1193baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								_alignPriceCount++;
1194baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
1195baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						}
1196baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						UInt32 distance = pos;
1197baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--)
1198baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_repDistances[i] = _repDistances[i - 1];
1199baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_repDistances[0] = distance;
1200baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_matchPriceCount++;
1201baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1202baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset));
1203baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1204baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_additionalOffset -= len;
1205baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				nowPos64 += len;
1206baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (_additionalOffset == 0)
1207baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
1208baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					// if (!_fastMode)
1209baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_matchPriceCount >= (1 << 7))
1210baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						FillDistancesPrices();
1211baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_alignPriceCount >= Base.kAlignTableSize)
1212baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						FillAlignPrices();
1213baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					inSize = nowPos64;
1214baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					outSize = _rangeEncoder.GetProcessedSizeAdd();
1215baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (_matchFinder.GetNumAvailableBytes() == 0)
1216baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1217baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Flush((UInt32)nowPos64);
1218baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						return;
1219baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1220baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1221baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (nowPos64 - progressPosValuePrev >= (1 << 12))
1222baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1223baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_finished = false;
1224baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						finished = false;
1225baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						return;
1226baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1227baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1228baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1229baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1230baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1231baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void ReleaseMFStream()
1232baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1233baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			if (_matchFinder != null && _needReleaseMFStream)
1234baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1235baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_matchFinder.ReleaseStream();
1236baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_needReleaseMFStream = false;
1237baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1238baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1239baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1240baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); }
1241baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); }
1242baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1243baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void ReleaseStreams()
1244baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1245baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			ReleaseMFStream();
1246baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			ReleaseOutStream();
1247baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1248baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1249baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream,
1250baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				Int64 inSize, Int64 outSize)
1251baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1252baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_inStream = inStream;
1253baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_finished = false;
1254baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Create();
1255baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			SetOutStream(outStream);
1256baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Init();
1257baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1258baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			// if (!_fastMode)
1259baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1260baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				FillDistancesPrices();
1261baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				FillAlignPrices();
1262baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1263baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1264baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
1265baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_lenEncoder.UpdateTables((UInt32)1 << _posStateBits);
1266baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
1267baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits);
1268baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1269baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			nowPos64 = 0;
1270baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1271baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1272baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1273baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
1274baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			Int64 inSize, Int64 outSize, ICodeProgress progress)
1275baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1276baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_needReleaseMFStream = false;
1277baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			try
1278baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1279baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				SetStreams(inStream, outStream, inSize, outSize);
1280baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				while (true)
1281baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
1282baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Int64 processedInSize;
1283baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					Int64 processedOutSize;
1284baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					bool finished;
1285baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					CodeOneBlock(out processedInSize, out processedOutSize, out finished);
1286baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (finished)
1287baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						return;
1288baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					if (progress != null)
1289baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1290baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						progress.SetProgress(processedInSize, processedOutSize);
1291baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1292baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1293baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1294baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			finally
1295baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1296baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				ReleaseStreams();
1297baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1298baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1299baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1300baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		const int kPropSize = 5;
1301baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		Byte[] properties = new Byte[kPropSize];
1302baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1303baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		public void WriteCoderProperties(System.IO.Stream outStream)
1304baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1305baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
1306baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (int i = 0; i < 4; i++)
1307baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				properties[1 + i] = (Byte)((_dictionarySize >> (8 * i)) & 0xFF);
1308baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			outStream.Write(properties, 0, kPropSize);
1309baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1310baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1311baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32[] tempPrices = new UInt32[Base.kNumFullDistances];
1312baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		UInt32 _matchPriceCount;
1313baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1314baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void FillDistancesPrices()
1315baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1316baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
1317baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1318baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 posSlot = GetPosSlot(i);
1319baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				int footerBits = (int)((posSlot >> 1) - 1);
1320baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
1321baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
1322baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					baseVal - posSlot - 1, footerBits, i - baseVal);
1323baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1324baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1325baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
1326baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1327baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 posSlot;
1328baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
1329baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1330baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 st = (lenToPosState << Base.kNumPosSlotBits);
1331baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (posSlot = 0; posSlot < _distTableSize; posSlot++)
1332baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
1333baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
1334baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits);
1335baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1336baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 st2 = lenToPosState * Base.kNumFullDistances;
1337baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				UInt32 i;
1338baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (i = 0; i < Base.kStartPosModelIndex; i++)
1339baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_distancesPrices[st2 + i] = _posSlotPrices[st + i];
1340baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				for (; i < Base.kNumFullDistances; i++)
1341baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					_distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
1342baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1343baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_matchPriceCount = 0;
1344baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1345baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1346baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		void FillAlignPrices()
1347baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1348baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (UInt32 i = 0; i < Base.kAlignTableSize; i++)
1349baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
1350baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_alignPriceCount = 0;
1351baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1352baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1353baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1354baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		static string[] kMatchFinderIDs =
1355baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1356baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			"BT2",
1357baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			"BT4",
1358baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		};
1359baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1360baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		static int FindMatchFinder(string s)
1361baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1362baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (int m = 0; m < kMatchFinderIDs.Length; m++)
1363baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				if (s == kMatchFinderIDs[m])
1364baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					return m;
1365baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			return -1;
1366baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1367baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1368baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)
1369baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1370baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			for (UInt32 i = 0; i < properties.Length; i++)
1371baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			{
1372baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				object prop = properties[i];
1373baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				switch (propIDs[i])
1374baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				{
1375baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.NumFastBytes:
1376baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1377baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Int32))
1378baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1379baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Int32 numFastBytes = (Int32)prop;
1380baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
1381baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1382baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_numFastBytes = (UInt32)numFastBytes;
1383baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1384baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1385baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.Algorithm:
1386baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1387baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						/*
1388baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Int32))
1389baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1390baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Int32 maximize = (Int32)prop;
1391baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_fastMode = (maximize == 0);
1392baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_maxMode = (maximize >= 2);
1393baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						*/
1394baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1395baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1396baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.MatchFinder:
1397baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1398baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is String))
1399baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1400baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						EMatchFinderType matchFinderIndexPrev = _matchFinderType;
1401baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						int m = FindMatchFinder(((string)prop).ToUpper());
1402baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (m < 0)
1403baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1404baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_matchFinderType = (EMatchFinderType)m;
1405baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
1406baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							{
1407baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_dictionarySizePrev = 0xFFFFFFFF;
1408baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							_matchFinder = null;
1409baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							}
1410baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1411baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1412baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.DictionarySize:
1413baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1414baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						const int kDicLogSizeMaxCompress = 30;
1415baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Int32))
1416baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException(); ;
1417baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Int32 dictionarySize = (Int32)prop;
1418baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) ||
1419baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress))
1420baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1421baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_dictionarySize = (UInt32)dictionarySize;
1422baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						int dicLogSize;
1423baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
1424baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							if (dictionarySize <= ((UInt32)(1) << dicLogSize))
1425baa3858d3f5d128a5c8466b700098109edcad5f2repo sync								break;
1426baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_distTableSize = (UInt32)dicLogSize * 2;
1427baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1428baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1429baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.PosStateBits:
1430baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1431baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Int32))
1432baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1433baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Int32 v = (Int32)prop;
1434baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax)
1435baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1436baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_posStateBits = (int)v;
1437baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_posStateMask = (((UInt32)1) << (int)_posStateBits) - 1;
1438baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1439baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1440baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.LitPosBits:
1441baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1442baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Int32))
1443baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1444baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Int32 v = (Int32)prop;
1445baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax)
1446baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1447baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_numLiteralPosStateBits = (int)v;
1448baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1449baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1450baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.LitContextBits:
1451baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1452baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Int32))
1453baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1454baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						Int32 v = (Int32)prop;
1455baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax)
1456baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException(); ;
1457baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						_numLiteralContextBits = (int)v;
1458baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1459baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1460baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					case CoderPropID.EndMarker:
1461baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					{
1462baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						if (!(prop is Boolean))
1463baa3858d3f5d128a5c8466b700098109edcad5f2repo sync							throw new InvalidParamException();
1464baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						SetWriteEndMarkerMode((Boolean)prop);
1465baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						break;
1466baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					}
1467baa3858d3f5d128a5c8466b700098109edcad5f2repo sync					default:
1468baa3858d3f5d128a5c8466b700098109edcad5f2repo sync						throw new InvalidParamException();
1469baa3858d3f5d128a5c8466b700098109edcad5f2repo sync				}
1470baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			}
1471baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1472baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1473baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		uint _trainSize = 0;
1474baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		public void SetTrainSize(uint trainSize)
1475baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		{
1476baa3858d3f5d128a5c8466b700098109edcad5f2repo sync			_trainSize = trainSize;
1477baa3858d3f5d128a5c8466b700098109edcad5f2repo sync		}
1478baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
1479baa3858d3f5d128a5c8466b700098109edcad5f2repo sync	}
1480baa3858d3f5d128a5c8466b700098109edcad5f2repo sync}
1481