• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 package org.tukaani.xz.rangecoder;
12 
13 import java.io.IOException;
14 
15 public 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 
reset()54     public void reset() {
55         low = 0;
56         range = 0xFFFFFFFF;
57         cache = 0x00;
58         cacheSize = 1;
59     }
60 
getPendingSize()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 
finish()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 
writeByte(int b)79     abstract void writeByte(int b) throws IOException;
80 
shiftLow()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 
encodeBit(short[] probs, int index, int bit)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 
getBitPrice(int prob, int bit)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 
encodeBitTree(short[] probs, int symbol)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 
getBitTreePrice(short[] probs, int symbol)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 
encodeReverseBitTree(short[] probs, int symbol)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 
getReverseBitTreePrice(short[] probs, int symbol)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 
encodeDirectBits(int value, int count)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 
getDirectBitsPrice(int count)197     public static int getDirectBitsPrice(int count) {
198         return count << BIT_PRICE_SHIFT_BITS;
199     }
200 }
201