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