source: josm/trunk/src/org/tukaani/xz/rangecoder/RangeEncoder.java@ 13632

Last change on this file since 13632 was 13350, checked in by stoecker, 7 years ago

see #15816 - add XZ support

File size: 5.5 KB
Line 
1/*
2 * RangeEncoder
3 *
4 * Authors: Lasse Collin <lasse.collin@tukaani.org>
5 * Igor Pavlov <http://7-zip.org/>
6 *
7 * This file has been put into the public domain.
8 * You can do whatever you want with this file.
9 */
10
11package org.tukaani.xz.rangecoder;
12
13import java.io.IOException;
14
15public abstract class RangeEncoder extends RangeCoder {
16 private static final int MOVE_REDUCING_BITS = 4;
17 private static final int BIT_PRICE_SHIFT_BITS = 4;
18
19 private static final int[] prices
20 = new int[BIT_MODEL_TOTAL >>> MOVE_REDUCING_BITS];
21
22 private long low;
23 private int range;
24
25 // NOTE: int is OK for LZMA2 because a compressed chunk
26 // is not more than 64 KiB, but with LZMA1 there is no chunking
27 // so in theory cacheSize can grow very big. To be very safe,
28 // use long instead of int since this code is used for LZMA1 too.
29 long cacheSize;
30 private byte cache;
31
32 static {
33 for (int i = (1 << MOVE_REDUCING_BITS) / 2; i < BIT_MODEL_TOTAL;
34 i += (1 << MOVE_REDUCING_BITS)) {
35 int w = i;
36 int bitCount = 0;
37
38 for (int j = 0; j < BIT_PRICE_SHIFT_BITS; ++j) {
39 w *= w;
40 bitCount <<= 1;
41
42 while ((w & 0xFFFF0000) != 0) {
43 w >>>= 1;
44 ++bitCount;
45 }
46 }
47
48 prices[i >> MOVE_REDUCING_BITS]
49 = (BIT_MODEL_TOTAL_BITS << BIT_PRICE_SHIFT_BITS)
50 - 15 - bitCount;
51 }
52 }
53
54 public void reset() {
55 low = 0;
56 range = 0xFFFFFFFF;
57 cache = 0x00;
58 cacheSize = 1;
59 }
60
61 public int getPendingSize() {
62 // This function is only needed by users of RangeEncoderToBuffer,
63 // but providing a must-be-never-called version here makes
64 // LZMAEncoder simpler.
65 throw new Error();
66 }
67
68 public int finish() throws IOException {
69 for (int i = 0; i < 5; ++i)
70 shiftLow();
71
72 // RangeEncoderToBuffer.finish() needs a return value to tell
73 // how big the finished buffer is. RangeEncoderToStream has no
74 // buffer and thus no return value is needed. Here we use a dummy
75 // value which can be overriden in RangeEncoderToBuffer.finish().
76 return -1;
77 }
78
79 abstract void writeByte(int b) throws IOException;
80
81 private void shiftLow() throws IOException {
82 int lowHi = (int)(low >>> 32);
83
84 if (lowHi != 0 || low < 0xFF000000L) {
85 int temp = cache;
86
87 do {
88 writeByte(temp + lowHi);
89 temp = 0xFF;
90 } while (--cacheSize != 0);
91
92 cache = (byte)(low >>> 24);
93 }
94
95 ++cacheSize;
96 low = (low & 0x00FFFFFF) << 8;
97 }
98
99 public void encodeBit(short[] probs, int index, int bit)
100 throws IOException {
101 int prob = probs[index];
102 int bound = (range >>> BIT_MODEL_TOTAL_BITS) * prob;
103
104 // NOTE: Any non-zero value for bit is taken as 1.
105 if (bit == 0) {
106 range = bound;
107 probs[index] = (short)(
108 prob + ((BIT_MODEL_TOTAL - prob) >>> MOVE_BITS));
109 } else {
110 low += bound & 0xFFFFFFFFL;
111 range -= bound;
112 probs[index] = (short)(prob - (prob >>> MOVE_BITS));
113 }
114
115 if ((range & TOP_MASK) == 0) {
116 range <<= SHIFT_BITS;
117 shiftLow();
118 }
119 }
120
121 public static int getBitPrice(int prob, int bit) {
122 // NOTE: Unlike in encodeBit(), here bit must be 0 or 1.
123 assert bit == 0 || bit == 1;
124 return prices[(prob ^ ((-bit) & (BIT_MODEL_TOTAL - 1)))
125 >>> MOVE_REDUCING_BITS];
126 }
127
128 public void encodeBitTree(short[] probs, int symbol) throws IOException {
129 int index = 1;
130 int mask = probs.length;
131
132 do {
133 mask >>>= 1;
134 int bit = symbol & mask;
135 encodeBit(probs, index, bit);
136
137 index <<= 1;
138 if (bit != 0)
139 index |= 1;
140
141 } while (mask != 1);
142 }
143
144 public static int getBitTreePrice(short[] probs, int symbol) {
145 int price = 0;
146 symbol |= probs.length;
147
148 do {
149 int bit = symbol & 1;
150 symbol >>>= 1;
151 price += getBitPrice(probs[symbol], bit);
152 } while (symbol != 1);
153
154 return price;
155 }
156
157 public void encodeReverseBitTree(short[] probs, int symbol)
158 throws IOException {
159 int index = 1;
160 symbol |= probs.length;
161
162 do {
163 int bit = symbol & 1;
164 symbol >>>= 1;
165 encodeBit(probs, index, bit);
166 index = (index << 1) | bit;
167 } while (symbol != 1);
168 }
169
170 public static int getReverseBitTreePrice(short[] probs, int symbol) {
171 int price = 0;
172 int index = 1;
173 symbol |= probs.length;
174
175 do {
176 int bit = symbol & 1;
177 symbol >>>= 1;
178 price += getBitPrice(probs[index], bit);
179 index = (index << 1) | bit;
180 } while (symbol != 1);
181
182 return price;
183 }
184
185 public void encodeDirectBits(int value, int count) throws IOException {
186 do {
187 range >>>= 1;
188 low += range & (0 - ((value >>> --count) & 1));
189
190 if ((range & TOP_MASK) == 0) {
191 range <<= SHIFT_BITS;
192 shiftLow();
193 }
194 } while (count != 0);
195 }
196
197 public static int getDirectBitsPrice(int count) {
198 return count << BIT_PRICE_SHIFT_BITS;
199 }
200}
Note: See TracBrowser for help on using the repository browser.