context: using System;
  
  namespace SevenZip.Compression.RangeCoder
  {
  	class Encoder
  	{
  		public const uint kTopValue = (1 << 24);
  
  		System.IO.Stream Stream;
  
  		public ulong Low;
  		public uint Range;
  		uint _cacheSize;
  		byte _cache;
  
  		long StartPosition;
  
  		public void SetStream(System.IO.Stream stream)
  		{
  			Stream = stream;
  		}
  
  		public void ReleaseStream()
  		{
  			Stream = null;
  		}
  
  		public void Init()
  		{
  			StartPosition = Stream.Position;
  
  			Low = 0;
  			Range = 0xFFFFFFFF;
  			_cacheSize = 1;
  			_cache = 0;
  		}
  
  		public void FlushData()
  		{
  			for (int i = 0; i < 5; i++)
  				ShiftLow();
  		}
  
  		public void FlushStream()
  		{
  			Stream.Flush();
  		}
  
  		public void CloseStream()
  		{
  			Stream.Close();
  		}
  
  		public void Encode(uint start, uint size, uint total)
  		{
  			Low += start * (Range /= total);
  			Range *= size;
  			while (Range < kTopValue)
  			{
  				Range <<= 8;
  				ShiftLow();
  			}
  		}
  
  		public void ShiftLow()
  		{
  			if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
  			{
  				byte temp = _cache;
  				do
  				{
  					Stream.WriteByte((byte)(temp + (Low >> 32)));
  					temp = 0xFF;
  				}
  				while (--_cacheSize != 0);
  				_cache = (byte)(((uint)Low) >> 24);
  			}
  			_cacheSize++;
  			Low = ((uint)Low) << 8;
  		}
  
  		public void EncodeDirectBits(uint v, int numTotalBits)
  		{
  			for (int i = numTotalBits - 1; i >= 0; i--)
  			{
  				Range >>= 1;
  				if (((v >> i) & 1) == 1)
  					Low += Range;
  				if (Range < kTopValue)
  				{
  					Range <<= 8;
  					ShiftLow();
  				}
  			}
  		}
  
  		public void EncodeBit(uint size0, int numTotalBits, uint symbol)
  		{
  			uint newBound = (Range >> numTotalBits) * size0;
  			if (symbol == 0)
  				Range = newBound;
  			else
  			{
  				Low += newBound;
  				Range -= newBound;
  			}
  			while (Range < kTopValue)
  			{
  				Range <<= 8;
  				ShiftLow();
  			}
  		}
  
  		public long GetProcessedSizeAdd()
  		{
  			return _cacheSize +
  				Stream.Position - StartPosition + 4;
  			//-- (long)Stream.GetProcessedSize();
  		}
  	}
  
  	class Decoder
  	{
  		public const uint kTopValue = (1 << 24);
  		public uint Range;
  		public uint Code;
  		//-- public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
  		public System.IO.Stream Stream;
  
  		public void Init(System.IO.Stream stream)
  		{
  			//-- Stream.Init(stream);
  			Stream = stream;
  
  			Code = 0;
  			Range = 0xFFFFFFFF;
  			for (int i = 0; i < 5; i++)
  				Code = (Code << 8) | (byte)Stream.ReadByte();
  		}
  
  		public void ReleaseStream()
  		{
  			//-- Stream.ReleaseStream();
  			Stream = null;
  		}
  
  		public void CloseStream()
  		{
  			Stream.Close();
  		}
  
  		public void Normalize()
  		{
  			while (Range < kTopValue)
  			{
  				Code = (Code << 8) | (byte)Stream.ReadByte();
  				Range <<= 8;
  			}
  		}
  
  		public void Normalize2()
  		{
  			if (Range < kTopValue)
  			{
  				Code = (Code << 8) | (byte)Stream.ReadByte();
  				Range <<= 8;
  			}
  		}
  
  		public uint GetThreshold(uint total)
  		{
  			return Code / (Range /= total);
  		}
  
  		public void Decode(uint start, uint size, uint total)
  		{
  			Code -= start * Range;
  			Range *= size;
  			Normalize();
  		}
  
  		public uint DecodeDirectBits(int numTotalBits)
  		{
  			uint range = Range;
  			uint code = Code;
  			uint result = 0;
  			for (int i = numTotalBits; i > 0; i--)
  			{
  				range >>= 1;
  				/*
  				result <<= 1;
  				if (code >= range)
  				{
  					code -= range;
  					result |= 1;
  				}
  				*/
  				uint t = (code - range) >> 31;
  				code -= range & (t - 1);
  				result = (result << 1) | (1 - t);
  
  				if (range < kTopValue)
  				{
  
gt: 					code = (code << 8) | (byte)Stream.ReadByte();