1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.harmony.pack200;
20
21 import java.io.EOFException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.Map;
27
28
29
30
31 public class CodecEncoding {
32
33 private static final int[] EMPTY_INT_ARRAY = {};
34
35
36
37
38
39 private static final BHSDCodec[] canonicalCodec = { null, new BHSDCodec(1, 256), new BHSDCodec(1, 256, 1), new BHSDCodec(1, 256, 0, 1),
40 new BHSDCodec(1, 256, 1, 1), new BHSDCodec(2, 256), new BHSDCodec(2, 256, 1), new BHSDCodec(2, 256, 0, 1), new BHSDCodec(2, 256, 1, 1),
41 new BHSDCodec(3, 256), new BHSDCodec(3, 256, 1), new BHSDCodec(3, 256, 0, 1), new BHSDCodec(3, 256, 1, 1), new BHSDCodec(4, 256),
42 new BHSDCodec(4, 256, 1), new BHSDCodec(4, 256, 0, 1), new BHSDCodec(4, 256, 1, 1), new BHSDCodec(5, 4), new BHSDCodec(5, 4, 1),
43 new BHSDCodec(5, 4, 2), new BHSDCodec(5, 16), new BHSDCodec(5, 16, 1), new BHSDCodec(5, 16, 2), new BHSDCodec(5, 32), new BHSDCodec(5, 32, 1),
44 new BHSDCodec(5, 32, 2), new BHSDCodec(5, 64), new BHSDCodec(5, 64, 1), new BHSDCodec(5, 64, 2), new BHSDCodec(5, 128), new BHSDCodec(5, 128, 1),
45 new BHSDCodec(5, 128, 2), new BHSDCodec(5, 4, 0, 1), new BHSDCodec(5, 4, 1, 1), new BHSDCodec(5, 4, 2, 1), new BHSDCodec(5, 16, 0, 1),
46 new BHSDCodec(5, 16, 1, 1), new BHSDCodec(5, 16, 2, 1), new BHSDCodec(5, 32, 0, 1), new BHSDCodec(5, 32, 1, 1), new BHSDCodec(5, 32, 2, 1),
47 new BHSDCodec(5, 64, 0, 1), new BHSDCodec(5, 64, 1, 1), new BHSDCodec(5, 64, 2, 1), new BHSDCodec(5, 128, 0, 1), new BHSDCodec(5, 128, 1, 1),
48 new BHSDCodec(5, 128, 2, 1), new BHSDCodec(2, 192), new BHSDCodec(2, 224), new BHSDCodec(2, 240), new BHSDCodec(2, 248), new BHSDCodec(2, 252),
49 new BHSDCodec(2, 8, 0, 1), new BHSDCodec(2, 8, 1, 1), new BHSDCodec(2, 16, 0, 1), new BHSDCodec(2, 16, 1, 1), new BHSDCodec(2, 32, 0, 1),
50 new BHSDCodec(2, 32, 1, 1), new BHSDCodec(2, 64, 0, 1), new BHSDCodec(2, 64, 1, 1), new BHSDCodec(2, 128, 0, 1), new BHSDCodec(2, 128, 1, 1),
51 new BHSDCodec(2, 192, 0, 1), new BHSDCodec(2, 192, 1, 1), new BHSDCodec(2, 224, 0, 1), new BHSDCodec(2, 224, 1, 1), new BHSDCodec(2, 240, 0, 1),
52 new BHSDCodec(2, 240, 1, 1), new BHSDCodec(2, 248, 0, 1), new BHSDCodec(2, 248, 1, 1), new BHSDCodec(3, 192), new BHSDCodec(3, 224),
53 new BHSDCodec(3, 240), new BHSDCodec(3, 248), new BHSDCodec(3, 252), new BHSDCodec(3, 8, 0, 1), new BHSDCodec(3, 8, 1, 1),
54 new BHSDCodec(3, 16, 0, 1), new BHSDCodec(3, 16, 1, 1), new BHSDCodec(3, 32, 0, 1), new BHSDCodec(3, 32, 1, 1), new BHSDCodec(3, 64, 0, 1),
55 new BHSDCodec(3, 64, 1, 1), new BHSDCodec(3, 128, 0, 1), new BHSDCodec(3, 128, 1, 1), new BHSDCodec(3, 192, 0, 1), new BHSDCodec(3, 192, 1, 1),
56 new BHSDCodec(3, 224, 0, 1), new BHSDCodec(3, 224, 1, 1), new BHSDCodec(3, 240, 0, 1), new BHSDCodec(3, 240, 1, 1), new BHSDCodec(3, 248, 0, 1),
57 new BHSDCodec(3, 248, 1, 1), new BHSDCodec(4, 192), new BHSDCodec(4, 224), new BHSDCodec(4, 240), new BHSDCodec(4, 248), new BHSDCodec(4, 252),
58 new BHSDCodec(4, 8, 0, 1), new BHSDCodec(4, 8, 1, 1), new BHSDCodec(4, 16, 0, 1), new BHSDCodec(4, 16, 1, 1), new BHSDCodec(4, 32, 0, 1),
59 new BHSDCodec(4, 32, 1, 1), new BHSDCodec(4, 64, 0, 1), new BHSDCodec(4, 64, 1, 1), new BHSDCodec(4, 128, 0, 1), new BHSDCodec(4, 128, 1, 1),
60 new BHSDCodec(4, 192, 0, 1), new BHSDCodec(4, 192, 1, 1), new BHSDCodec(4, 224, 0, 1), new BHSDCodec(4, 224, 1, 1), new BHSDCodec(4, 240, 0, 1),
61 new BHSDCodec(4, 240, 1, 1), new BHSDCodec(4, 248, 0, 1), new BHSDCodec(4, 248, 1, 1) };
62
63 private static Map<BHSDCodec, Integer> canonicalCodecsToSpecifiers;
64
65 static {
66 final HashMap<BHSDCodec, Integer> reverseMap = new HashMap<>(canonicalCodec.length);
67 for (int i = 0; i < canonicalCodec.length; i++) {
68 reverseMap.put(canonicalCodec[i], Integer.valueOf(i));
69 }
70 canonicalCodecsToSpecifiers = reverseMap;
71 }
72
73 public static BHSDCodec getCanonicalCodec(final int i) {
74 return canonicalCodec[i];
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public static Codec getCodec(final int value, final InputStream in, final Codec defaultCodec) throws IOException, Pack200Exception {
91
92
93 if (canonicalCodec.length != 116) {
94 throw new Error("Canonical encodings have been incorrectly modified");
95 }
96 if (value < 0) {
97 throw new IllegalArgumentException("Encoding cannot be less than zero");
98 }
99 if (value == 0) {
100 return defaultCodec;
101 }
102 if (value <= 115) {
103 return canonicalCodec[value];
104 }
105 if (value == 116) {
106 int code = in.read();
107 if (code == -1) {
108 throw new EOFException("End of buffer read whilst trying to decode codec");
109 }
110 final int d = code & 0x01;
111 final int s = code >> 1 & 0x03;
112 final int b = (code >> 3 & 0x07) + 1;
113
114
115 code = in.read();
116 if (code == -1) {
117 throw new EOFException("End of buffer read whilst trying to decode codec");
118 }
119 final int h = code + 1;
120
121 return new BHSDCodec(b, h, s, d);
122 }
123 if (value >= 117 && value <= 140) {
124 final int offset = value - 117;
125 final int kx = offset & 3;
126 final boolean kbflag = (offset >> 2 & 1) == 1;
127 final boolean adef = (offset >> 3 & 1) == 1;
128 final boolean bdef = (offset >> 4 & 1) == 1;
129
130
131 if (adef && bdef) {
132 throw new Pack200Exception("ADef and BDef should never both be true");
133 }
134 final int kb = kbflag ? in.read() : 3;
135 final int k = (kb + 1) * (int) Math.pow(16, kx);
136 final Codec aCodec;
137 final Codec bCodec;
138 if (adef) {
139 aCodec = defaultCodec;
140 } else {
141 aCodec = getCodec(in.read(), in, defaultCodec);
142 }
143 if (bdef) {
144 bCodec = defaultCodec;
145 } else {
146 bCodec = getCodec(in.read(), in, defaultCodec);
147 }
148 return new RunCodec(k, aCodec, bCodec);
149 }
150 if (value < 141 || value > 188) {
151 throw new Pack200Exception("Invalid codec encoding byte (" + value + ") found");
152 }
153 final int offset = value - 141;
154 final boolean fdef = (offset & 1) == 1;
155 final boolean udef = (offset >> 1 & 1) == 1;
156 final int tdefl = offset >> 2;
157 final boolean tdef = tdefl != 0;
158
159 final int[] tdefToL = { 0, 4, 8, 16, 32, 64, 128, 192, 224, 240, 248, 252 };
160 final int l = tdefToL[tdefl];
161
162
163
164 if (tdef) {
165 final Codec fCodec = fdef ? defaultCodec : getCodec(in.read(), in, defaultCodec);
166 final Codec uCodec = udef ? defaultCodec : getCodec(in.read(), in, defaultCodec);
167
168
169
170
171
172 return new PopulationCodec(fCodec, l, uCodec);
173 }
174 final Codec fCodec = fdef ? defaultCodec : getCodec(in.read(), in, defaultCodec);
175 final Codec tCodec = getCodec(in.read(), in, defaultCodec);
176 final Codec uCodec = udef ? defaultCodec : getCodec(in.read(), in, defaultCodec);
177 return new PopulationCodec(fCodec, tCodec, uCodec);
178 }
179
180 public static int[] getSpecifier(final Codec codec, final Codec defaultForBand) {
181 if (canonicalCodecsToSpecifiers.containsKey(codec)) {
182 return new int[] { canonicalCodecsToSpecifiers.get(codec).intValue() };
183 }
184 if (codec instanceof BHSDCodec) {
185
186 final BHSDCodec bhsdCodec = (BHSDCodec) codec;
187 final int[] specifiers = new int[3];
188 specifiers[0] = 116;
189 specifiers[1] = (bhsdCodec.isDelta() ? 1 : 0) + 2 * bhsdCodec.getS() + 8 * (bhsdCodec.getB() - 1);
190 specifiers[2] = bhsdCodec.getH() - 1;
191 return specifiers;
192 }
193 if (codec instanceof RunCodec) {
194 final RunCodec runCodec = (RunCodec) codec;
195 final int k = runCodec.getK();
196 final int kb;
197 final int kx;
198 if (k <= 256) {
199 kb = 0;
200 kx = k - 1;
201 } else if (k <= 4096) {
202 kb = 1;
203 kx = k / 16 - 1;
204 } else if (k <= 65536) {
205 kb = 2;
206 kx = k / 256 - 1;
207 } else {
208 kb = 3;
209 kx = k / 4096 - 1;
210 }
211 final Codec aCodec = runCodec.getACodec();
212 final Codec bCodec = runCodec.getBCodec();
213 int abDef = 0;
214 if (aCodec.equals(defaultForBand)) {
215 abDef = 1;
216 } else if (bCodec.equals(defaultForBand)) {
217 abDef = 2;
218 }
219 final int first = 117 + kb + (kx == 3 ? 0 : 4) + 8 * abDef;
220 final int[] aSpecifier = abDef == 1 ? EMPTY_INT_ARRAY : getSpecifier(aCodec, defaultForBand);
221 final int[] bSpecifier = abDef == 2 ? EMPTY_INT_ARRAY : getSpecifier(bCodec, defaultForBand);
222 final int[] specifier = new int[1 + (kx == 3 ? 0 : 1) + aSpecifier.length + bSpecifier.length];
223 specifier[0] = first;
224 int index = 1;
225 if (kx != 3) {
226 specifier[1] = kx;
227 index++;
228 }
229 for (final int element : aSpecifier) {
230 specifier[index] = element;
231 index++;
232 }
233 for (final int element : bSpecifier) {
234 specifier[index] = element;
235 index++;
236 }
237 return specifier;
238 }
239 if (codec instanceof PopulationCodec) {
240 final PopulationCodec populationCodec = (PopulationCodec) codec;
241 final Codec tokenCodec = populationCodec.getTokenCodec();
242 final Codec favouredCodec = populationCodec.getFavouredCodec();
243 final Codec unfavouredCodec = populationCodec.getUnfavouredCodec();
244 final int fDef = favouredCodec.equals(defaultForBand) ? 1 : 0;
245 final int uDef = unfavouredCodec.equals(defaultForBand) ? 1 : 0;
246 int tDefL = 0;
247 final int[] favoured = populationCodec.getFavoured();
248 if (favoured != null) {
249 if (tokenCodec == Codec.BYTE1) {
250 tDefL = 1;
251 } else if (tokenCodec instanceof BHSDCodec) {
252 final BHSDCodec tokenBHSD = (BHSDCodec) tokenCodec;
253 if (tokenBHSD.getS() == 0) {
254 final int[] possibleLValues = { 4, 8, 16, 32, 64, 128, 192, 224, 240, 248, 252 };
255 final int l = 256 - tokenBHSD.getH();
256 int index = Arrays.binarySearch(possibleLValues, l);
257 if (index != -1) {
258
259 tDefL = index++;
260 }
261 }
262 }
263 }
264 final int first = 141 + fDef + 2 * uDef + 4 * tDefL;
265 final int[] favouredSpecifier = fDef == 1 ? EMPTY_INT_ARRAY : getSpecifier(favouredCodec, defaultForBand);
266 final int[] tokenSpecifier = tDefL != 0 ? EMPTY_INT_ARRAY : getSpecifier(tokenCodec, defaultForBand);
267 final int[] unfavouredSpecifier = uDef == 1 ? EMPTY_INT_ARRAY : getSpecifier(unfavouredCodec, defaultForBand);
268 final int[] specifier = new int[1 + favouredSpecifier.length + unfavouredSpecifier.length + tokenSpecifier.length];
269 specifier[0] = first;
270 int index = 1;
271 for (final int element : favouredSpecifier) {
272 specifier[index] = element;
273 index++;
274 }
275 for (final int element : tokenSpecifier) {
276 specifier[index] = element;
277 index++;
278 }
279 for (final int element : unfavouredSpecifier) {
280 specifier[index] = element;
281 index++;
282 }
283 return specifier;
284 }
285
286 return null;
287 }
288
289 public static int getSpecifierForDefaultCodec(final BHSDCodec defaultCodec) {
290 return getSpecifier(defaultCodec, null)[0];
291 }
292 }