misc/libphysfs/lzma/Java/SevenZip/Compression/LZMA/Encoder.java
author nemo
Mon, 10 Apr 2017 12:06:43 -0400
changeset 12218 bb5522e88ab2
permissions -rw-r--r--
bulk copy of latest physfs to our misc/libphysfs since this seems to fix an off-by-1 error reliably hit in readln read of 1 byte probably introduced in the addition of the buffered read. Whether this is excessive or whether libphysfs should even be maintained by us is another matter. But at least we shouldn't crash

package SevenZip.Compression.LZMA;

import SevenZip.Compression.RangeCoder.BitTreeEncoder;
import SevenZip.Compression.LZMA.Base;
import SevenZip.Compression.LZ.BinTree;
import SevenZip.ICodeProgress;
import java.io.IOException;

public class Encoder
{
	public static final int EMatchFinderTypeBT2 = 0;
	public static final int EMatchFinderTypeBT4 = 1;




	static final int kIfinityPrice = 0xFFFFFFF;

	static byte[] g_FastPos = new byte[1 << 11];

	static
	{
		int kFastSlots = 22;
		int c = 2;
		g_FastPos[0] = 0;
		g_FastPos[1] = 1;
		for (int slotFast = 2; slotFast < kFastSlots; slotFast++)
		{
			int k = (1 << ((slotFast >> 1) - 1));
			for (int j = 0; j < k; j++, c++)
				g_FastPos[c] = (byte)slotFast;
		}
	}

	static int GetPosSlot(int pos)
	{
		if (pos < (1 << 11))
			return g_FastPos[pos];
		if (pos < (1 << 21))
			return (g_FastPos[pos >> 10] + 20);
		return (g_FastPos[pos >> 20] + 40);
	}

	static int GetPosSlot2(int pos)
	{
		if (pos < (1 << 17))
			return (g_FastPos[pos >> 6] + 12);
		if (pos < (1 << 27))
			return (g_FastPos[pos >> 16] + 32);
		return (g_FastPos[pos >> 26] + 52);
	}

	int _state = Base.StateInit();
	byte _previousByte;
	int[] _repDistances = new int[Base.kNumRepDistances];

	void BaseInit()
	{
		_state = Base.StateInit();
		_previousByte = 0;
		for (int i = 0; i < Base.kNumRepDistances; i++)
			_repDistances[i] = 0;
	}

	static final int kDefaultDictionaryLogSize = 22;
	static final int kNumFastBytesDefault = 0x20;

	class LiteralEncoder
	{
		class Encoder2
		{
			short[] m_Encoders = new short[0x300];

			public void Init() { SevenZip.Compression.RangeCoder.Encoder.InitBitModels(m_Encoders); }



			public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol) throws IOException
			{
				int context = 1;
				for (int i = 7; i >= 0; i--)
				{
					int bit = ((symbol >> i) & 1);
					rangeEncoder.Encode(m_Encoders, context, bit);
					context = (context << 1) | bit;
				}
			}

			public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException
			{
				int context = 1;
				boolean same = true;
				for (int i = 7; i >= 0; i--)
				{
					int bit = ((symbol >> i) & 1);
					int state = context;
					if (same)
					{
						int matchBit = ((matchByte >> i) & 1);
						state += ((1 + matchBit) << 8);
						same = (matchBit == bit);
					}
					rangeEncoder.Encode(m_Encoders, state, bit);
					context = (context << 1) | bit;
				}
			}

