17e2399c80b851754358adffc821699045534cd0egspencer@chromium.orgpackage SevenZip.Compression.RangeCoder;
27e2399c80b851754358adffc821699045534cd0egspencer@chromium.orgimport java.io.IOException;
37e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
47e2399c80b851754358adffc821699045534cd0egspencer@chromium.orgpublic class Encoder
57e2399c80b851754358adffc821699045534cd0egspencer@chromium.org{
67e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	static final int kTopMask = ~((1 << 24) - 1);
77e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
87e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	static final int kNumBitModelTotalBits = 11;
97e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	static final int kBitModelTotal = (1 << kNumBitModelTotalBits);
107e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	static final int kNumMoveBits = 5;
117e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
127e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	java.io.OutputStream Stream;
137e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
147e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	long Low;
157e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	int Range;
167e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	int _cacheSize;
177e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	int _cache;
187e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
197e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	long _position;
207e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
217e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	public void SetStream(java.io.OutputStream stream)
227e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	{
237e2399c80b851754358adffc821699045534cd0egspencer@chromium.org		Stream = stream;
247e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	}
257e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
267e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	public void ReleaseStream()
277e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	{
287e2399c80b851754358adffc821699045534cd0egspencer@chromium.org		Stream = null;
297e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	}
307e2399c80b851754358adffc821699045534cd0egspencer@chromium.org
317e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	public void Init()
327e2399c80b851754358adffc821699045534cd0egspencer@chromium.org	{
337e2399c80b851754358adffc821699045534cd0egspencer@chromium.org		_position = 0;
34		Low = 0;
35		Range = -1;
36		_cacheSize = 1;
37		_cache = 0;
38	}
39
40	public void FlushData() throws IOException
41	{
42		for (int i = 0; i < 5; i++)
43			ShiftLow();
44	}
45
46	public void FlushStream() throws IOException
47	{
48		Stream.flush();
49	}
50
51	public void ShiftLow() throws IOException
52	{
53		int LowHi = (int)(Low >>> 32);
54		if (LowHi != 0 || Low < 0xFF000000L)
55		{
56			_position += _cacheSize;
57			int temp = _cache;
58			do
59			{
60				Stream.write(temp + LowHi);
61				temp = 0xFF;
62			}
63			while(--_cacheSize != 0);
64			_cache = (((int)Low) >>> 24);
65		}
66		_cacheSize++;
67		Low = (Low & 0xFFFFFF) << 8;
68	}
69
70	public void EncodeDirectBits(int v, int numTotalBits) throws IOException
71	{
72		for (int i = numTotalBits - 1; i >= 0; i--)
73		{
74			Range >>>= 1;
75			if (((v >>> i) & 1) == 1)
76				Low += Range;
77			if ((Range & Encoder.kTopMask) == 0)
78			{
79				Range <<= 8;
80				ShiftLow();
81			}
82		}
83	}
84
85
86	public long GetProcessedSizeAdd()
87	{
88		return _cacheSize + _position + 4;
89	}
90
91
92
93	static final int kNumMoveReducingBits = 2;
94	public static final int kNumBitPriceShiftBits = 6;
95
96	public static void InitBitModels(short []probs)
97	{
98		for (int i = 0; i < probs.length; i++)
99			probs[i] = (kBitModelTotal >>> 1);
100	}
101
102	public void Encode(short []probs, int index, int symbol) throws IOException
103	{
104		int prob = probs[index];
105		int newBound = (Range >>> kNumBitModelTotalBits) * prob;
106		if (symbol == 0)
107		{
108			Range = newBound;
109			probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));
110		}
111		else
112		{
113			Low += (newBound & 0xFFFFFFFFL);
114			Range -= newBound;
115			probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));
116		}
117		if ((Range & kTopMask) == 0)
118		{
119			Range <<= 8;
120			ShiftLow();
121		}
122	}
123
124	private static int[] ProbPrices = new int[kBitModelTotal >>> kNumMoveReducingBits];
125
126	static
127	{
128		int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
129		for (int i = kNumBits - 1; i >= 0; i--)
130		{
131			int start = 1 << (kNumBits - i - 1);
132			int end = 1 << (kNumBits - i);
133			for (int j = start; j < end; j++)
134				ProbPrices[j] = (i << kNumBitPriceShiftBits) +
135						(((end - j) << kNumBitPriceShiftBits) >>> (kNumBits - i - 1));
136		}
137	}
138
139	static public int GetPrice(int Prob, int symbol)
140	{
141		return ProbPrices[(((Prob - symbol) ^ ((-symbol))) & (kBitModelTotal - 1)) >>> kNumMoveReducingBits];
142	}
143	static public int GetPrice0(int Prob)
144	{
145		return ProbPrices[Prob >>> kNumMoveReducingBits];
146	}
147	static public int GetPrice1(int Prob)
148	{
149		return ProbPrices[(kBitModelTotal - Prob) >>> kNumMoveReducingBits];
150	}
151}
152