1package SevenZip.Compression.LZMA;
2
3import SevenZip.Compression.RangeCoder.BitTreeEncoder;
4import SevenZip.Compression.LZMA.Base;
5import SevenZip.Compression.LZ.BinTree;
6import SevenZip.ICodeProgress;
7import java.io.IOException;
8
9public class Encoder
10{
11	public static final int EMatchFinderTypeBT2 = 0;
12	public static final int EMatchFinderTypeBT4 = 1;
13
14
15
16
17	static final int kIfinityPrice = 0xFFFFFFF;
18
19	static byte[] g_FastPos = new byte[1 << 11];
20
21	static
22	{
23		int kFastSlots = 22;
24		int c = 2;
25		g_FastPos[0] = 0;
26		g_FastPos[1] = 1;
27		for (int slotFast = 2; slotFast < kFastSlots; slotFast++)
28		{
29			int k = (1 << ((slotFast >> 1) - 1));
30			for (int j = 0; j < k; j++, c++)
31				g_FastPos[c] = (byte)slotFast;
32		}
33	}
34
35	static int GetPosSlot(int pos)
36	{
37		if (pos < (1 << 11))
38			return g_FastPos[pos];
39		if (pos < (1 << 21))
40			return (g_FastPos[pos >> 10] + 20);
41		return (g_FastPos[pos >> 20] + 40);
42	}
43
44	static int GetPosSlot2(int pos)
45	{
46		if (pos < (1 << 17))
47			return (g_FastPos[pos >> 6] + 12);
48		if (pos < (1 << 27))
49			return (g_FastPos[pos >> 16] + 32);
50		return (g_FastPos[pos >> 26] + 52);
51	}
52
53	int _state = Base.StateInit();
54	byte _previousByte;
55	int[] _repDistances = new int[Base.kNumRepDistances];
56
57	void BaseInit()
58	{
59		_state = Base.StateInit();
60		_previousByte = 0;
61		for (int i = 0; i < Base.kNumRepDistances; i++)
62			_repDistances[i] = 0;
63	}
64
65	static final int kDefaultDictionaryLogSize = 22;
66	static final int kNumFastBytesDefault = 0x20;
67
68	class LiteralEncoder
69	{
70		class Encoder2
71		{
72			short[] m_Encoders = new short[0x300];
73
74			public void Init() { SevenZip.Compression.RangeCoder.Encoder.InitBitModels(m_Encoders); }
75
76
77
78			public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol) throws IOException
79			{
80				int context = 1;
81				for (int i = 7; i >= 0; i--)
82				{
83					int bit = ((symbol >> i) & 1);
84					rangeEncoder.Encode(m_Encoders, context, bit);
85					context = (context << 1) | bit;
86				}
87			}
88
89			public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException
90			{
91				int context = 1;
92				boolean same = true;
93				for (int i = 7; i >= 0; i--)
94				{
95					int bit = ((symbol >> i) & 1);
96					int state = context;
97					if (same)
98					{
99						int matchBit = ((matchByte >> i) & 1);
100						state += ((1 + matchBit) << 8);
101						same = (matchBit == bit);
102					}
103					rangeEncoder.Encode(m_Encoders, state, bit);
104					context = (context << 1) | bit;
105				}
106			}
107
108			public int GetPrice(boolean matchMode, byte matchByte, byte symbol)
109			{
110				int price = 0;
111				int context = 1;
112				int i = 7;
113				if (matchMode)
114				{
115					for (; i >= 0; i--)
116					{
117						int matchBit = (matchByte >> i) & 1;
118						int bit = (symbol >> i) & 1;
119						price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8) + context], 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					int bit = (symbol >> i) & 1;
131					price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[context], 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		int m_PosMask;
142
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 = (1 << numPosBits) - 1;
149			m_NumPrevBits = numPrevBits;
150			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
151			m_Coders = new Encoder2[numStates];
152			for (int i = 0; i < numStates; i++)
153				m_Coders[i] = new Encoder2();
154		}
155
156		public void Init()
157		{
158			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
159			for (int i = 0; i < numStates; i++)
160				m_Coders[i].Init();
161		}
162
163		public Encoder2 GetSubCoder(int pos, byte prevByte)
164		{ return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; }
165	}
166
167	class LenEncoder
168	{
169		short[] _choice = new short[2];
170		BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
171		BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
172		BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);
173
174
175		public LenEncoder()
176		{
177			for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
178			{
179				_lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);
180				_midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);
181			}
182		}
183
184		public void Init(int numPosStates)
185		{
186			SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_choice);
187
188			for (int posState = 0; posState < numPosStates; posState++)
189			{
190				_lowCoder[posState].Init();
191				_midCoder[posState].Init();
192			}
193			_highCoder.Init();
194		}
195
196		public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
197		{
198			if (symbol < Base.kNumLowLenSymbols)
199			{
200				rangeEncoder.Encode(_choice, 0, 0);
201				_lowCoder[posState].Encode(rangeEncoder, symbol);
202			}
203			else
204			{
205				symbol -= Base.kNumLowLenSymbols;
206				rangeEncoder.Encode(_choice, 0, 1);
207				if (symbol < Base.kNumMidLenSymbols)
208				{
209					rangeEncoder.Encode(_choice, 1, 0);
210					_midCoder[posState].Encode(rangeEncoder, symbol);
211				}
212				else
213				{
214					rangeEncoder.Encode(_choice, 1, 1);
215					_highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
216				}
217			}
218		}
219
220		public void SetPrices(int posState, int numSymbols, int[] prices, int st)
221		{
222			int a0 = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[0]);
223			int a1 = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[0]);
224			int b0 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[1]);
225			int b1 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[1]);
226			int 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	public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
245
246	class LenPriceTableEncoder extends LenEncoder
247	{
248		int[] _prices = new int[Base.kNumLenSymbols<<Base.kNumPosStatesBitsEncodingMax];
249		int _tableSize;
250		int[] _counters = new int[Base.kNumPosStatesEncodingMax];
251
252		public void SetTableSize(int tableSize) { _tableSize = tableSize; }
253
254		public int GetPrice(int symbol, int posState)
255		{
256			return _prices[posState * Base.kNumLenSymbols + symbol];
257		}
258
259		void UpdateTable(int posState)
260		{
261			SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
262			_counters[posState] = _tableSize;
263		}
264
265		public void UpdateTables(int numPosStates)
266		{
267			for (int posState = 0; posState < numPosStates; posState++)
268				UpdateTable(posState);
269		}
270
271		public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
272		{
273			super.Encode(rangeEncoder, symbol, posState);
274			if (--_counters[posState] == 0)
275				UpdateTable(posState);
276		}
277	}
278
279	static final int kNumOpts = 1 << 12;
280	class Optimal
281	{
282		public int State;
283
284		public boolean Prev1IsChar;
285		public boolean Prev2;
286
287		public int PosPrev2;
288		public int BackPrev2;
289
290		public int Price;
291		public int PosPrev;
292		public int BackPrev;
293
294		public int Backs0;
295		public int Backs1;
296		public int Backs2;
297		public int Backs3;
298
299		public void MakeAsChar() { BackPrev = -1; Prev1IsChar = false; }
300		public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
301		public boolean IsShortRep() { return (BackPrev == 0); }
302	};
303	Optimal[] _optimum = new Optimal[kNumOpts];
304	SevenZip.Compression.LZ.BinTree _matchFinder = null;
305	SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();
306
307	short[] _isMatch = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
308	short[] _isRep = new short[Base.kNumStates];
309	short[] _isRepG0 = new short[Base.kNumStates];
310	short[] _isRepG1 = new short[Base.kNumStates];
311	short[] _isRepG2 = new short[Base.kNumStates];
312	short[] _isRep0Long = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
313
314	BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits
315
316	short[] _posEncoders = new short[Base.kNumFullDistances-Base.kEndPosModelIndex];
317	BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);
318
319	LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
320	LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
321
322	LiteralEncoder _literalEncoder = new LiteralEncoder();
323
324	int[] _matchDistances = new int[Base.kMatchMaxLen*2+2];
325
326	int _numFastBytes = kNumFastBytesDefault;
327	int _longestMatchLength;
328	int _numDistancePairs;
329
330	int _additionalOffset;
331
332	int _optimumEndIndex;
333	int _optimumCurrentIndex;
334
335	boolean _longestMatchWasFound;
336
337	int[] _posSlotPrices = new int[1<<(Base.kNumPosSlotBits+Base.kNumLenToPosStatesBits)];
338	int[] _distancesPrices = new int[Base.kNumFullDistances<<Base.kNumLenToPosStatesBits];
339	int[] _alignPrices = new int[Base.kAlignTableSize];
340	int _alignPriceCount;
341
342	int _distTableSize = (kDefaultDictionaryLogSize * 2);
343
344	int _posStateBits = 2;
345	int _posStateMask = (4 - 1);
346	int _numLiteralPosStateBits = 0;
347	int _numLiteralContextBits = 3;
348
349	int _dictionarySize = (1 << kDefaultDictionaryLogSize);
350	int _dictionarySizePrev = -1;
351	int _numFastBytesPrev = -1;
352
353	long nowPos64;
354	boolean _finished;
355	java.io.InputStream _inStream;
356
357	int _matchFinderType = EMatchFinderTypeBT4;
358	boolean _writeEndMark = false;
359
360	boolean _needReleaseMFStream = false;
361
362	void Create()
363	{
364		if (_matchFinder == null)
365		{
366			SevenZip.Compression.LZ.BinTree bt = new SevenZip.Compression.LZ.BinTree();
367			int numHashBytes = 4;
368			if (_matchFinderType == EMatchFinderTypeBT2)
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
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 BitTreeEncoder(Base.kNumPosSlotBits);
388	}
389
390	void SetWriteEndMarkerMode(boolean writeEndMarker)
391	{
392		_writeEndMark = writeEndMarker;
393	}
394
395	void Init()
396	{
397		BaseInit();
398		_rangeEncoder.Init();
399
400		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isMatch);
401		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep0Long);
402		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep);
403		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG0);
404		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG1);
405		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG2);
406		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_posEncoders);
407
408
409
410
411
412
413
414		_literalEncoder.Init();
415		for (int i = 0; i < Base.kNumLenToPosStates; i++)
416			_posSlotEncoder[i].Init();
417
418
419
420		_lenEncoder.Init(1 << _posStateBits);
421		_repMatchLenEncoder.Init(1 << _posStateBits);
422
423		_posAlignEncoder.Init();
424
425		_longestMatchWasFound = false;
426		_optimumEndIndex = 0;
427		_optimumCurrentIndex = 0;
428		_additionalOffset = 0;
429	}
430
431	int ReadMatchDistances() throws java.io.IOException
432	{
433		int 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		return lenRes;
444	}
445
446	void MovePos(int num) throws java.io.IOException
447	{
448		if (num > 0)
449		{
450			_matchFinder.Skip(num);
451			_additionalOffset += num;
452		}
453	}
454
455	int GetRepLen1Price(int state, int posState)
456	{
457		return SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]) +
458				SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
459	}
460
461	int GetPureRepPrice(int repIndex, int state, int posState)
462	{
463		int price;
464		if (repIndex == 0)
465		{
466			price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]);
467			price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
468		}
469		else
470		{
471			price = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG0[state]);
472			if (repIndex == 1)
473				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG1[state]);
474			else
475			{
476				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG1[state]);
477				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);
478			}
479		}
480		return price;
481	}
482
483	int GetRepPrice(int repIndex, int len, int state, int posState)
484	{
485		int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
486		return price + GetPureRepPrice(repIndex, state, posState);
487	}
488
489	int GetPosLenPrice(int pos, int len, int posState)
490	{
491		int price;
492		int 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
501	int Backward(int cur)
502	{
503		_optimumEndIndex = cur;
504		int posMem = _optimum[cur].PosPrev;
505		int 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			int posPrev = posMem;
520			int 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	int[] reps = new int[Base.kNumRepDistances];
536	int[] repLens = new int[Base.kNumRepDistances];
537	int backRes;
538
539	int GetOptimum(int position) throws IOException
540	{
541		if (_optimumEndIndex != _optimumCurrentIndex)
542		{
543			int 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		int lenMain, numDistancePairs;
551		if (!_longestMatchWasFound)
552		{
553			lenMain = ReadMatchDistances();
554		}
555		else
556		{
557			lenMain = _longestMatchLength;
558			_longestMatchWasFound = false;
559		}
560		numDistancePairs = _numDistancePairs;
561
562		int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
563		if (numAvailableBytes < 2)
564		{
565			backRes = -1;
566			return 1;
567		}
568		if (numAvailableBytes > Base.kMatchMaxLen)
569			numAvailableBytes = Base.kMatchMaxLen;
570
571		int repMaxIndex = 0;
572		int 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			int 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(0 - _repDistances[0] - 1 - 1);
597
598		if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
599		{
600			backRes = -1;
601			return 1;
602		}
603
604		_optimum[0].State = _state;
605
606		int posState = (position & _posStateMask);
607
608		_optimum[1].Price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) +
609				_literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);
610		_optimum[1].MakeAsChar();
611
612		int matchPrice = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);
613		int repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[_state]);
614
615		if (matchByte == currentByte)
616		{
617			int 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		int 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		int len = lenEnd;
641		do
642			_optimum[len--].Price = kIfinityPrice;
643		while (len >= 2);
644
645		for (i = 0; i < Base.kNumRepDistances; i++)
646		{
647			int repLen = repLens[i];
648			if (repLen < 2)
649				continue;
650			int price = repMatchPrice + GetPureRepPrice(i, _state, posState);
651			do
652			{
653				int 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		int normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[_state]);
667
668		len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
669		if (len <= lenMain)
670		{
671			int offs = 0;
672			while (len > _matchDistances[offs])
673				offs += 2;
674			for (; ; len++)
675			{
676				int distance = _matchDistances[offs + 1];
677				int 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		int cur = 0;
696
697		while (true)
698		{
699			cur++;
700			if (cur == lenEnd)
701				return Backward(cur);
702			int newLen = ReadMatchDistances();
703			numDistancePairs = _numDistancePairs;
704			if (newLen >= _numFastBytes)
705			{
706
707				_longestMatchLength = newLen;
708				_longestMatchWasFound = true;
709				return Backward(cur);
710			}
711			position++;
712			int posPrev = _optimum[cur].PosPrev;
713			int 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 = Base.StateUpdateRep(state);
722					else
723						state = Base.StateUpdateMatch(state);
724				}
725				else
726					state = _optimum[posPrev].State;
727				state = Base.StateUpdateChar(state);
728			}
729			else
730				state = _optimum[posPrev].State;
731			if (posPrev == cur - 1)
732			{
733				if (_optimum[cur].IsShortRep())
734					state = Base.StateUpdateShortRep(state);
735				else
736					state = Base.StateUpdateChar(state);
737			}
738			else
739			{
740				int pos;
741				if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
742				{
743					posPrev = _optimum[cur].PosPrev2;
744					pos = _optimum[cur].BackPrev2;
745					state = Base.StateUpdateRep(state);
746				}
747				else
748				{
749					pos = _optimum[cur].BackPrev;
750					if (pos < Base.kNumRepDistances)
751						state = Base.StateUpdateRep(state);
752					else
753						state = Base.StateUpdateMatch(state);
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			int curPrice = _optimum[cur].Price;
801
802			currentByte = _matchFinder.GetIndexByte(0 - 1);
803			matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);
804
805			posState = (position & _posStateMask);
806
807			int curAnd1Price = curPrice +
808				SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) +
809				_literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
810				GetPrice(!Base.StateIsCharState(state), matchByte, currentByte);
811
812			Optimal nextOptimum = _optimum[cur + 1];
813
814			boolean 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 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]);
824			repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state]);
825
826			if (matchByte == currentByte &&
827				!(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
828			{
829				int 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			int 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				int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);
851				int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
852				if (lenTest2 >= 2)
853				{
854					int state2 = Base.StateUpdateChar(state);
855
856					int posStateNext = (position + 1) & _posStateMask;
857					int nextRepMatchPrice = curAnd1Price +
858						SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
859						SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
860					{
861						int offset = cur + 1 + lenTest2;
862						while (lenEnd < offset)
863							_optimum[++lenEnd].Price = kIfinityPrice;
864						int 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			int startLen = 2; // speed optimization
880
881			for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
882			{
883				int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
884				if (lenTest < 2)
885					continue;
886				int lenTestTemp = lenTest;
887				do
888				{
889					while (lenEnd < cur + lenTest)
890						_optimum[++lenEnd].Price = kIfinityPrice;
891					int 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					int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
911					int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);
912					if (lenTest2 >= 2)
913					{
914						int state2 = Base.StateUpdateRep(state);
915
916						int posStateNext = (position + lenTest) & _posStateMask;
917						int curAndLenCharPrice =
918								repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
919								SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
920								_literalEncoder.GetSubCoder(position + lenTest,
921								_matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,
922								_matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)),
923								_matchFinder.GetIndexByte(lenTest - 1));
924						state2 = Base.StateUpdateChar(state2);
925						posStateNext = (position + lenTest + 1) & _posStateMask;
926						int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
927						int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
928
929						// for(; lenTest2 >= 2; lenTest2--)
930						{
931							int offset = lenTest + 1 + lenTest2;
932							while (lenEnd < cur + offset)
933								_optimum[++lenEnd].Price = kIfinityPrice;
934							int 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 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[state]);
961				while (lenEnd < cur + newLen)
962					_optimum[++lenEnd].Price = kIfinityPrice;
963
964				int offs = 0;
965				while (startLen > _matchDistances[offs])
966					offs += 2;
967
968				for (int lenTest = startLen; ; lenTest++)
969				{
970					int curBack = _matchDistances[offs + 1];
971					int 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							int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
986							int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);
987							if (lenTest2 >= 2)
988							{
989								int state2 = Base.StateUpdateMatch(state);
990
991								int posStateNext = (position + lenTest) & _posStateMask;
992								int curAndLenCharPrice = curAndLenPrice +
993									SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
994									_literalEncoder.GetSubCoder(position + lenTest,
995									_matchFinder.GetIndexByte(lenTest - 1 - 1)).
996									GetPrice(true,
997									_matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),
998									_matchFinder.GetIndexByte(lenTest - 1));
999								state2 = Base.StateUpdateChar(state2);
1000								posStateNext = (position + lenTest + 1) & _posStateMask;
1001								int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
1002								int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
1003
1004								int 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
1030	boolean ChangePair(int smallDist, int bigDist)
1031	{
1032		int kDif = 7;
1033		return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));
1034	}
1035
1036	void WriteEndMarker(int posState) throws IOException
1037	{
1038		if (!_writeEndMark)
1039			return;
1040
1041		_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);
1042		_rangeEncoder.Encode(_isRep, _state, 0);
1043		_state = Base.StateUpdateMatch(_state);
1044		int len = Base.kMatchMinLen;
1045		_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1046		int posSlot = (1 << Base.kNumPosSlotBits) - 1;
1047		int lenToPosState = Base.GetLenToPosState(len);
1048		_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
1049		int footerBits = 30;
1050		int posReduced = (1 << footerBits) - 1;
1051		_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
1052		_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
1053	}
1054
1055	void Flush(int nowPos) throws IOException
1056	{
1057		ReleaseMFStream();
1058		WriteEndMarker(nowPos & _posStateMask);
1059		_rangeEncoder.FlushData();
1060		_rangeEncoder.FlushStream();
1061	}
1062
1063	public void CodeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException
1064	{
1065		inSize[0] = 0;
1066		outSize[0] = 0;
1067		finished[0] = true;
1068
1069		if (_inStream != null)
1070		{
1071			_matchFinder.SetStream(_inStream);
1072			_matchFinder.Init();
1073			_needReleaseMFStream = true;
1074			_inStream = null;
1075		}
1076
1077		if (_finished)
1078			return;
1079		_finished = true;
1080
1081
1082		long progressPosValuePrev = nowPos64;
1083		if (nowPos64 == 0)
1084		{
1085			if (_matchFinder.GetNumAvailableBytes() == 0)
1086			{
1087				Flush((int)nowPos64);
1088				return;
1089			}
1090
1091			ReadMatchDistances();
1092			int posState = (int)(nowPos64) & _posStateMask;
1093			_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);
1094			_state = Base.StateUpdateChar(_state);
1095			byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);
1096			_literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
1097			_previousByte = curByte;
1098			_additionalOffset--;
1099			nowPos64++;
1100		}
1101		if (_matchFinder.GetNumAvailableBytes() == 0)
1102		{
1103			Flush((int)nowPos64);
1104			return;
1105		}
1106		while (true)
1107		{
1108
1109			int len = GetOptimum((int)nowPos64);
1110			int pos = backRes;
1111			int posState = ((int)nowPos64) & _posStateMask;
1112			int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;
1113			if (len == 1 && pos == -1)
1114			{
1115				_rangeEncoder.Encode(_isMatch, complexState, 0);
1116				byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
1117				LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);
1118				if (!Base.StateIsCharState(_state))
1119				{
1120					byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
1121					subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
1122				}
1123				else
1124					subCoder.Encode(_rangeEncoder, curByte);
1125				_previousByte = curByte;
1126				_state = Base.StateUpdateChar(_state);
1127			}
1128			else
1129			{
1130				_rangeEncoder.Encode(_isMatch, complexState, 1);
1131				if (pos < Base.kNumRepDistances)
1132				{
1133					_rangeEncoder.Encode(_isRep, _state, 1);
1134					if (pos == 0)
1135					{
1136						_rangeEncoder.Encode(_isRepG0, _state, 0);
1137						if (len == 1)
1138							_rangeEncoder.Encode(_isRep0Long, complexState, 0);
1139						else
1140							_rangeEncoder.Encode(_isRep0Long, complexState, 1);
1141					}
1142					else
1143					{
1144						_rangeEncoder.Encode(_isRepG0, _state, 1);
1145						if (pos == 1)
1146							_rangeEncoder.Encode(_isRepG1, _state, 0);
1147						else
1148						{
1149							_rangeEncoder.Encode(_isRepG1, _state, 1);
1150							_rangeEncoder.Encode(_isRepG2, _state, pos - 2);
1151						}
1152					}
1153					if (len == 1)
1154						_state = Base.StateUpdateShortRep(_state);
1155					else
1156					{
1157						_repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1158						_state = Base.StateUpdateRep(_state);
1159					}
1160					int distance = _repDistances[pos];
1161					if (pos != 0)
1162					{
1163						for (int i = pos; i >= 1; i--)
1164							_repDistances[i] = _repDistances[i - 1];
1165						_repDistances[0] = distance;
1166					}
1167				}
1168				else
1169				{
1170					_rangeEncoder.Encode(_isRep, _state, 0);
1171					_state = Base.StateUpdateMatch(_state);
1172					_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1173					pos -= Base.kNumRepDistances;
1174					int posSlot = GetPosSlot(pos);
1175					int lenToPosState = Base.GetLenToPosState(len);
1176					_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
1177
1178					if (posSlot >= Base.kStartPosModelIndex)
1179					{
1180						int footerBits = (int)((posSlot >> 1) - 1);
1181						int baseVal = ((2 | (posSlot & 1)) << footerBits);
1182						int posReduced = pos - baseVal;
1183
1184						if (posSlot < Base.kEndPosModelIndex)
1185							BitTreeEncoder.ReverseEncode(_posEncoders,
1186									baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
1187						else
1188						{
1189							_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
1190							_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
1191							_alignPriceCount++;
1192						}
1193					}
1194					int distance = pos;
1195					for (int i = Base.kNumRepDistances - 1; i >= 1; i--)
1196						_repDistances[i] = _repDistances[i - 1];
1197					_repDistances[0] = distance;
1198					_matchPriceCount++;
1199				}
1200				_previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);
1201			}
1202			_additionalOffset -= len;
1203			nowPos64 += len;
1204			if (_additionalOffset == 0)
1205			{
1206				// if (!_fastMode)
1207				if (_matchPriceCount >= (1 << 7))
1208					FillDistancesPrices();
1209				if (_alignPriceCount >= Base.kAlignTableSize)
1210					FillAlignPrices();
1211				inSize[0] = nowPos64;
1212				outSize[0] = _rangeEncoder.GetProcessedSizeAdd();
1213				if (_matchFinder.GetNumAvailableBytes() == 0)
1214				{
1215					Flush((int)nowPos64);
1216					return;
1217				}
1218
1219				if (nowPos64 - progressPosValuePrev >= (1 << 12))
1220				{
1221					_finished = false;
1222					finished[0] = false;
1223					return;
1224				}
1225			}
1226		}
1227	}
1228
1229	void ReleaseMFStream()
1230	{
1231		if (_matchFinder != null && _needReleaseMFStream)
1232		{
1233			_matchFinder.ReleaseStream();
1234			_needReleaseMFStream = false;
1235		}
1236	}
1237
1238	void SetOutStream(java.io.OutputStream outStream)
1239	{ _rangeEncoder.SetStream(outStream); }
1240	void ReleaseOutStream()
1241	{ _rangeEncoder.ReleaseStream(); }
1242
1243	void ReleaseStreams()
1244	{
1245		ReleaseMFStream();
1246		ReleaseOutStream();
1247	}
1248
1249	void SetStreams(java.io.InputStream inStream, java.io.OutputStream outStream,
1250			long inSize, long 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(1 << _posStateBits);
1266		_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
1267		_repMatchLenEncoder.UpdateTables(1 << _posStateBits);
1268
1269		nowPos64 = 0;
1270	}
1271
1272	long[] processedInSize = new long[1]; long[] processedOutSize = new long[1]; boolean[] finished = new boolean[1];
1273	public void Code(java.io.InputStream inStream, java.io.OutputStream outStream,
1274			long inSize, long outSize, ICodeProgress progress) throws IOException
1275	{
1276		_needReleaseMFStream = false;
1277		try
1278		{
1279			SetStreams(inStream, outStream, inSize, outSize);
1280			while (true)
1281			{
1282
1283
1284
1285				CodeOneBlock(processedInSize, processedOutSize, finished);
1286				if (finished[0])
1287					return;
1288				if (progress != null)
1289				{
1290					progress.SetProgress(processedInSize[0], processedOutSize[0]);
1291				}
1292			}
1293		}
1294		finally
1295		{
1296			ReleaseStreams();
1297		}
1298	}
1299
1300	public static final int kPropSize = 5;
1301	byte[] properties = new byte[kPropSize];
1302
1303	public void WriteCoderProperties(java.io.OutputStream outStream) throws IOException
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));
1308		outStream.write(properties, 0, kPropSize);
1309	}
1310
1311	int[] tempPrices = new int[Base.kNumFullDistances];
1312	int _matchPriceCount;
1313
1314	void FillDistancesPrices()
1315	{
1316		for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
1317		{
1318			int posSlot = GetPosSlot(i);
1319			int footerBits = (int)((posSlot >> 1) - 1);
1320			int baseVal = ((2 | (posSlot & 1)) << footerBits);
1321			tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
1322				baseVal - posSlot - 1, footerBits, i - baseVal);
1323		}
1324
1325		for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
1326		{
1327			int posSlot;
1328			BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
1329
1330			int 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) << SevenZip.Compression.RangeCoder.Encoder.kNumBitPriceShiftBits);
1335
1336			int st2 = lenToPosState * Base.kNumFullDistances;
1337			int 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
1346	void FillAlignPrices()
1347	{
1348		for (int i = 0; i < Base.kAlignTableSize; i++)
1349			_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
1350		_alignPriceCount = 0;
1351	}
1352
1353
1354	public boolean SetAlgorithm(int algorithm)
1355	{
1356		/*
1357		_fastMode = (algorithm == 0);
1358		_maxMode = (algorithm >= 2);
1359		*/
1360		return true;
1361	}
1362
1363	public boolean SetDictionarySize(int dictionarySize)
1364	{
1365		int kDicLogSizeMaxCompress = 29;
1366		if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress))
1367			return false;
1368		_dictionarySize = dictionarySize;
1369		int dicLogSize;
1370		for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) ;
1371		_distTableSize = dicLogSize * 2;
1372		return true;
1373	}
1374
1375	public boolean SetNumFastBytes(int numFastBytes)
1376	{
1377		if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
1378			return false;
1379		_numFastBytes = numFastBytes;
1380		return true;
1381	}
1382
1383	public boolean SetMatchFinder(int matchFinderIndex)
1384	{
1385		if (matchFinderIndex < 0 || matchFinderIndex > 2)
1386			return false;
1387		int matchFinderIndexPrev = _matchFinderType;
1388		_matchFinderType = matchFinderIndex;
1389		if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
1390		{
1391			_dictionarySizePrev = -1;
1392			_matchFinder = null;
1393		}
1394		return true;
1395	}
1396
1397	public boolean SetLcLpPb(int lc, int lp, int pb)
1398	{
1399		if (
1400				lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax ||
1401				lc < 0 || lc > Base.kNumLitContextBitsMax ||
1402				pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax)
1403			return false;
1404		_numLiteralPosStateBits = lp;
1405		_numLiteralContextBits = lc;
1406		_posStateBits = pb;
1407		_posStateMask = ((1) << _posStateBits) - 1;
1408		return true;
1409	}
1410
1411	public void SetEndMarkerMode(boolean endMarkerMode)
1412	{
1413		_writeEndMark = endMarkerMode;
1414	}
1415}
1416
1417