			public int GetPrice(boolean matchMode, byte matchByte, byte symbol)
			{
				int price = 0;
				int context = 1;
				int i = 7;
				if (matchMode)
				{
					for (; i >= 0; i--)
					{
						int matchBit = (matchByte >> i) & 1;
						int bit = (symbol >> i) & 1;
						price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8) + context], bit);
						context = (context << 1) | bit;
						if (matchBit != bit)
						{
							i--;
							break;
						}
					}
				}
				for (; i >= 0; i--)
				{
					int bit = (symbol >> i) & 1;
					price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[context], bit);
					context = (context << 1) | bit;
				}
				return price;
			}
		}

		Encoder2[] m_Coders;
		int m_NumPrevBits;
		int m_NumPosBits;
		int m_PosMask;

		public void Create(int numPosBits, int numPrevBits)
		{
			if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
				return;
			m_NumPosBits = numPosBits;
			m_PosMask = (1 << numPosBits) - 1;
			m_NumPrevBits = numPrevBits;
			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
			m_Coders = new Encoder2[numStates];
			for (int i = 0; i < numStates; i++)
				m_Coders[i] = new Encoder2();
		}

		public void Init()
		{
			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
			for (int i = 0; i < numStates; i++)
				m_Coders[i].Init();
		}

		public Encoder2 GetSubCoder(int pos, byte prevByte)
		{ return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; }
	}

	class LenEncoder
	{
		short[] _choice = new short[2];
		BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
		BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
		BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);


		public LenEncoder()
		{
			for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
			{
				_lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);
				_midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);
			}
		}

		public void Init(int numPosStates)
		{
			SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_choice);

			for (int posState = 0; posState < numPosStates; posState++)
			{
				_lowCoder[posState].Init();
				_midCoder[posState].Init();
			}
			_highCoder.Init();
		}

		public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
		{
			if (symbol < Base.kNumLowLenSymbols)
			{
				rangeEncoder.Encode(_choice, 0, 0);
				_lowCoder[posState].Encode(rangeEncoder, symbol);
			}
			else
			{
				symbol -= Base.kNumLowLenSymbols;
				rangeEncoder.Encode(_choice, 0, 1);
				if (symbol < Base.kNumMidLenSymbols)
				{
					rangeEncoder.Encode(_choice, 1, 0);
					_midCoder[posState].Encode(rangeEncoder, symbol);
				}
				else
				{
					rangeEncoder.Encode(_choice, 1, 1);
					_highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
				}
			}
		}

		public void SetPrices(int posState, int numSymbols, int[] prices, int st)
		{
			int a0 = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[0]);
			int a1 = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[0]);
			int b0 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[1]);
			int b1 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[1]);
			int i = 0;
			for (i = 0; i < Base.kNumLowLenSymbols; i++)
			{
				if (i >= numSymbols)
					return;
				prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
			}
			for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
			{
				if (i >= numSymbols)
					return;
				prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
			}
			for (; i < numSymbols; i++)
				prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
		}
	};

	public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;

	class LenPriceTableEncoder extends LenEncoder
	{
		int[] _prices = new int[Base.kNumLenSymbols<<Base.kNumPosStatesBitsEncodingMax];
		int _tableSize;
		int[] _counters = new int[Base.kNumPosStatesEncodingMax];

		public void SetTableSize(int tableSize) { _tableSize = tableSize; }

		public int GetPrice(int symbol, int posState)
		{
			return _prices[posState * Base.kNumLenSymbols + symbol];
		}

		void UpdateTable(int posState)
		{
			SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
			_counters[posState] = _tableSize;
		}

		public void UpdateTables(int numPosStates)
		{
			for (int posState = 0; posState < numPosStates; posState++)
				UpdateTable(posState);
		}

		public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
		{
			super.Encode(rangeEncoder, symbol, posState);
			if (--_counters[posState] == 0)
				UpdateTable(posState);
		}
	}

	static final int kNumOpts = 1 << 12;
	class Optimal
	{
		public int State;

		public boolean Prev1IsChar;
		public boolean Prev2;

		public int PosPrev2;
		public int BackPrev2;

		public int Price;
		public int PosPrev;
		public int BackPrev;

		public int Backs0;
		public int Backs1;
		public int Backs2;
		public int Backs3;

		public void MakeAsChar() { BackPrev = -1; Prev1IsChar = false; }
		public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
		public boolean IsShortRep() { return (BackPrev == 0); }
	};
	Optimal[] _optimum = new Optimal[kNumOpts];
	SevenZip.Compression.LZ.BinTree _matchFinder = null;
	SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();

	short[] _isMatch = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
	short[] _isRep = new short[Base.kNumStates];
	short[] _isRepG0 = new short[Base.kNumStates];
	short[] _isRepG1 = new short[Base.kNumStates];
	short[] _isRepG2 = new short[Base.kNumStates];
	short[] _isRep0Long = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];

	BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits

	short[] _posEncoders = new short[Base.kNumFullDistances-Base.kEndPosModelIndex];
	BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);

	LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
	LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();

	LiteralEncoder _literalEncoder = new LiteralEncoder();

	int[] _matchDistances = new int[Base.kMatchMaxLen*2+2];

	int _numFastBytes = kNumFastBytesDefault;
	int _longestMatchLength;
	int _numDistancePairs;

	int _additionalOffset;

	int _optimumEndIndex;
	int _optimumCurrentIndex;

	boolean _longestMatchWasFound;

	int[] _posSlotPrices = new int[1<<(Base.kNumPosSlotBits+Base.kNumLenToPosStatesBits)];
	int[] _distancesPrices = new int[Base.kNumFullDistances<<Base.kNumLenToPosStatesBits];
	int[] _alignPrices = new int[Base.kAlignTableSize];
	int _alignPriceCount;

	int _distTableSize = (kDefaultDictionaryLogSize * 2);

	int _posStateBits = 2;
	int _posStateMask = (4 - 1);
	int _numLiteralPosStateBits = 0;
	int _numLiteralContextBits = 3;

	int _dictionarySize = (1 << kDefaultDictionaryLogSize);
	int _dictionarySizePrev = -1;
	int _numFastBytesPrev = -1;

	long nowPos64;
	boolean _finished;
	java.io.InputStream _inStream;

	int _matchFinderType = EMatchFinderTypeBT4;
	boolean _writeEndMark = false;

	boolean _needReleaseMFStream = false;

	void Create()
	{
		if (_matchFinder == null)
		{
			SevenZip.Compression.LZ.BinTree bt = new SevenZip.Compression.LZ.BinTree();
			int numHashBytes = 4;
			if (_matchFinderType == EMatchFinderTypeBT2)
				numHashBytes = 2;
			bt.SetType(numHashBytes);
			_matchFinder = bt;
		}
		_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);

		if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
			return;
		_matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
		_dictionarySizePrev = _dictionarySize;
		_numFastBytesPrev = _numFastBytes;
	}

	public Encoder()
	{
		for (int i = 0; i < kNumOpts; i++)
			_optimum[i] = new Optimal();
		for (int i = 0; i < Base.kNumLenToPosStates; i++)
			_posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits);
	}

	void SetWriteEndMarkerMode(boolean writeEndMarker)
	{
		_writeEndMark = writeEndMarker;
	}

	void Init()
	{
		BaseInit();
		_rangeEncoder.Init();

		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isMatch);
		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep0Long);
		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep);
		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG0);
		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG1);
		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG2);
		SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_posEncoders);







		_literalEncoder.Init();
		for (int i = 0; i < Base.kNumLenToPosStates; i++)
			_posSlotEncoder[i].Init();



		_lenEncoder.Init(1 << _posStateBits);
		_repMatchLenEncoder.Init(1 << _posStateBits);

		_posAlignEncoder.Init();

		_longestMatchWasFound = false;
		_optimumEndIndex = 0;
		_optimumCurrentIndex = 0;
		_additionalOffset = 0;
	}

	int ReadMatchDistances() throws java.io.IOException
	{
		int lenRes = 0;
		_numDistancePairs = _matchFinder.GetMatches(_matchDistances);
		if (_numDistancePairs > 0)
		{
			lenRes = _matchDistances[_numDistancePairs - 2];
			if (lenRes == _numFastBytes)
				lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[_numDistancePairs - 1],
					Base.kMatchMaxLen - lenRes);
		}
		_additionalOffset++;
		return lenRes;
	}

	void MovePos(int num) throws java.io.IOException
	{
		if (num > 0)
		{
			_matchFinder.Skip(num);
			_additionalOffset += num;
		}
	}

	int GetRepLen1Price(int state, int posState)
	{
		return SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]) +
				SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
	}

	int GetPureRepPrice(int repIndex, int state, int posState)
	{
		int price;
		if (repIndex == 0)
		{
			price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]);
			price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
		}
		else
		{
			price = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG0[state]);
			if (repIndex == 1)
				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG1[state]);
			else
			{
				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG1[state]);
				price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);
			}
		}
		return price;
	}

	int GetRepPrice(int repIndex, int len, int state, int posState)
	{
		int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
		return price + GetPureRepPrice(repIndex, state, posState);
	}

	int GetPosLenPrice(int pos, int len, int posState)
	{
		int price;
		int lenToPosState = Base.GetLenToPosState(len);
		if (pos < Base.kNumFullDistances)
			price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
		else
			price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
				_alignPrices[pos & Base.kAlignMask];
		return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
	}

	int Backward(int cur)
	{
		_optimumEndIndex = cur;
		int posMem = _optimum[cur].PosPrev;
		int backMem = _optimum[cur].BackPrev;
		do
		{
			if (_optimum[cur].Prev1IsChar)
			{
				_optimum[posMem].MakeAsChar();
				_optimum[posMem].PosPrev = posMem - 1;
				if (_optimum[cur].Prev2)
				{
					_optimum[posMem - 1].Prev1IsChar = false;
					_optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
					_optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
				}
			}
			int posPrev = posMem;
			int backCur = backMem;

			backMem = _optimum[posPrev].BackPrev;
			posMem = _optimum[posPrev].PosPrev;

			_optimum[posPrev].BackPrev = backCur;
			_optimum[posPrev].PosPrev = cur;
			cur = posPrev;
		}
		while (cur > 0);
		backRes = _optimum[0].BackPrev;
		_optimumCurrentIndex = _optimum[0].PosPrev;
		return _optimumCurrentIndex;
	}

	int[] reps = new int[Base.kNumRepDistances];
	int[] repLens = new int[Base.kNumRepDistances];
	int backRes;

	int GetOptimum(int position) throws IOException
	{
		if (_optimumEndIndex != _optimumCurrentIndex)
		{
			int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
			backRes = _optimum[_optimumCurrentIndex].BackPrev;
			_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
			return lenRes;
		}
		_optimumCurrentIndex = _optimumEndIndex = 0;

		int lenMain, numDistancePairs;
		if (!_longestMatchWasFound)
		{
			lenMain = ReadMatchDistances();
		}
		else
		{
			lenMain = _longestMatchLength;
			_longestMatchWasFound = false;
		}
		numDistancePairs = _numDistancePairs;

		int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
		if (numAvailableBytes < 2)
		{
			backRes = -1;
			return 1;
		}
		if (numAvailableBytes > Base.kMatchMaxLen)
			numAvailableBytes = Base.kMatchMaxLen;

		int repMaxIndex = 0;
		int i;
		for (i = 0; i < Base.kNumRepDistances; i++)
		{
			reps[i] = _repDistances[i];
			repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
			if (repLens[i] > repLens[repMaxIndex])
				repMaxIndex = i;
		}
		if (repLens[repMaxIndex] >= _numFastBytes)
		{
			backRes = repMaxIndex;
			int lenRes = repLens[repMaxIndex];
			MovePos(lenRes - 1);
			return lenRes;
		}

		if (lenMain >= _numFastBytes)
		{
			backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
			MovePos(lenMain - 1);
			return lenMain;
		}

		byte currentByte = _matchFinder.GetIndexByte(0 - 1);
		byte matchByte = _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1);

		if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
		{
			backRes = -1;
			return 1;
		}

		_optimum[0].State = _state;

		int posState = (position & _posStateMask);

		_optimum[1].Price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) +
				_literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);
		_optimum[1].MakeAsChar();

		int matchPrice = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);
		int repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[_state]);

		if (matchByte == currentByte)
		{
			int shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
			if (shortRepPrice < _optimum[1].Price)
			{
				_optimum[1].Price = shortRepPrice;
				_optimum[1].MakeAsShortRep();
			}
		}

		int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);

		if (lenEnd < 2)
		{
			backRes = _optimum[1].BackPrev;
			return 1;
		}

		_optimum[1].PosPrev = 0;

		_optimum[0].Backs0 = reps[0];
		_optimum[0].Backs1 = reps[1];
		_optimum[0].Backs2 = reps[2];
		_optimum[0].Backs3 = reps[3];

		int len = lenEnd;
		do
			_optimum[len--].Price = kIfinityPrice;
		while (len >= 2);

		for (i = 0; i < Base.kNumRepDistances; i++)
		{
			int repLen = repLens[i];
			if (repLen < 2)
				continue;
			int price = repMatchPrice + GetPureRepPrice(i, _state, posState);
			do
			{
				int curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
				Optimal optimum = _optimum[repLen];
				if (curAndLenPrice < optimum.Price)
				{
					optimum.Price = curAndLenPrice;
					optimum.PosPrev = 0;
					optimum.BackPrev = i;
					optimum.Prev1IsChar = false;
				}
			}
			while (--repLen >= 2);
		}

		int normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[_state]);

		len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
		if (len <= lenMain)
		{
			int offs = 0;
			while (len > _matchDistances[offs])
				offs += 2;
			for (; ; len++)
			{
				int distance = _matchDistances[offs + 1];
				int curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
				Optimal optimum = _optimum[len];
				if (curAndLenPrice < optimum.Price)
				{
					optimum.Price = curAndLenPrice;
					optimum.PosPrev = 0;
					optimum.BackPrev = distance + Base.kNumRepDistances;
					optimum.Prev1IsChar = false;
				}
				if (len == _matchDistances[offs])
				{
					offs += 2;
					if (offs == numDistancePairs)
						break;
				}
			}
		}

		int cur = 0;

		while (true)
		{
			cur++;
			if (cur == lenEnd)
				return Backward(cur);
			int newLen = ReadMatchDistances();
			numDistancePairs = _numDistancePairs;
			if (newLen >= _numFastBytes)
			{

				_longestMatchLength = newLen;
				_longestMatchWasFound = true;
				return Backward(cur);
			}
			position++;
			int posPrev = _optimum[cur].PosPrev;
			int state;
			if (_optimum[cur].Prev1IsChar)
			{
				posPrev--;
				if (_optimum[cur].Prev2)
				{
					state = _optimum[_optimum[cur].PosPrev2].State;
					if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
						state = Base.StateUpdateRep(state);
					else
						state = Base.StateUpdateMatch(state);
				}
				else
					state = _optimum[posPrev].State;
				state = Base.StateUpdateChar(state);
			}
			else
				state = _optimum[posPrev].State;
			if (posPrev == cur - 1)
			{
				if (_optimum[cur].IsShortRep())
					state = Base.StateUpdateShortRep(state);
				else
					state = Base.StateUpdateChar(state);
			}
			else
			{
				int pos;
				if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
				{
					posPrev = _optimum[cur].PosPrev2;
					pos = _optimum[cur].BackPrev2;
					state = Base.StateUpdateRep(state);
				}
				else
				{
					pos = _optimum[cur].BackPrev;
					if (pos < Base.kNumRepDistances)
						state = Base.StateUpdateRep(state);
					else
						state = Base.StateUpdateMatch(state);
				}
				Optimal opt = _optimum[posPrev];
				if (pos < Base.kNumRepDistances)
				{
					if (pos == 0)
					{
						reps[0] = opt.Backs0;
						reps[1] = opt.Backs1;
						reps[2] = opt.Backs2;
						reps[3] = opt.Backs3;
					}
					else if (pos == 1)
					{
						reps[0] = opt.Backs1;
						reps[1] = opt.Backs0;
						reps[2] = opt.Backs2;
						reps[3] = opt.Backs3;
					}
					else if (pos == 2)
					{
						reps[0] = opt.Backs2;
						reps[1] = opt.Backs0;
						reps[2] = opt.Backs1;
						reps[3] = opt.Backs3;
					}
					else
					{
						reps[0] = opt.Backs3;
						reps[1] = opt.Backs0;
						reps[2] = opt.Backs1;
						reps[3] = opt.Backs2;
					}
				}
				else
				{
					reps[0] = (pos - Base.kNumRepDistances);
					reps[1] = opt.Backs0;
					reps[2] = opt.Backs1;
					reps[3] = opt.Backs2;
				}
			}
			_optimum[cur].State = state;
			_optimum[cur].Backs0 = reps[0];
			_optimum[cur].Backs1 = reps[1];
			_optimum[cur].Backs2 = reps[2];
			_optimum[cur].Backs3 = reps[3];
			int curPrice = _optimum[cur].Price;

			currentByte = _matchFinder.GetIndexByte(0 - 1);
			matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);

			posState = (position & _posStateMask);

			int curAnd1Price = curPrice +
				SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) +
				_literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
				GetPrice(!Base.StateIsCharState(state), matchByte, currentByte);

			Optimal nextOptimum = _optimum[cur + 1];

			boolean nextIsChar = false;
			if (curAnd1Price < nextOptimum.Price)
			{
				nextOptimum.Price = curAnd1Price;
				nextOptimum.PosPrev = cur;
				nextOptimum.MakeAsChar();
				nextIsChar = true;
			}

			matchPrice = curPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]);
			repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state]);

			if (matchByte == currentByte &&
				!(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
			{
				int shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
				if (shortRepPrice <= nextOptimum.Price)
				{
					nextOptimum.Price = shortRepPrice;
					nextOptimum.PosPrev = cur;
					nextOptimum.MakeAsShortRep();
					nextIsChar = true;
				}
			}

			int numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
			numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull);
			numAvailableBytes = numAvailableBytesFull;

			if (numAvailableBytes < 2)
				continue;
			if (numAvailableBytes > _numFastBytes)
				numAvailableBytes = _numFastBytes;
			if (!nextIsChar && matchByte != currentByte)
			{
				// try Literal + rep0
				int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);
				int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
				if (lenTest2 >= 2)
				{
					int state2 = Base.StateUpdateChar(state);

					int posStateNext = (position + 1) & _posStateMask;
					int nextRepMatchPrice = curAnd1Price +
						SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
						SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
					{
						int offset = cur + 1 + lenTest2;
						while (lenEnd < offset)
							_optimum[++lenEnd].Price = kIfinityPrice;
						int curAndLenPrice = nextRepMatchPrice + GetRepPrice(
								0, lenTest2, state2, posStateNext);
						Optimal optimum = _optimum[offset];
						if (curAndLenPrice < optimum.Price)
						{
							optimum.Price = curAndLenPrice;
							optimum.PosPrev = cur + 1;
							optimum.BackPrev = 0;
							optimum.Prev1IsChar = true;
							optimum.Prev2 = false;
						}
					}
				}
			}

			int startLen = 2; // speed optimization 

			for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
			{
				int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
				if (lenTest < 2)
					continue;
				int lenTestTemp = lenTest;
				do
				{
					while (lenEnd < cur + lenTest)
						_optimum[++lenEnd].Price = kIfinityPrice;
					int curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
					Optimal optimum = _optimum[cur + lenTest];
					if (curAndLenPrice < optimum.Price)
					{
						optimum.Price = curAndLenPrice;
						optimum.PosPrev = cur;
						optimum.BackPrev = repIndex;
						optimum.Prev1IsChar = false;
					}
				}
				while (--lenTest >= 2);
				lenTest = lenTestTemp;

				if (repIndex == 0)
					startLen = lenTest + 1;

				// if (_maxMode)
				if (lenTest < numAvailableBytesFull)
				{
					int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
					int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);
					if (lenTest2 >= 2)
					{
						int state2 = Base.StateUpdateRep(state);

						int posStateNext = (position + lenTest) & _posStateMask;
						int curAndLenCharPrice =
								repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
								SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
								_literalEncoder.GetSubCoder(position + lenTest,
								_matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,
								_matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)),
								_matchFinder.GetIndexByte(lenTest - 1));
						state2 = Base.StateUpdateChar(state2);
						posStateNext = (position + lenTest + 1) & _posStateMask;
						int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
						int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);

						// for(; lenTest2 >= 2; lenTest2--)
						{
							int offset = lenTest + 1 + lenTest2;
							while (lenEnd < cur + offset)
								_optimum[++lenEnd].Price = kIfinityPrice;
							int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
							Optimal optimum = _optimum[cur + offset];
							if (curAndLenPrice < optimum.Price)
							{
								optimum.Price = curAndLenPrice;
								optimum.PosPrev = cur + lenTest + 1;
								optimum.BackPrev = 0;
								optimum.Prev1IsChar = true;
								optimum.Prev2 = true;
								optimum.PosPrev2 = cur;
								optimum.BackPrev2 = repIndex;
							}
						}
					}
				}
			}

			if (newLen > numAvailableBytes)
			{
				newLen = numAvailableBytes;
				for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
				_matchDistances[numDistancePairs] = newLen;
				numDistancePairs += 2;
			}
			if (newLen >= startLen)
			{
				normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[state]);
				while (lenEnd < cur + newLen)
					_optimum[++lenEnd].Price = kIfinityPrice;

				int offs = 0;
				while (startLen > _matchDistances[offs])
					offs += 2;

				for (int lenTest = startLen; ; lenTest++)
				{
					int curBack = _matchDistances[offs + 1];
					int curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
					Optimal optimum = _optimum[cur + lenTest];
					if (curAndLenPrice < optimum.Price)
					{
						optimum.Price = curAndLenPrice;
						optimum.PosPrev = cur;
						optimum.BackPrev = curBack + Base.kNumRepDistances;
						optimum.Prev1IsChar = false;
					}

					if (lenTest == _matchDistances[offs])
					{
						if (lenTest < numAvailableBytesFull)
						{
							int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
							int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);
							if (lenTest2 >= 2)
							{
								int state2 = Base.StateUpdateMatch(state);

								int posStateNext = (position + lenTest) & _posStateMask;
								int curAndLenCharPrice = curAndLenPrice +
									SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
									_literalEncoder.GetSubCoder(position + lenTest,
									_matchFinder.GetIndexByte(lenTest - 1 - 1)).
									GetPrice(true,
									_matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),
									_matchFinder.GetIndexByte(lenTest - 1));
								state2 = Base.StateUpdateChar(state2);
								posStateNext = (position + lenTest + 1) & _posStateMask;
								int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
								int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);

								int offset = lenTest + 1 + lenTest2;
								while (lenEnd < cur + offset)
									_optimum[++lenEnd].Price = kIfinityPrice;
								curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
								optimum = _optimum[cur + offset];
								if (curAndLenPrice < optimum.Price)
								{
									optimum.Price = curAndLenPrice;
									optimum.PosPrev = cur + lenTest + 1;
									optimum.BackPrev = 0;
									optimum.Prev1IsChar = true;
									optimum.Prev2 = true;
									optimum.PosPrev2 = cur;
									optimum.BackPrev2 = curBack + Base.kNumRepDistances;
								}
							}
						}
						offs += 2;
						if (offs == numDistancePairs)
							break;
					}
				}
			}
		}
	}

	boolean ChangePair(int smallDist, int bigDist)
	{
		int kDif = 7;
		return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));
	}

	void WriteEndMarker(int posState) throws IOException
	{
		if (!_writeEndMark)
			return;

		_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);
		_rangeEncoder.Encode(_isRep, _state, 0);
		_state = Base.StateUpdateMatch(_state);
		int len = Base.kMatchMinLen;
		_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
		int posSlot = (1 << Base.kNumPosSlotBits) - 1;
		int lenToPosState = Base.GetLenToPosState(len);
		_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
		int footerBits = 30;
		int posReduced = (1 << footerBits) - 1;
		_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
		_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
	}

	void Flush(int nowPos) throws IOException
	{
		ReleaseMFStream();
		WriteEndMarker(nowPos & _posStateMask);
		_rangeEncoder.FlushData();
		_rangeEncoder.FlushStream();
	}

	public void CodeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException
	{
		inSize[0] = 0;
		outSize[0] = 0;
		finished[0] = true;

		if (_inStream != null)
		{
			_matchFinder.SetStream(_inStream);
			_matchFinder.Init();
			_needReleaseMFStream = true;
			_inStream = null;
		}

		if (_finished)
			return;
		_finished = true;


		long progressPosValuePrev = nowPos64;
		if (nowPos64 == 0)
		{
			if (_matchFinder.GetNumAvailableBytes() == 0)
			{
				Flush((int)nowPos64);
				return;
			}

			ReadMatchDistances();
			int posState = (int)(nowPos64) & _posStateMask;
			_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);
			_state = Base.StateUpdateChar(_state);
			byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);
			_literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
			_previousByte = curByte;
			_additionalOffset--;
			nowPos64++;
		}
		if (_matchFinder.GetNumAvailableBytes() == 0)
		{
			Flush((int)nowPos64);
			return;
		}
		while (true)
		{

			int len = GetOptimum((int)nowPos64);
			int pos = backRes;
			int posState = ((int)nowPos64) & _posStateMask;
			int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;
			if (len == 1 && pos == -1)
			{
				_rangeEncoder.Encode(_isMatch, complexState, 0);
				byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
				LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);
				if (!Base.StateIsCharState(_state))
				{
					byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
					subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
				}
				else
					subCoder.Encode(_rangeEncoder, curByte);
				_previousByte = curByte;
				_state = Base.StateUpdateChar(_state);
			}
			else
			{
				_rangeEncoder.Encode(_isMatch, complexState, 1);
				if (pos < Base.kNumRepDistances)
				{
					_rangeEncoder.Encode(_isRep, _state, 1);
					if (pos == 0)
					{
						_rangeEncoder.Encode(_isRepG0, _state, 0);
						if (len == 1)
							_rangeEncoder.Encode(_isRep0Long, complexState, 0);
						else
							_rangeEncoder.Encode(_isRep0Long, complexState, 1);
					}
					else
					{
						_rangeEncoder.Encode(_isRepG0, _state, 1);
						if (pos == 1)
							_rangeEncoder.Encode(_isRepG1, _state, 0);
						else
						{
							_rangeEncoder.Encode(_isRepG1, _state, 1);
							_rangeEncoder.Encode(_isRepG2, _state, pos - 2);
						}
					}
					if (len == 1)
						_state = Base.StateUpdateShortRep(_state);
					else
					{
						_repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
						_state = Base.StateUpdateRep(_state);
					}
					int distance = _repDistances[pos];
					if (pos != 0)
					{
						for (int i = pos; i >= 1; i--)
							_repDistances[i] = _repDistances[i - 1];
						_repDistances[0] = distance;
					}
				}
				else
				{
					_rangeEncoder.Encode(_isRep, _state, 0);
					_state = Base.StateUpdateMatch(_state);
					_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
					pos -= Base.kNumRepDistances;
					int posSlot = GetPosSlot(pos);
					int lenToPosState = Base.GetLenToPosState(len);
					_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);

					if (posSlot >= Base.kStartPosModelIndex)
					{
						int footerBits = (int)((posSlot >> 1) - 1);
						int baseVal = ((2 | (posSlot & 1)) << footerBits);
						int posReduced = pos - baseVal;

						if (posSlot < Base.kEndPosModelIndex)
							BitTreeEncoder.ReverseEncode(_posEncoders,
									baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
						else
						{
							_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
							_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
							_alignPriceCount++;
						}
					}
					int distance = pos;
					for (int i = Base.kNumRepDistances - 1; i >= 1; i--)
						_repDistances[i] = _repDistances[i - 1];
					_repDistances[0] = distance;
					_matchPriceCount++;
				}
				_previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);
			}
			_additionalOffset -= len;
			nowPos64 += len;
			if (_additionalOffset == 0)
			{
				// if (!_fastMode)
				if (_matchPriceCount >= (1 << 7))
					FillDistancesPrices();
				if (_alignPriceCount >= Base.kAlignTableSize)
					FillAlignPrices();
				inSize[0] = nowPos64;
				outSize[0] = _rangeEncoder.GetProcessedSizeAdd();
				if (_matchFinder.GetNumAvailableBytes() == 0)
				{
					Flush((int)nowPos64);
					return;
				}

				if (nowPos64 - progressPosValuePrev >= (1 << 12))
				{
					_finished = false;
					finished[0] = false;
					return;
				}
			}
		}
	}

	void ReleaseMFStream()
	{
		if (_matchFinder != null && _needReleaseMFStream)
		{
			_matchFinder.ReleaseStream();
			_needReleaseMFStream = false;
		}
	}

	void SetOutStream(java.io.OutputStream outStream)
	{ _rangeEncoder.SetStream(outStream); }
	void ReleaseOutStream()
	{ _rangeEncoder.ReleaseStream(); }

	void ReleaseStreams()
	{
		ReleaseMFStream();
		ReleaseOutStream();
	}

	void SetStreams(java.io.InputStream inStream, java.io.OutputStream outStream,
			long inSize, long outSize)
	{
		_inStream = inStream;
		_finished = false;
		Create();
		SetOutStream(outStream);
		Init();

		// if (!_fastMode)
		{
			FillDistancesPrices();
			FillAlignPrices();
		}

		_lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
		_lenEncoder.UpdateTables(1 << _posStateBits);
		_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
		_repMatchLenEncoder.UpdateTables(1 << _posStateBits);

		nowPos64 = 0;
	}

	long[] processedInSize = new long[1]; long[] processedOutSize = new long[1]; boolean[] finished = new boolean[1];
	public void Code(java.io.InputStream inStream, java.io.OutputStream outStream,
			long inSize, long outSize, ICodeProgress progress) throws IOException
	{
		_needReleaseMFStream = false;
		try
		{
			SetStreams(inStream, outStream, inSize, outSize);
			while (true)
			{



				CodeOneBlock(processedInSize, processedOutSize, finished);
				if (finished[0])
					return;
				if (progress != null)
				{
					progress.SetProgress(processedInSize[0], processedOutSize[0]);
				}
			}
		}
		finally
		{
			ReleaseStreams();
		}
	}

	public static final int kPropSize = 5;
	byte[] properties = new byte[kPropSize];

	public void WriteCoderProperties(java.io.OutputStream outStream) throws IOException
	{
		properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
		for (int i = 0; i < 4; i++)
			properties[1 + i] = (byte)(_dictionarySize >> (8 * i));
		outStream.write(properties, 0, kPropSize);
	}

	int[] tempPrices = new int[Base.kNumFullDistances];
	int _matchPriceCount;

	void FillDistancesPrices()
	{
		for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
		{
			int posSlot = GetPosSlot(i);
			int footerBits = (int)((posSlot >> 1) - 1);
			int baseVal = ((2 | (posSlot & 1)) << footerBits);
			tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
				baseVal - posSlot - 1, footerBits, i - baseVal);
		}

		for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
		{
			int posSlot;
			BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];

			int st = (lenToPosState << Base.kNumPosSlotBits);
			for (posSlot = 0; posSlot < _distTableSize; posSlot++)
				_posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
			for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
				_posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << SevenZip.Compression.RangeCoder.Encoder.kNumBitPriceShiftBits);

			int st2 = lenToPosState * Base.kNumFullDistances;
			int i;
			for (i = 0; i < Base.kStartPosModelIndex; i++)
				_distancesPrices[st2 + i] = _posSlotPrices[st + i];
			for (; i < Base.kNumFullDistances; i++)
				_distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
		}
		_matchPriceCount = 0;
	}

	void FillAlignPrices()
	{
		for (int i = 0; i < Base.kAlignTableSize; i++)
			_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
		_alignPriceCount = 0;
	}


	public boolean SetAlgorithm(int algorithm)
	{
		/*
		_fastMode = (algorithm == 0);
		_maxMode = (algorithm >= 2);
		*/
		return true;
	}

	public boolean SetDictionarySize(int dictionarySize)
	{
		int kDicLogSizeMaxCompress = 29;
		if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress))
			return false;
		_dictionarySize = dictionarySize;
		int dicLogSize;
		for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) ;
		_distTableSize = dicLogSize * 2;
		return true;
	}

	public boolean SeNumFastBytes(int numFastBytes)
	{
		if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
			return false;
		_numFastBytes = numFastBytes;
		return true;
	}

	public boolean SetMatchFinder(int matchFinderIndex)
	{
		if (matchFinderIndex < 0 || matchFinderIndex > 2)
			return false;
		int matchFinderIndexPrev = _matchFinderType;
		_matchFinderType = matchFinderIndex;
		if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
		{
			_dictionarySizePrev = -1;
			_matchFinder = null;
		}
		return true;
	}

	public boolean SetLcLpPb(int lc, int lp, int pb)
	{
		if (
				lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax ||
				lc < 0 || lc > Base.kNumLitContextBitsMax ||
				pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax)
			return false;
		_numLiteralPosStateBits = lp;
		_numLiteralContextBits = lc;
		_posStateBits = pb;
		_posStateMask = ((1) << _posStateBits) - 1;
		return true;
	}

	public void SetEndMarkerMode(boolean endMarkerMode)
	{
		_writeEndMark = endMarkerMode;
	}
}