Home | History | Annotate | Download | only in lzma
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.utils.compression.lzma;
     18 
     19 import java.io.IOException;
     20 
     21 import com.badlogic.gdx.utils.compression.ICodeProgress;
     22 import com.badlogic.gdx.utils.compression.rangecoder.BitTreeEncoder;
     23 
     24 public class Encoder {
     25 	public static final int EMatchFinderTypeBT2 = 0;
     26 	public static final int EMatchFinderTypeBT4 = 1;
     27 
     28 	static final int kIfinityPrice = 0xFFFFFFF;
     29 
     30 	static byte[] g_FastPos = new byte[1 << 11];
     31 
     32 	static {
     33 		int kFastSlots = 22;
     34 		int c = 2;
     35 		g_FastPos[0] = 0;
     36 		g_FastPos[1] = 1;
     37 		for (int slotFast = 2; slotFast < kFastSlots; slotFast++) {
     38 			int k = (1 << ((slotFast >> 1) - 1));
     39 			for (int j = 0; j < k; j++, c++)
     40 				g_FastPos[c] = (byte)slotFast;
     41 		}
     42 	}
     43 
     44 	static int GetPosSlot (int pos) {
     45 		if (pos < (1 << 11)) return g_FastPos[pos];
     46 		if (pos < (1 << 21)) return (g_FastPos[pos >> 10] + 20);
     47 		return (g_FastPos[pos >> 20] + 40);
     48 	}
     49 
     50 	static int GetPosSlot2 (int pos) {
     51 		if (pos < (1 << 17)) return (g_FastPos[pos >> 6] + 12);
     52 		if (pos < (1 << 27)) return (g_FastPos[pos >> 16] + 32);
     53 		return (g_FastPos[pos >> 26] + 52);
     54 	}
     55 
     56 	int _state = Base.StateInit();
     57 	byte _previousByte;
     58 	int[] _repDistances = new int[Base.kNumRepDistances];
     59 
     60 	void BaseInit () {
     61 		_state = Base.StateInit();
     62 		_previousByte = 0;
     63 		for (int i = 0; i < Base.kNumRepDistances; i++)
     64 			_repDistances[i] = 0;
     65 	}
     66 
     67 	static final int kDefaultDictionaryLogSize = 22;
     68 	static final int kNumFastBytesDefault = 0x20;
     69 
     70 	class LiteralEncoder {
     71 		class Encoder2 {
     72 			short[] m_Encoders = new short[0x300];
     73 
     74 			public void Init () {
     75 				com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(m_Encoders);
     76 			}
     77 
     78 			public void Encode (com.badlogic.gdx.utils.compression.rangecoder.Encoder rangeEncoder, byte symbol) throws IOException {
     79 				int context = 1;
     80 				for (int i = 7; i >= 0; i--) {
     81 					int bit = ((symbol >> i) & 1);
     82 					rangeEncoder.Encode(m_Encoders, context, bit);
     83 					context = (context << 1) | bit;
     84 				}
     85 			}
     86 
     87 			public void EncodeMatched (com.badlogic.gdx.utils.compression.rangecoder.Encoder rangeEncoder, byte matchByte,
     88 				byte symbol) throws IOException {
     89 				int context = 1;
     90 				boolean same = true;
     91 				for (int i = 7; i >= 0; i--) {
     92 					int bit = ((symbol >> i) & 1);
     93 					int state = context;
     94 					if (same) {
     95 						int matchBit = ((matchByte >> i) & 1);
     96 						state += ((1 + matchBit) << 8);
     97 						same = (matchBit == bit);
     98 					}
     99 					rangeEncoder.Encode(m_Encoders, state, bit);
    100 					context = (context << 1) | bit;
    101 				}
    102 			}
    103 
    104 			public int GetPrice (boolean matchMode, byte matchByte, byte symbol) {
    105 				int price = 0;
    106 				int context = 1;
    107 				int i = 7;
    108 				if (matchMode) {
    109 					for (; i >= 0; i--) {
    110 						int matchBit = (matchByte >> i) & 1;
    111 						int bit = (symbol >> i) & 1;
    112 						price += com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8)
    113 							+ context], bit);
    114 						context = (context << 1) | bit;
    115 						if (matchBit != bit) {
    116 							i--;
    117 							break;
    118 						}
    119 					}
    120 				}
    121 				for (; i >= 0; i--) {
    122 					int bit = (symbol >> i) & 1;
    123 					price += com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice(m_Encoders[context], bit);
    124 					context = (context << 1) | bit;
    125 				}
    126 				return price;
    127 			}
    128 		}
    129 
    130 		Encoder2[] m_Coders;
    131 		int m_NumPrevBits;
    132 		int m_NumPosBits;
    133 		int m_PosMask;
    134 
    135 		public void Create (int numPosBits, int numPrevBits) {
    136 			if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits) return;
    137 			m_NumPosBits = numPosBits;
    138 			m_PosMask = (1 << numPosBits) - 1;
    139 			m_NumPrevBits = numPrevBits;
    140 			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
    141 			m_Coders = new Encoder2[numStates];
    142 			for (int i = 0; i < numStates; i++)
    143 				m_Coders[i] = new Encoder2();
    144 		}
    145 
    146 		public void Init () {
    147 			int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
    148 			for (int i = 0; i < numStates; i++)
    149 				m_Coders[i].Init();
    150 		}
    151 
    152 		public Encoder2 GetSubCoder (int pos, byte prevByte) {
    153 			return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))];
    154 		}
    155 	}
    156 
    157 	class LenEncoder {
    158 		short[] _choice = new short[2];
    159 		BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
    160 		BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
    161 		BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);
    162 
    163 		public LenEncoder () {
    164 			for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++) {
    165 				_lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);
    166 				_midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);
    167 			}
    168 		}
    169 
    170 		public void Init (int numPosStates) {
    171 			com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_choice);
    172 
    173 			for (int posState = 0; posState < numPosStates; posState++) {
    174 				_lowCoder[posState].Init();
    175 				_midCoder[posState].Init();
    176 			}
    177 			_highCoder.Init();
    178 		}
    179 
    180 		public void Encode (com.badlogic.gdx.utils.compression.rangecoder.Encoder rangeEncoder, int symbol, int posState)
    181 			throws IOException {
    182 			if (symbol < Base.kNumLowLenSymbols) {
    183 				rangeEncoder.Encode(_choice, 0, 0);
    184 				_lowCoder[posState].Encode(rangeEncoder, symbol);
    185 			} else {
    186 				symbol -= Base.kNumLowLenSymbols;
    187 				rangeEncoder.Encode(_choice, 0, 1);
    188 				if (symbol < Base.kNumMidLenSymbols) {
    189 					rangeEncoder.Encode(_choice, 1, 0);
    190 					_midCoder[posState].Encode(rangeEncoder, symbol);
    191 				} else {
    192 					rangeEncoder.Encode(_choice, 1, 1);
    193 					_highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
    194 				}
    195 			}
    196 		}
    197 
    198 		public void SetPrices (int posState, int numSymbols, int[] prices, int st) {
    199 			int a0 = com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_choice[0]);
    200 			int a1 = com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_choice[0]);
    201 			int b0 = a1 + com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_choice[1]);
    202 			int b1 = a1 + com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_choice[1]);
    203 			int i = 0;
    204 			for (i = 0; i < Base.kNumLowLenSymbols; i++) {
    205 				if (i >= numSymbols) return;
    206 				prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
    207 			}
    208 			for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++) {
    209 				if (i >= numSymbols) return;
    210 				prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
    211 			}
    212 			for (; i < numSymbols; i++)
    213 				prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
    214 		}
    215 	};
    216 
    217 	public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
    218 
    219 	class LenPriceTableEncoder extends LenEncoder {
    220 		int[] _prices = new int[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax];
    221 		int _tableSize;
    222 		int[] _counters = new int[Base.kNumPosStatesEncodingMax];
    223 
    224 		public void SetTableSize (int tableSize) {
    225 			_tableSize = tableSize;
    226 		}
    227 
    228 		public int GetPrice (int symbol, int posState) {
    229 			return _prices[posState * Base.kNumLenSymbols + symbol];
    230 		}
    231 
    232 		void UpdateTable (int posState) {
    233 			SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
    234 			_counters[posState] = _tableSize;
    235 		}
    236 
    237 		public void UpdateTables (int numPosStates) {
    238 			for (int posState = 0; posState < numPosStates; posState++)
    239 				UpdateTable(posState);
    240 		}
    241 
    242 		public void Encode (com.badlogic.gdx.utils.compression.rangecoder.Encoder rangeEncoder, int symbol, int posState)
    243 			throws IOException {
    244 			super.Encode(rangeEncoder, symbol, posState);
    245 			if (--_counters[posState] == 0) UpdateTable(posState);
    246 		}
    247 	}
    248 
    249 	static final int kNumOpts = 1 << 12;
    250 
    251 	class Optimal {
    252 		public int State;
    253 
    254 		public boolean Prev1IsChar;
    255 		public boolean Prev2;
    256 
    257 		public int PosPrev2;
    258 		public int BackPrev2;
    259 
    260 		public int Price;
    261 		public int PosPrev;
    262 		public int BackPrev;
    263 
    264 		public int Backs0;
    265 		public int Backs1;
    266 		public int Backs2;
    267 		public int Backs3;
    268 
    269 		public void MakeAsChar () {
    270 			BackPrev = -1;
    271 			Prev1IsChar = false;
    272 		}
    273 
    274 		public void MakeAsShortRep () {
    275 			BackPrev = 0;
    276 			;
    277 			Prev1IsChar = false;
    278 		}
    279 
    280 		public boolean IsShortRep () {
    281 			return (BackPrev == 0);
    282 		}
    283 	};
    284 
    285 	Optimal[] _optimum = new Optimal[kNumOpts];
    286 	com.badlogic.gdx.utils.compression.lz.BinTree _matchFinder = null;
    287 	com.badlogic.gdx.utils.compression.rangecoder.Encoder _rangeEncoder = new com.badlogic.gdx.utils.compression.rangecoder.Encoder();
    288 
    289 	short[] _isMatch = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
    290 	short[] _isRep = new short[Base.kNumStates];
    291 	short[] _isRepG0 = new short[Base.kNumStates];
    292 	short[] _isRepG1 = new short[Base.kNumStates];
    293 	short[] _isRepG2 = new short[Base.kNumStates];
    294 	short[] _isRep0Long = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
    295 
    296 	BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits
    297 
    298 	short[] _posEncoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex];
    299 	BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);
    300 
    301 	LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
    302 	LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
    303 
    304 	LiteralEncoder _literalEncoder = new LiteralEncoder();
    305 
    306 	int[] _matchDistances = new int[Base.kMatchMaxLen * 2 + 2];
    307 
    308 	int _numFastBytes = kNumFastBytesDefault;
    309 	int _longestMatchLength;
    310 	int _numDistancePairs;
    311 
    312 	int _additionalOffset;
    313 
    314 	int _optimumEndIndex;
    315 	int _optimumCurrentIndex;
    316 
    317 	boolean _longestMatchWasFound;
    318 
    319 	int[] _posSlotPrices = new int[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)];
    320 	int[] _distancesPrices = new int[Base.kNumFullDistances << Base.kNumLenToPosStatesBits];
    321 	int[] _alignPrices = new int[Base.kAlignTableSize];
    322 	int _alignPriceCount;
    323 
    324 	int _distTableSize = (kDefaultDictionaryLogSize * 2);
    325 
    326 	int _posStateBits = 2;
    327 	int _posStateMask = (4 - 1);
    328 	int _numLiteralPosStateBits = 0;
    329 	int _numLiteralContextBits = 3;
    330 
    331 	int _dictionarySize = (1 << kDefaultDictionaryLogSize);
    332 	int _dictionarySizePrev = -1;
    333 	int _numFastBytesPrev = -1;
    334 
    335 	long nowPos64;
    336 	boolean _finished;
    337 	java.io.InputStream _inStream;
    338 
    339 	int _matchFinderType = EMatchFinderTypeBT4;
    340 	boolean _writeEndMark = false;
    341 
    342 	boolean _needReleaseMFStream = false;
    343 
    344 	void Create () {
    345 		if (_matchFinder == null) {
    346 			com.badlogic.gdx.utils.compression.lz.BinTree bt = new com.badlogic.gdx.utils.compression.lz.BinTree();
    347 			int numHashBytes = 4;
    348 			if (_matchFinderType == EMatchFinderTypeBT2) numHashBytes = 2;
    349 			bt.SetType(numHashBytes);
    350 			_matchFinder = bt;
    351 		}
    352 		_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
    353 
    354 		if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes) return;
    355 		_matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
    356 		_dictionarySizePrev = _dictionarySize;
    357 		_numFastBytesPrev = _numFastBytes;
    358 	}
    359 
    360 	public Encoder () {
    361 		for (int i = 0; i < kNumOpts; i++)
    362 			_optimum[i] = new Optimal();
    363 		for (int i = 0; i < Base.kNumLenToPosStates; i++)
    364 			_posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits);
    365 	}
    366 
    367 	void SetWriteEndMarkerMode (boolean writeEndMarker) {
    368 		_writeEndMark = writeEndMarker;
    369 	}
    370 
    371 	void Init () {
    372 		BaseInit();
    373 		_rangeEncoder.Init();
    374 
    375 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_isMatch);
    376 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_isRep0Long);
    377 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_isRep);
    378 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_isRepG0);
    379 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_isRepG1);
    380 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_isRepG2);
    381 		com.badlogic.gdx.utils.compression.rangecoder.Encoder.InitBitModels(_posEncoders);
    382 
    383 		_literalEncoder.Init();
    384 		for (int i = 0; i < Base.kNumLenToPosStates; i++)
    385 			_posSlotEncoder[i].Init();
    386 
    387 		_lenEncoder.Init(1 << _posStateBits);
    388 		_repMatchLenEncoder.Init(1 << _posStateBits);
    389 
    390 		_posAlignEncoder.Init();
    391 
    392 		_longestMatchWasFound = false;
    393 		_optimumEndIndex = 0;
    394 		_optimumCurrentIndex = 0;
    395 		_additionalOffset = 0;
    396 	}
    397 
    398 	int ReadMatchDistances () throws java.io.IOException {
    399 		int lenRes = 0;
    400 		_numDistancePairs = _matchFinder.GetMatches(_matchDistances);
    401 		if (_numDistancePairs > 0) {
    402 			lenRes = _matchDistances[_numDistancePairs - 2];
    403 			if (lenRes == _numFastBytes)
    404 				lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[_numDistancePairs - 1], Base.kMatchMaxLen
    405 					- lenRes);
    406 		}
    407 		_additionalOffset++;
    408 		return lenRes;
    409 	}
    410 
    411 	void MovePos (int num) throws java.io.IOException {
    412 		if (num > 0) {
    413 			_matchFinder.Skip(num);
    414 			_additionalOffset += num;
    415 		}
    416 	}
    417 
    418 	int GetRepLen1Price (int state, int posState) {
    419 		return com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isRepG0[state])
    420 			+ com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax)
    421 				+ posState]);
    422 	}
    423 
    424 	int GetPureRepPrice (int repIndex, int state, int posState) {
    425 		int price;
    426 		if (repIndex == 0) {
    427 			price = com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isRepG0[state]);
    428 			price += com.badlogic.gdx.utils.compression.rangecoder.Encoder
    429 				.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
    430 		} else {
    431 			price = com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRepG0[state]);
    432 			if (repIndex == 1)
    433 				price += com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isRepG1[state]);
    434 			else {
    435 				price += com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRepG1[state]);
    436 				price += com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);
    437 			}
    438 		}
    439 		return price;
    440 	}
    441 
    442 	int GetRepPrice (int repIndex, int len, int state, int posState) {
    443 		int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
    444 		return price + GetPureRepPrice(repIndex, state, posState);
    445 	}
    446 
    447 	int GetPosLenPrice (int pos, int len, int posState) {
    448 		int price;
    449 		int lenToPosState = Base.GetLenToPosState(len);
    450 		if (pos < Base.kNumFullDistances)
    451 			price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
    452 		else
    453 			price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] + _alignPrices[pos & Base.kAlignMask];
    454 		return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
    455 	}
    456 
    457 	int Backward (int cur) {
    458 		_optimumEndIndex = cur;
    459 		int posMem = _optimum[cur].PosPrev;
    460 		int backMem = _optimum[cur].BackPrev;
    461 		do {
    462 			if (_optimum[cur].Prev1IsChar) {
    463 				_optimum[posMem].MakeAsChar();
    464 				_optimum[posMem].PosPrev = posMem - 1;
    465 				if (_optimum[cur].Prev2) {
    466 					_optimum[posMem - 1].Prev1IsChar = false;
    467 					_optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
    468 					_optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
    469 				}
    470 			}
    471 			int posPrev = posMem;
    472 			int backCur = backMem;
    473 
    474 			backMem = _optimum[posPrev].BackPrev;
    475 			posMem = _optimum[posPrev].PosPrev;
    476 
    477 			_optimum[posPrev].BackPrev = backCur;
    478 			_optimum[posPrev].PosPrev = cur;
    479 			cur = posPrev;
    480 		} while (cur > 0);
    481 		backRes = _optimum[0].BackPrev;
    482 		_optimumCurrentIndex = _optimum[0].PosPrev;
    483 		return _optimumCurrentIndex;
    484 	}
    485 
    486 	int[] reps = new int[Base.kNumRepDistances];
    487 	int[] repLens = new int[Base.kNumRepDistances];
    488 	int backRes;
    489 
    490 	int GetOptimum (int position) throws IOException {
    491 		if (_optimumEndIndex != _optimumCurrentIndex) {
    492 			int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
    493 			backRes = _optimum[_optimumCurrentIndex].BackPrev;
    494 			_optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
    495 			return lenRes;
    496 		}
    497 		_optimumCurrentIndex = _optimumEndIndex = 0;
    498 
    499 		int lenMain, numDistancePairs;
    500 		if (!_longestMatchWasFound) {
    501 			lenMain = ReadMatchDistances();
    502 		} else {
    503 			lenMain = _longestMatchLength;
    504 			_longestMatchWasFound = false;
    505 		}
    506 		numDistancePairs = _numDistancePairs;
    507 
    508 		int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
    509 		if (numAvailableBytes < 2) {
    510 			backRes = -1;
    511 			return 1;
    512 		}
    513 		if (numAvailableBytes > Base.kMatchMaxLen) numAvailableBytes = Base.kMatchMaxLen;
    514 
    515 		int repMaxIndex = 0;
    516 		int i;
    517 		for (i = 0; i < Base.kNumRepDistances; i++) {
    518 			reps[i] = _repDistances[i];
    519 			repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
    520 			if (repLens[i] > repLens[repMaxIndex]) repMaxIndex = i;
    521 		}
    522 		if (repLens[repMaxIndex] >= _numFastBytes) {
    523 			backRes = repMaxIndex;
    524 			int lenRes = repLens[repMaxIndex];
    525 			MovePos(lenRes - 1);
    526 			return lenRes;
    527 		}
    528 
    529 		if (lenMain >= _numFastBytes) {
    530 			backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
    531 			MovePos(lenMain - 1);
    532 			return lenMain;
    533 		}
    534 
    535 		byte currentByte = _matchFinder.GetIndexByte(0 - 1);
    536 		byte matchByte = _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1);
    537 
    538 		if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2) {
    539 			backRes = -1;
    540 			return 1;
    541 		}
    542 
    543 		_optimum[0].State = _state;
    544 
    545 		int posState = (position & _posStateMask);
    546 
    547 		_optimum[1].Price = com.badlogic.gdx.utils.compression.rangecoder.Encoder
    548 			.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState])
    549 			+ _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);
    550 		_optimum[1].MakeAsChar();
    551 
    552 		int matchPrice = com.badlogic.gdx.utils.compression.rangecoder.Encoder
    553 			.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);
    554 		int repMatchPrice = matchPrice + com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRep[_state]);
    555 
    556 		if (matchByte == currentByte) {
    557 			int shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
    558 			if (shortRepPrice < _optimum[1].Price) {
    559 				_optimum[1].Price = shortRepPrice;
    560 				_optimum[1].MakeAsShortRep();
    561 			}
    562 		}
    563 
    564 		int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
    565 
    566 		if (lenEnd < 2) {
    567 			backRes = _optimum[1].BackPrev;
    568 			return 1;
    569 		}
    570 
    571 		_optimum[1].PosPrev = 0;
    572 
    573 		_optimum[0].Backs0 = reps[0];
    574 		_optimum[0].Backs1 = reps[1];
    575 		_optimum[0].Backs2 = reps[2];
    576 		_optimum[0].Backs3 = reps[3];
    577 
    578 		int len = lenEnd;
    579 		do
    580 			_optimum[len--].Price = kIfinityPrice;
    581 		while (len >= 2);
    582 
    583 		for (i = 0; i < Base.kNumRepDistances; i++) {
    584 			int repLen = repLens[i];
    585 			if (repLen < 2) continue;
    586 			int price = repMatchPrice + GetPureRepPrice(i, _state, posState);
    587 			do {
    588 				int curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
    589 				Optimal optimum = _optimum[repLen];
    590 				if (curAndLenPrice < optimum.Price) {
    591 					optimum.Price = curAndLenPrice;
    592 					optimum.PosPrev = 0;
    593 					optimum.BackPrev = i;
    594 					optimum.Prev1IsChar = false;
    595 				}
    596 			} while (--repLen >= 2);
    597 		}
    598 
    599 		int normalMatchPrice = matchPrice + com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isRep[_state]);
    600 
    601 		len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
    602 		if (len <= lenMain) {
    603 			int offs = 0;
    604 			while (len > _matchDistances[offs])
    605 				offs += 2;
    606 			for (;; len++) {
    607 				int distance = _matchDistances[offs + 1];
    608 				int curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
    609 				Optimal optimum = _optimum[len];
    610 				if (curAndLenPrice < optimum.Price) {
    611 					optimum.Price = curAndLenPrice;
    612 					optimum.PosPrev = 0;
    613 					optimum.BackPrev = distance + Base.kNumRepDistances;
    614 					optimum.Prev1IsChar = false;
    615 				}
    616 				if (len == _matchDistances[offs]) {
    617 					offs += 2;
    618 					if (offs == numDistancePairs) break;
    619 				}
    620 			}
    621 		}
    622 
    623 		int cur = 0;
    624 
    625 		while (true) {
    626 			cur++;
    627 			if (cur == lenEnd) return Backward(cur);
    628 			int newLen = ReadMatchDistances();
    629 			numDistancePairs = _numDistancePairs;
    630 			if (newLen >= _numFastBytes) {
    631 
    632 				_longestMatchLength = newLen;
    633 				_longestMatchWasFound = true;
    634 				return Backward(cur);
    635 			}
    636 			position++;
    637 			int posPrev = _optimum[cur].PosPrev;
    638 			int state;
    639 			if (_optimum[cur].Prev1IsChar) {
    640 				posPrev--;
    641 				if (_optimum[cur].Prev2) {
    642 					state = _optimum[_optimum[cur].PosPrev2].State;
    643 					if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
    644 						state = Base.StateUpdateRep(state);
    645 					else
    646 						state = Base.StateUpdateMatch(state);
    647 				} else
    648 					state = _optimum[posPrev].State;
    649 				state = Base.StateUpdateChar(state);
    650 			} else
    651 				state = _optimum[posPrev].State;
    652 			if (posPrev == cur - 1) {
    653 				if (_optimum[cur].IsShortRep())
    654 					state = Base.StateUpdateShortRep(state);
    655 				else
    656 					state = Base.StateUpdateChar(state);
    657 			} else {
    658 				int pos;
    659 				if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2) {
    660 					posPrev = _optimum[cur].PosPrev2;
    661 					pos = _optimum[cur].BackPrev2;
    662 					state = Base.StateUpdateRep(state);
    663 				} else {
    664 					pos = _optimum[cur].BackPrev;
    665 					if (pos < Base.kNumRepDistances)
    666 						state = Base.StateUpdateRep(state);
    667 					else
    668 						state = Base.StateUpdateMatch(state);
    669 				}
    670 				Optimal opt = _optimum[posPrev];
    671 				if (pos < Base.kNumRepDistances) {
    672 					if (pos == 0) {
    673 						reps[0] = opt.Backs0;
    674 						reps[1] = opt.Backs1;
    675 						reps[2] = opt.Backs2;
    676 						reps[3] = opt.Backs3;
    677 					} else if (pos == 1) {
    678 						reps[0] = opt.Backs1;
    679 						reps[1] = opt.Backs0;
    680 						reps[2] = opt.Backs2;
    681 						reps[3] = opt.Backs3;
    682 					} else if (pos == 2) {
    683 						reps[0] = opt.Backs2;
    684 						reps[1] = opt.Backs0;
    685 						reps[2] = opt.Backs1;
    686 						reps[3] = opt.Backs3;
    687 					} else {
    688 						reps[0] = opt.Backs3;
    689 						reps[1] = opt.Backs0;
    690 						reps[2] = opt.Backs1;
    691 						reps[3] = opt.Backs2;
    692 					}
    693 				} else {
    694 					reps[0] = (pos - Base.kNumRepDistances);
    695 					reps[1] = opt.Backs0;
    696 					reps[2] = opt.Backs1;
    697 					reps[3] = opt.Backs2;
    698 				}
    699 			}
    700 			_optimum[cur].State = state;
    701 			_optimum[cur].Backs0 = reps[0];
    702 			_optimum[cur].Backs1 = reps[1];
    703 			_optimum[cur].Backs2 = reps[2];
    704 			_optimum[cur].Backs3 = reps[3];
    705 			int curPrice = _optimum[cur].Price;
    706 
    707 			currentByte = _matchFinder.GetIndexByte(0 - 1);
    708 			matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);
    709 
    710 			posState = (position & _posStateMask);
    711 
    712 			int curAnd1Price = curPrice
    713 				+ com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax)
    714 					+ posState])
    715 				+ _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).GetPrice(!Base.StateIsCharState(state),
    716 					matchByte, currentByte);
    717 
    718 			Optimal nextOptimum = _optimum[cur + 1];
    719 
    720 			boolean nextIsChar = false;
    721 			if (curAnd1Price < nextOptimum.Price) {
    722 				nextOptimum.Price = curAnd1Price;
    723 				nextOptimum.PosPrev = cur;
    724 				nextOptimum.MakeAsChar();
    725 				nextIsChar = true;
    726 			}
    727 
    728 			matchPrice = curPrice
    729 				+ com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax)
    730 					+ posState]);
    731 			repMatchPrice = matchPrice + com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRep[state]);
    732 
    733 			if (matchByte == currentByte && !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0)) {
    734 				int shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
    735 				if (shortRepPrice <= nextOptimum.Price) {
    736 					nextOptimum.Price = shortRepPrice;
    737 					nextOptimum.PosPrev = cur;
    738 					nextOptimum.MakeAsShortRep();
    739 					nextIsChar = true;
    740 				}
    741 			}
    742 
    743 			int numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
    744 			numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull);
    745 			numAvailableBytes = numAvailableBytesFull;
    746 
    747 			if (numAvailableBytes < 2) continue;
    748 			if (numAvailableBytes > _numFastBytes) numAvailableBytes = _numFastBytes;
    749 			if (!nextIsChar && matchByte != currentByte) {
    750 				// try Literal + rep0
    751 				int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);
    752 				int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
    753 				if (lenTest2 >= 2) {
    754 					int state2 = Base.StateUpdateChar(state);
    755 
    756 					int posStateNext = (position + 1) & _posStateMask;
    757 					int nextRepMatchPrice = curAnd1Price
    758 						+ com.badlogic.gdx.utils.compression.rangecoder.Encoder
    759 							.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext])
    760 						+ com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRep[state2]);
    761 					{
    762 						int offset = cur + 1 + lenTest2;
    763 						while (lenEnd < offset)
    764 							_optimum[++lenEnd].Price = kIfinityPrice;
    765 						int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
    766 						Optimal optimum = _optimum[offset];
    767 						if (curAndLenPrice < optimum.Price) {
    768 							optimum.Price = curAndLenPrice;
    769 							optimum.PosPrev = cur + 1;
    770 							optimum.BackPrev = 0;
    771 							optimum.Prev1IsChar = true;
    772 							optimum.Prev2 = false;
    773 						}
    774 					}
    775 				}
    776 			}
    777 
    778 			int startLen = 2; // speed optimization
    779 
    780 			for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++) {
    781 				int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
    782 				if (lenTest < 2) continue;
    783 				int lenTestTemp = lenTest;
    784 				do {
    785 					while (lenEnd < cur + lenTest)
    786 						_optimum[++lenEnd].Price = kIfinityPrice;
    787 					int curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
    788 					Optimal optimum = _optimum[cur + lenTest];
    789 					if (curAndLenPrice < optimum.Price) {
    790 						optimum.Price = curAndLenPrice;
    791 						optimum.PosPrev = cur;
    792 						optimum.BackPrev = repIndex;
    793 						optimum.Prev1IsChar = false;
    794 					}
    795 				} while (--lenTest >= 2);
    796 				lenTest = lenTestTemp;
    797 
    798 				if (repIndex == 0) startLen = lenTest + 1;
    799 
    800 				// if (_maxMode)
    801 				if (lenTest < numAvailableBytesFull) {
    802 					int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
    803 					int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);
    804 					if (lenTest2 >= 2) {
    805 						int state2 = Base.StateUpdateRep(state);
    806 
    807 						int posStateNext = (position + lenTest) & _posStateMask;
    808 						int curAndLenCharPrice = repMatchPrice
    809 							+ GetRepPrice(repIndex, lenTest, state, posState)
    810 							+ com.badlogic.gdx.utils.compression.rangecoder.Encoder
    811 								.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext])
    812 							+ _literalEncoder.GetSubCoder(position + lenTest, _matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,
    813 								_matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)), _matchFinder.GetIndexByte(lenTest - 1));
    814 						state2 = Base.StateUpdateChar(state2);
    815 						posStateNext = (position + lenTest + 1) & _posStateMask;
    816 						int nextMatchPrice = curAndLenCharPrice
    817 							+ com.badlogic.gdx.utils.compression.rangecoder.Encoder
    818 								.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
    819 						int nextRepMatchPrice = nextMatchPrice
    820 							+ com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRep[state2]);
    821 
    822 						// for(; lenTest2 >= 2; lenTest2--)
    823 						{
    824 							int offset = lenTest + 1 + lenTest2;
    825 							while (lenEnd < cur + offset)
    826 								_optimum[++lenEnd].Price = kIfinityPrice;
    827 							int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
    828 							Optimal optimum = _optimum[cur + offset];
    829 							if (curAndLenPrice < optimum.Price) {
    830 								optimum.Price = curAndLenPrice;
    831 								optimum.PosPrev = cur + lenTest + 1;
    832 								optimum.BackPrev = 0;
    833 								optimum.Prev1IsChar = true;
    834 								optimum.Prev2 = true;
    835 								optimum.PosPrev2 = cur;
    836 								optimum.BackPrev2 = repIndex;
    837 							}
    838 						}
    839 					}
    840 				}
    841 			}
    842 
    843 			if (newLen > numAvailableBytes) {
    844 				newLen = numAvailableBytes;
    845 				for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2)
    846 					;
    847 				_matchDistances[numDistancePairs] = newLen;
    848 				numDistancePairs += 2;
    849 			}
    850 			if (newLen >= startLen) {
    851 				normalMatchPrice = matchPrice + com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice0(_isRep[state]);
    852 				while (lenEnd < cur + newLen)
    853 					_optimum[++lenEnd].Price = kIfinityPrice;
    854 
    855 				int offs = 0;
    856 				while (startLen > _matchDistances[offs])
    857 					offs += 2;
    858 
    859 				for (int lenTest = startLen;; lenTest++) {
    860 					int curBack = _matchDistances[offs + 1];
    861 					int curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
    862 					Optimal optimum = _optimum[cur + lenTest];
    863 					if (curAndLenPrice < optimum.Price) {
    864 						optimum.Price = curAndLenPrice;
    865 						optimum.PosPrev = cur;
    866 						optimum.BackPrev = curBack + Base.kNumRepDistances;
    867 						optimum.Prev1IsChar = false;
    868 					}
    869 
    870 					if (lenTest == _matchDistances[offs]) {
    871 						if (lenTest < numAvailableBytesFull) {
    872 							int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
    873 							int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);
    874 							if (lenTest2 >= 2) {
    875 								int state2 = Base.StateUpdateMatch(state);
    876 
    877 								int posStateNext = (position + lenTest) & _posStateMask;
    878 								int curAndLenCharPrice = curAndLenPrice
    879 									+ com.badlogic.gdx.utils.compression.rangecoder.Encoder
    880 										.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext])
    881 									+ _literalEncoder.GetSubCoder(position + lenTest, _matchFinder.GetIndexByte(lenTest - 1 - 1))
    882 										.GetPrice(true, _matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),
    883 											_matchFinder.GetIndexByte(lenTest - 1));
    884 								state2 = Base.StateUpdateChar(state2);
    885 								posStateNext = (position + lenTest + 1) & _posStateMask;
    886 								int nextMatchPrice = curAndLenCharPrice
    887 									+ com.badlogic.gdx.utils.compression.rangecoder.Encoder
    888 										.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
    889 								int nextRepMatchPrice = nextMatchPrice
    890 									+ com.badlogic.gdx.utils.compression.rangecoder.Encoder.GetPrice1(_isRep[state2]);
    891 
    892 								int offset = lenTest + 1 + lenTest2;
    893 								while (lenEnd < cur + offset)
    894 									_optimum[++lenEnd].Price = kIfinityPrice;
    895 								curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
    896 								optimum = _optimum[cur + offset];
    897 								if (curAndLenPrice < optimum.Price) {
    898 									optimum.Price = curAndLenPrice;
    899 									optimum.PosPrev = cur + lenTest + 1;
    900 									optimum.BackPrev = 0;
    901 									optimum.Prev1IsChar = true;
    902 									optimum.Prev2 = true;
    903 									optimum.PosPrev2 = cur;
    904 									optimum.BackPrev2 = curBack + Base.kNumRepDistances;
    905 								}
    906 							}
    907 						}
    908 						offs += 2;
    909 						if (offs == numDistancePairs) break;
    910 					}
    911 				}
    912 			}
    913 		}
    914 	}
    915 
    916 	boolean ChangePair (int smallDist, int bigDist) {
    917 		int kDif = 7;
    918 		return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));
    919 	}
    920 
    921 	void WriteEndMarker (int posState) throws IOException {
    922 		if (!_writeEndMark) return;
    923 
    924 		_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);
    925 		_rangeEncoder.Encode(_isRep, _state, 0);
    926 		_state = Base.StateUpdateMatch(_state);
    927 		int len = Base.kMatchMinLen;
    928 		_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
    929 		int posSlot = (1 << Base.kNumPosSlotBits) - 1;
    930 		int lenToPosState = Base.GetLenToPosState(len);
    931 		_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
    932 		int footerBits = 30;
    933 		int posReduced = (1 << footerBits) - 1;
    934 		_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
    935 		_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
    936 	}
    937 
    938 	void Flush (int nowPos) throws IOException {
    939 		ReleaseMFStream();
    940 		WriteEndMarker(nowPos & _posStateMask);
    941 		_rangeEncoder.FlushData();
    942 		_rangeEncoder.FlushStream();
    943 	}
    944 
    945 	public void CodeOneBlock (long[] inSize, long[] outSize, boolean[] finished) throws IOException {
    946 		inSize[0] = 0;
    947 		outSize[0] = 0;
    948 		finished[0] = true;
    949 
    950 		if (_inStream != null) {
    951 			_matchFinder.SetStream(_inStream);
    952 			_matchFinder.Init();
    953 			_needReleaseMFStream = true;
    954 			_inStream = null;
    955 		}
    956 
    957 		if (_finished) return;
    958 		_finished = true;
    959 
    960 		long progressPosValuePrev = nowPos64;
    961 		if (nowPos64 == 0) {
    962 			if (_matchFinder.GetNumAvailableBytes() == 0) {
    963 				Flush((int)nowPos64);
    964 				return;
    965 			}
    966 
    967 			ReadMatchDistances();
    968 			int posState = (int)(nowPos64) & _posStateMask;
    969 			_rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);
    970 			_state = Base.StateUpdateChar(_state);
    971 			byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);
    972 			_literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
    973 			_previousByte = curByte;
    974 			_additionalOffset--;
    975 			nowPos64++;
    976 		}
    977 		if (_matchFinder.GetNumAvailableBytes() == 0) {
    978 			Flush((int)nowPos64);
    979 			return;
    980 		}
    981 		while (true) {
    982 
    983 			int len = GetOptimum((int)nowPos64);
    984 			int pos = backRes;
    985 			int posState = ((int)nowPos64) & _posStateMask;
    986 			int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;
    987 			if (len == 1 && pos == -1) {
    988 				_rangeEncoder.Encode(_isMatch, complexState, 0);
    989 				byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
    990 				LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);
    991 				if (!Base.StateIsCharState(_state)) {
    992 					byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
    993 					subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
    994 				} else
    995 					subCoder.Encode(_rangeEncoder, curByte);
    996 				_previousByte = curByte;
    997 				_state = Base.StateUpdateChar(_state);
    998 			} else {
    999 				_rangeEncoder.Encode(_isMatch, complexState, 1);
   1000 				if (pos < Base.kNumRepDistances) {
   1001 					_rangeEncoder.Encode(_isRep, _state, 1);
   1002 					if (pos == 0) {
   1003 						_rangeEncoder.Encode(_isRepG0, _state, 0);
   1004 						if (len == 1)
   1005 							_rangeEncoder.Encode(_isRep0Long, complexState, 0);
   1006 						else
   1007 							_rangeEncoder.Encode(_isRep0Long, complexState, 1);
   1008 					} else {
   1009 						_rangeEncoder.Encode(_isRepG0, _state, 1);
   1010 						if (pos == 1)
   1011 							_rangeEncoder.Encode(_isRepG1, _state, 0);
   1012 						else {
   1013 							_rangeEncoder.Encode(_isRepG1, _state, 1);
   1014 							_rangeEncoder.Encode(_isRepG2, _state, pos - 2);
   1015 						}
   1016 					}
   1017 					if (len == 1)
   1018 						_state = Base.StateUpdateShortRep(_state);
   1019 					else {
   1020 						_repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
   1021 						_state = Base.StateUpdateRep(_state);
   1022 					}
   1023 					int distance = _repDistances[pos];
   1024 					if (pos != 0) {
   1025 						for (int i = pos; i >= 1; i--)
   1026 							_repDistances[i] = _repDistances[i - 1];
   1027 						_repDistances[0] = distance;
   1028 					}
   1029 				} else {
   1030 					_rangeEncoder.Encode(_isRep, _state, 0);
   1031 					_state = Base.StateUpdateMatch(_state);
   1032 					_lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
   1033 					pos -= Base.kNumRepDistances;
   1034 					int posSlot = GetPosSlot(pos);
   1035 					int lenToPosState = Base.GetLenToPosState(len);
   1036 					_posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
   1037 
   1038 					if (posSlot >= Base.kStartPosModelIndex) {
   1039 						int footerBits = (int)((posSlot >> 1) - 1);
   1040 						int baseVal = ((2 | (posSlot & 1)) << footerBits);
   1041 						int posReduced = pos - baseVal;
   1042 
   1043 						if (posSlot < Base.kEndPosModelIndex)
   1044 							BitTreeEncoder.ReverseEncode(_posEncoders, baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
   1045 						else {
   1046 							_rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
   1047 							_posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
   1048 							_alignPriceCount++;
   1049 						}
   1050 					}
   1051 					int distance = pos;
   1052 					for (int i = Base.kNumRepDistances - 1; i >= 1; i--)
   1053 						_repDistances[i] = _repDistances[i - 1];
   1054 					_repDistances[0] = distance;
   1055 					_matchPriceCount++;
   1056 				}
   1057 				_previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);
   1058 			}
   1059 			_additionalOffset -= len;
   1060 			nowPos64 += len;
   1061 			if (_additionalOffset == 0) {
   1062 				// if (!_fastMode)
   1063 				if (_matchPriceCount >= (1 << 7)) FillDistancesPrices();
   1064 				if (_alignPriceCount >= Base.kAlignTableSize) FillAlignPrices();
   1065 				inSize[0] = nowPos64;
   1066 				outSize[0] = _rangeEncoder.GetProcessedSizeAdd();
   1067 				if (_matchFinder.GetNumAvailableBytes() == 0) {
   1068 					Flush((int)nowPos64);
   1069 					return;
   1070 				}
   1071 
   1072 				if (nowPos64 - progressPosValuePrev >= (1 << 12)) {
   1073 					_finished = false;
   1074 					finished[0] = false;
   1075 					return;
   1076 				}
   1077 			}
   1078 		}
   1079 	}
   1080 
   1081 	void ReleaseMFStream () {
   1082 		if (_matchFinder != null && _needReleaseMFStream) {
   1083 			_matchFinder.ReleaseStream();
   1084 			_needReleaseMFStream = false;
   1085 		}
   1086 	}
   1087 
   1088 	void SetOutStream (java.io.OutputStream outStream) {
   1089 		_rangeEncoder.SetStream(outStream);
   1090 	}
   1091 
   1092 	void ReleaseOutStream () {
   1093 		_rangeEncoder.ReleaseStream();
   1094 	}
   1095 
   1096 	void ReleaseStreams () {
   1097 		ReleaseMFStream();
   1098 		ReleaseOutStream();
   1099 	}
   1100 
   1101 	void SetStreams (java.io.InputStream inStream, java.io.OutputStream outStream, long inSize, long outSize) {
   1102 		_inStream = inStream;
   1103 		_finished = false;
   1104 		Create();
   1105 		SetOutStream(outStream);
   1106 		Init();
   1107 
   1108 		// if (!_fastMode)
   1109 		{
   1110 			FillDistancesPrices();
   1111 			FillAlignPrices();
   1112 		}
   1113 
   1114 		_lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
   1115 		_lenEncoder.UpdateTables(1 << _posStateBits);
   1116 		_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
   1117 		_repMatchLenEncoder.UpdateTables(1 << _posStateBits);
   1118 
   1119 		nowPos64 = 0;
   1120 	}
   1121 
   1122 	long[] processedInSize = new long[1];
   1123 	long[] processedOutSize = new long[1];
   1124 	boolean[] finished = new boolean[1];
   1125 
   1126 	public void Code (java.io.InputStream inStream, java.io.OutputStream outStream, long inSize, long outSize,
   1127 		ICodeProgress progress) throws IOException {
   1128 		_needReleaseMFStream = false;
   1129 		try {
   1130 			SetStreams(inStream, outStream, inSize, outSize);
   1131 			while (true) {
   1132 
   1133 				CodeOneBlock(processedInSize, processedOutSize, finished);
   1134 				if (finished[0]) return;
   1135 				if (progress != null) {
   1136 					progress.SetProgress(processedInSize[0], processedOutSize[0]);
   1137 				}
   1138 			}
   1139 		} finally {
   1140 			ReleaseStreams();
   1141 		}
   1142 	}
   1143 
   1144 	public static final int kPropSize = 5;
   1145 	byte[] properties = new byte[kPropSize];
   1146 
   1147 	public void WriteCoderProperties (java.io.OutputStream outStream) throws IOException {
   1148 		properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
   1149 		for (int i = 0; i < 4; i++)
   1150 			properties[1 + i] = (byte)(_dictionarySize >> (8 * i));
   1151 		outStream.write(properties, 0, kPropSize);
   1152 	}
   1153 
   1154 	int[] tempPrices = new int[Base.kNumFullDistances];
   1155 	int _matchPriceCount;
   1156 
   1157 	void FillDistancesPrices () {
   1158 		for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++) {
   1159 			int posSlot = GetPosSlot(i);
   1160 			int footerBits = (int)((posSlot >> 1) - 1);
   1161 			int baseVal = ((2 | (posSlot & 1)) << footerBits);
   1162 			tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders, baseVal - posSlot - 1, footerBits, i - baseVal);
   1163 		}
   1164 
   1165 		for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++) {
   1166 			int posSlot;
   1167 			BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
   1168 
   1169 			int st = (lenToPosState << Base.kNumPosSlotBits);
   1170 			for (posSlot = 0; posSlot < _distTableSize; posSlot++)
   1171 				_posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
   1172 			for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
   1173 				_posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << com.badlogic.gdx.utils.compression.rangecoder.Encoder.kNumBitPriceShiftBits);
   1174 
   1175 			int st2 = lenToPosState * Base.kNumFullDistances;
   1176 			int i;
   1177 			for (i = 0; i < Base.kStartPosModelIndex; i++)
   1178 				_distancesPrices[st2 + i] = _posSlotPrices[st + i];
   1179 			for (; i < Base.kNumFullDistances; i++)
   1180 				_distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
   1181 		}
   1182 		_matchPriceCount = 0;
   1183 	}
   1184 
   1185 	void FillAlignPrices () {
   1186 		for (int i = 0; i < Base.kAlignTableSize; i++)
   1187 			_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
   1188 		_alignPriceCount = 0;
   1189 	}
   1190 
   1191 	public boolean SetAlgorithm (int algorithm) {
   1192 		/*
   1193 		 * _fastMode = (algorithm == 0); _maxMode = (algorithm >= 2);
   1194 		 */
   1195 		return true;
   1196 	}
   1197 
   1198 	public boolean SetDictionarySize (int dictionarySize) {
   1199 		int kDicLogSizeMaxCompress = 29;
   1200 		if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress)) return false;
   1201 		_dictionarySize = dictionarySize;
   1202 		int dicLogSize;
   1203 		for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++)
   1204 			;
   1205 		_distTableSize = dicLogSize * 2;
   1206 		return true;
   1207 	}
   1208 
   1209 	public boolean SetNumFastBytes (int numFastBytes) {
   1210 		if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen) return false;
   1211 		_numFastBytes = numFastBytes;
   1212 		return true;
   1213 	}
   1214 
   1215 	public boolean SetMatchFinder (int matchFinderIndex) {
   1216 		if (matchFinderIndex < 0 || matchFinderIndex > 2) return false;
   1217 		int matchFinderIndexPrev = _matchFinderType;
   1218 		_matchFinderType = matchFinderIndex;
   1219 		if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) {
   1220 			_dictionarySizePrev = -1;
   1221 			_matchFinder = null;
   1222 		}
   1223 		return true;
   1224 	}
   1225 
   1226 	public boolean SetLcLpPb (int lc, int lp, int pb) {
   1227 		if (lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax || lc < 0 || lc > Base.kNumLitContextBitsMax || pb < 0
   1228 			|| pb > Base.kNumPosStatesBitsEncodingMax) return false;
   1229 		_numLiteralPosStateBits = lp;
   1230 		_numLiteralContextBits = lc;
   1231 		_posStateBits = pb;
   1232 		_posStateMask = ((1) << _posStateBits) - 1;
   1233 		return true;
   1234 	}
   1235 
   1236 	public void SetEndMarkerMode (boolean endMarkerMode) {
   1237 		_writeEndMark = endMarkerMode;
   1238 	}
   1239 }
   1240