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