1using System;
2
3namespace SevenZip.Compression.RangeCoder
4{
5	class Encoder
6	{
7		public const uint kTopValue = (1 << 24);
8
9		System.IO.Stream Stream;
10
11		public UInt64 Low;
12		public uint Range;
13		uint _cacheSize;
14		byte _cache;
15
16		long StartPosition;
17
18		public void SetStream(System.IO.Stream stream)
19		{
20			Stream = stream;
21		}
22
23		public void ReleaseStream()
24		{
25			Stream = null;
26		}
27
28		public void Init()
29		{
30			StartPosition = Stream.Position;
31
32			Low = 0;
33			Range = 0xFFFFFFFF;
34			_cacheSize = 1;
35			_cache = 0;
36		}
37
38		public void FlushData()
39		{
40			for (int i = 0; i < 5; i++)
41				ShiftLow();
42		}
43
44		public void FlushStream()
45		{
46			Stream.Flush();
47		}
48
49		public void CloseStream()
50		{
51			Stream.Close();
52		}
53
54		public void Encode(uint start, uint size, uint total)
55		{
56			Low += start * (Range /= total);
57			Range *= size;
58			while (Range < kTopValue)
59			{
60				Range <<= 8;
61				ShiftLow();
62			}
63		}
64
65		public void ShiftLow()
66		{
67			if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
68			{
69				byte temp = _cache;
70				do
71				{
72					Stream.WriteByte((byte)(temp + (Low >> 32)));
73					temp = 0xFF;
74				}
75				while (--_cacheSize != 0);
76				_cache = (byte)(((uint)Low) >> 24);
77			}
78			_cacheSize++;
79			Low = ((uint)Low) << 8;
80		}
81
82		public void EncodeDirectBits(uint v, int numTotalBits)
83		{
84			for (int i = numTotalBits - 1; i >= 0; i--)
85			{
86				Range >>= 1;
87				if (((v >> i) & 1) == 1)
88					Low += Range;
89				if (Range < kTopValue)
90				{
91					Range <<= 8;
92					ShiftLow();
93				}
94			}
95		}
96
97		public void EncodeBit(uint size0, int numTotalBits, uint symbol)
98		{
99			uint newBound = (Range >> numTotalBits) * size0;
100			if (symbol == 0)
101				Range = newBound;
102			else
103			{
104				Low += newBound;
105				Range -= newBound;
106			}
107			while (Range < kTopValue)
108			{
109				Range <<= 8;
110				ShiftLow();
111			}
112		}
113
114		public long GetProcessedSizeAdd()
115		{
116			return _cacheSize +
117				Stream.Position - StartPosition + 4;
118			// (long)Stream.GetProcessedSize();
119		}
120	}
121
122	class Decoder
123	{
124		public const uint kTopValue = (1 << 24);
125		public uint Range;
126		public uint Code;
127		// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
128		public System.IO.Stream Stream;
129
130		public void Init(System.IO.Stream stream)
131		{
132			// Stream.Init(stream);
133			Stream = stream;
134
135			Code = 0;
136			Range = 0xFFFFFFFF;
137			for (int i = 0; i < 5; i++)
138				Code = (Code << 8) | (byte)Stream.ReadByte();
139		}
140
141		public void ReleaseStream()
142		{
143			// Stream.ReleaseStream();
144			Stream = null;
145		}
146
147		public void CloseStream()
148		{
149			Stream.Close();
150		}
151
152		public void Normalize()
153		{
154			while (Range < kTopValue)
155			{
156				Code = (Code << 8) | (byte)Stream.ReadByte();
157				Range <<= 8;
158			}
159		}
160
161		public void Normalize2()
162		{
163			if (Range < kTopValue)
164			{
165				Code = (Code << 8) | (byte)Stream.ReadByte();
166				Range <<= 8;
167			}
168		}
169
170		public uint GetThreshold(uint total)
171		{
172			return Code / (Range /= total);
173		}
174
175		public void Decode(uint start, uint size, uint total)
176		{
177			Code -= start * Range;
178			Range *= size;
179			Normalize();
180		}
181
182		public uint DecodeDirectBits(int numTotalBits)
183		{
184			uint range = Range;
185			uint code = Code;
186			uint result = 0;
187			for (int i = numTotalBits; i > 0; i--)
188			{
189				range >>= 1;
190				/*
191				result <<= 1;
192				if (code >= range)
193				{
194					code -= range;
195					result |= 1;
196				}
197				*/
198				uint t = (code - range) >> 31;
199				code -= range & (t - 1);
200				result = (result << 1) | (1 - t);
201
202				if (range < kTopValue)
203				{
204					code = (code << 8) | (byte)Stream.ReadByte();
205					range <<= 8;
206				}
207			}
208			Range = range;
209			Code = code;
210			return result;
211		}
212
213		public uint DecodeBit(uint size0, int numTotalBits)
214		{
215			uint newBound = (Range >> numTotalBits) * size0;
216			uint symbol;
217			if (Code < newBound)
218			{
219				symbol = 0;
220				Range = newBound;
221			}
222			else
223			{
224				symbol = 1;
225				Code -= newBound;
226				Range -= newBound;
227			}
228			Normalize();
229			return symbol;
230		}
231
232		// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
233	}
234}
235