• 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.OutputStream;
14 import java.io.IOException;
15 
16 public final class RangeEncoder extends RangeCoder {
17     private static final int MOVE_REDUCING_BITS = 4;
18     private static final int BIT_PRICE_SHIFT_BITS = 4;
19 
20     private static final int[] prices
21             = new int[BIT_MODEL_TOTAL >>> MOVE_REDUCING_BITS];
22 
23     private long low;
24     private int range;
25 
26     // NOTE: int is OK for LZMA2 because a compressed chunk
27     // is not more than 64 KiB, but with LZMA1 there is no chunking
28     // so in theory cacheSize can grow very big. To be very safe,
29     // use long instead of int if you adapt this code for LZMA1.
30     private int cacheSize;
31     private byte cache;
32 
33     private final byte[] buf;
34     private int bufPos;
35 
36     static {
37         for (int i = (1 << MOVE_REDUCING_BITS) / 2; i < BIT_MODEL_TOTAL;
38                 i += (1 << MOVE_REDUCING_BITS)) {
39             int w = i;
40             int bitCount = 0;
41 
42             for (int j = 0; j < BIT_PRICE_SHIFT_BITS; ++j) {
43                 w *= w;
44                 bitCount <<= 1;
45 
46                 while ((w & 0xFFFF0000) != 0) {
47                     w >>>= 1;
48                     ++bitCount;
49                 }
50             }
51 
52             prices[i >> MOVE_REDUCING_BITS]
53                     = (BIT_MODEL_TOTAL_BITS << BIT_PRICE_SHIFT_BITS)
54                       - 15 - bitCount;
55         }
56     }
57 
RangeEncoder(int bufSize)58     public RangeEncoder(int bufSize) {
59         buf = new byte[bufSize];
60         reset();
61     }
62 
reset()63     public void reset() {
64         low = 0;
65         range = 0xFFFFFFFF;
66         cache = 0x00;
67         cacheSize = 1;
68         bufPos = 0;
69     }
70 
getPendingSize()71     public int getPendingSize() {
72         return bufPos + cacheSize + 5 - 1;
73     }
74 
finish()75     public int finish() {
76         for (int i = 0; i < 5; ++i)
77             shiftLow();
78 
79         return bufPos;
80     }
81 
write(OutputStream out)82     public void write(OutputStream out) throws IOException {
83         out.write(buf, 0, bufPos);
84     }
85 
shiftLow()86     private void shiftLow() {
87         int lowHi = (int)(low >>> 32);
88 
89         if (lowHi != 0 || low < 0xFF000000L) {
90             int temp = cache;
91 
92             do {
93                 buf[bufPos++] = (byte)(temp + lowHi);
94                 temp = 0xFF;
95             } while (--cacheSize != 0);
96 
97             cache = (byte)(low >>> 24);
98         }
99 
100         ++cacheSize;
101         low = (low & 0x00FFFFFF) << 8;
102     }
103 
encodeBit(short[] probs, int index, int bit)104     public void encodeBit(short[] probs, int index, int bit) {
105         int prob = probs[index];
106         int bound = (range >>> BIT_MODEL_TOTAL_BITS) * prob;
107 
108         // NOTE: Any non-zero value for bit is taken as 1.
109         if (bit == 0) {
110             range = bound;
111             probs[index] = (short)(
112                     prob + ((BIT_MODEL_TOTAL - prob) >>> MOVE_BITS));
113         } else {
114             low += bound & 0xFFFFFFFFL;
115             range -= bound;
116             probs[index] = (short)(prob - (prob >>> MOVE_BITS));
117         }
118 
119         if ((range & TOP_MASK) == 0) {
120             range <<= SHIFT_BITS;
121             shiftLow();
122         }
123     }
124 
getBitPrice(int prob, int bit)125     public static int getBitPrice(int prob, int bit) {
126         // NOTE: Unlike in encodeBit(), here bit must be 0 or 1.
127         assert bit == 0 || bit == 1;
128         return prices[(prob ^ ((-bit) & (BIT_MODEL_TOTAL - 1)))
129                       >>> MOVE_REDUCING_BITS];
130     }
131 
encodeBitTree(short[] probs, int symbol)132     public void encodeBitTree(short[] probs, int symbol) {
133         int index = 1;
134         int mask = probs.length;
135 
136         do {
137             mask >>>= 1;
138             int bit = symbol & mask;
139             encodeBit(probs, index, bit);
140 
141             index <<= 1;
142             if (bit != 0)
143                 index |= 1;
144 
145         } while (mask != 1);
146     }
147 
getBitTreePrice(short[] probs, int symbol)148     public static int getBitTreePrice(short[] probs, int symbol) {
149         int price = 0;
150         symbol |= probs.length;
151 
152         do {
153             int bit = symbol & 1;
154             symbol >>>= 1;
155             price += getBitPrice(probs[symbol], bit);
156         } while (symbol != 1);
157 
158         return price;
159     }
160 
encodeReverseBitTree(short[] probs, int symbol)161     public void encodeReverseBitTree(short[] probs, int symbol) {
162         int index = 1;
163         symbol |= probs.length;
164 
165         do {
166             int bit = symbol & 1;
167             symbol >>>= 1;
168             encodeBit(probs, index, bit);
169             index = (index << 1) | bit;
170         } while (symbol != 1);
171     }
172 
getReverseBitTreePrice(short[] probs, int symbol)173     public static int getReverseBitTreePrice(short[] probs, int symbol) {
174         int price = 0;
175         int index = 1;
176         symbol |= probs.length;
177 
178         do {
179             int bit = symbol & 1;
180             symbol >>>= 1;
181             price += getBitPrice(probs[index], bit);
182             index = (index << 1) | bit;
183         } while (symbol != 1);
184 
185         return price;
186     }
187 
encodeDirectBits(int value, int count)188     public void encodeDirectBits(int value, int count) {
189         do {
190             range >>>= 1;
191             low += range & (0 - ((value >>> --count) & 1));
192 
193             if ((range & TOP_MASK) == 0) {
194                 range <<= SHIFT_BITS;
195                 shiftLow();
196             }
197         } while (count != 0);
198     }
199 
getDirectBitsPrice(int count)200     public static int getDirectBitsPrice(int count) {
201         return count << BIT_PRICE_SHIFT_BITS;
202     }
203 }
204