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