Home | History | Annotate | Download | only in LZMA
      1 package SevenZip.Compression.LZMA;
      2 
      3 import SevenZip.Compression.RangeCoder.BitTreeEncoder;
      4 import SevenZip.Compression.LZMA.Base;
      5 import SevenZip.Compression.LZ.BinTree;
      6 import SevenZip.ICodeProgress;
      7 import java.io.IOException;
      8 
      9 public 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