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.unpack200;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import org.apache.commons.compress.harmony.pack200.Codec;
28 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
29 import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
30 import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
31 import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
32 import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
33 import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
34 import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
35 import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
36 import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
37 import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
38 import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
39 import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
40
41
42
43
44 public class CpBands extends BandSet {
45
46 private static final String EMPTY_STRING = "";
47
48 private final SegmentConstantPool pool = new SegmentConstantPool(this);
49
50 private String[] cpClass;
51
52 private int[] cpClassInts;
53 private int[] cpDescriptorNameInts;
54 private int[] cpDescriptorTypeInts;
55 private String[] cpDescriptor;
56 private double[] cpDouble;
57 private String[] cpFieldClass;
58 private String[] cpFieldDescriptor;
59 private int[] cpFieldClassInts;
60 private int[] cpFieldDescriptorInts;
61 private float[] cpFloat;
62 private String[] cpIMethodClass;
63 private String[] cpIMethodDescriptor;
64 private int[] cpIMethodClassInts;
65 private int[] cpIMethodDescriptorInts;
66 private int[] cpInt;
67 private long[] cpLong;
68 private String[] cpMethodClass;
69 private String[] cpMethodDescriptor;
70 private int[] cpMethodClassInts;
71 private int[] cpMethodDescriptorInts;
72 private String[] cpSignature;
73 private int[] cpSignatureInts;
74 private String[] cpString;
75 private int[] cpStringInts;
76 private String[] cpUTF8;
77 private final Map<String, CPUTF8> stringsToCPUTF8 = new HashMap<>();
78
79 private final Map<String, CPString> stringsToCPStrings = new HashMap<>();
80 private final Map<Long, CPLong> longsToCPLongs = new HashMap<>();
81 private final Map<Integer, CPInteger> integersToCPIntegers = new HashMap<>();
82 private final Map<Float, CPFloat> floatsToCPFloats = new HashMap<>();
83 private final Map<String, CPClass> stringsToCPClass = new HashMap<>();
84 private final Map<Double, CPDouble> doublesToCPDoubles = new HashMap<>();
85 private final Map<String, CPNameAndType> descriptorsToCPNameAndTypes = new HashMap<>();
86 private Map<String, Integer> mapClass;
87
88 private Map<String, Integer> mapDescriptor;
89 private Map<String, Integer> mapUTF8;
90
91 private Map<String, Integer> mapSignature;
92
93 private int intOffset;
94
95 private int floatOffset;
96 private int longOffset;
97 private int doubleOffset;
98 private int stringOffset;
99 private int classOffset;
100 private int signatureOffset;
101 private int descrOffset;
102 private int fieldOffset;
103 private int methodOffset;
104 private int imethodOffset;
105
106 public CpBands(final Segment segment) {
107 super(segment);
108 }
109
110 public CPClass cpClassValue(final int index) {
111 final String string = cpClass[index];
112 final int utf8Index = cpClassInts[index];
113 final int globalIndex = classOffset + index;
114 return stringsToCPClass.computeIfAbsent(string, k -> new CPClass(cpUTF8Value(utf8Index), globalIndex));
115 }
116
117 public CPClass cpClassValue(final String string) {
118 CPClass cpString = stringsToCPClass.get(string);
119 if (cpString == null) {
120 final Integer index = mapClass.get(string);
121 if (index != null) {
122 return cpClassValue(index.intValue());
123 }
124 cpString = new CPClass(cpUTF8Value(string, false), -1);
125 stringsToCPClass.put(string, cpString);
126 }
127 return cpString;
128 }
129
130 public CPDouble cpDoubleValue(final int index) {
131 return doublesToCPDoubles.computeIfAbsent(Double.valueOf(cpDouble[index]), k -> new CPDouble(k, index + doubleOffset));
132 }
133
134 public CPFieldRef cpFieldValue(final int index) {
135 return new CPFieldRef(cpClassValue(cpFieldClassInts[index]), cpNameAndTypeValue(cpFieldDescriptorInts[index]), index + fieldOffset);
136 }
137
138 public CPFloat cpFloatValue(final int index) {
139 return floatsToCPFloats.computeIfAbsent(Float.valueOf(cpFloat[index]), k -> new CPFloat(Float.valueOf(cpFloat[index]), index + floatOffset));
140 }
141
142 public CPInterfaceMethodRef cpIMethodValue(final int index) {
143 return new CPInterfaceMethodRef(cpClassValue(cpIMethodClassInts[index]), cpNameAndTypeValue(cpIMethodDescriptorInts[index]), index + imethodOffset);
144 }
145
146 public CPInteger cpIntegerValue(final int index) {
147 return integersToCPIntegers.computeIfAbsent(Integer.valueOf(cpInt[index]), k -> new CPInteger(k, index + intOffset));
148 }
149
150 public CPLong cpLongValue(final int index) {
151 return longsToCPLongs.computeIfAbsent(Long.valueOf(cpLong[index]), k -> new CPLong(k, index + longOffset));
152 }
153
154 public CPMethodRef cpMethodValue(final int index) {
155 return new CPMethodRef(cpClassValue(cpMethodClassInts[index]), cpNameAndTypeValue(cpMethodDescriptorInts[index]), index + methodOffset);
156 }
157
158 public CPNameAndType cpNameAndTypeValue(final int index) {
159 final String descriptor = cpDescriptor[index];
160 return descriptorsToCPNameAndTypes.computeIfAbsent(descriptor, k -> {
161 final int nameIndex = cpDescriptorNameInts[index];
162 final int descriptorIndex = cpDescriptorTypeInts[index];
163 final CPUTF8 name = cpUTF8Value(nameIndex);
164 final CPUTF8 descriptorU = cpSignatureValue(descriptorIndex);
165 return new CPNameAndType(name, descriptorU, index + descrOffset);
166 });
167 }
168
169 public CPNameAndType cpNameAndTypeValue(final String descriptor) {
170 CPNameAndType cpNameAndType = descriptorsToCPNameAndTypes.get(descriptor);
171 if (cpNameAndType == null) {
172 final Integer index = mapDescriptor.get(descriptor);
173 if (index != null) {
174 return cpNameAndTypeValue(index.intValue());
175 }
176 final int colon = descriptor.indexOf(':');
177 final String nameString = descriptor.substring(0, colon);
178 final String descriptorString = descriptor.substring(colon + 1);
179
180 final CPUTF8 name = cpUTF8Value(nameString, true);
181 final CPUTF8 descriptorU = cpUTF8Value(descriptorString, true);
182 cpNameAndType = new CPNameAndType(name, descriptorU, -1 + descrOffset);
183 descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType);
184 }
185 return cpNameAndType;
186 }
187
188 public CPUTF8 cpSignatureValue(final int index) {
189 final int globalIndex;
190 if (cpSignatureInts[index] != -1) {
191 globalIndex = cpSignatureInts[index];
192 } else {
193 globalIndex = index + signatureOffset;
194 }
195 return stringsToCPUTF8.computeIfAbsent(cpSignature[index], k -> new CPUTF8(k, globalIndex));
196 }
197
198 public CPString cpStringValue(final int index) {
199 final String string = cpString[index];
200 final int utf8Index = cpStringInts[index];
201 final int globalIndex = stringOffset + index;
202 return stringsToCPStrings.computeIfAbsent(string, k -> new CPString(cpUTF8Value(utf8Index), globalIndex));
203 }
204
205 public CPUTF8 cpUTF8Value(final int index) {
206 final String string = cpUTF8[index];
207 CPUTF8 cputf8 = stringsToCPUTF8.get(string);
208 if (cputf8 == null) {
209 cputf8 = new CPUTF8(string, index);
210 stringsToCPUTF8.put(string, cputf8);
211 } else if (cputf8.getGlobalIndex() > index) {
212 cputf8.setGlobalIndex(index);
213 }
214 return cputf8;
215 }
216
217 public CPUTF8 cpUTF8Value(final String string) {
218 return cpUTF8Value(string, true);
219 }
220
221 public CPUTF8 cpUTF8Value(final String string, final boolean searchForIndex) {
222 CPUTF8 cputf8 = stringsToCPUTF8.get(string);
223 if (cputf8 == null) {
224 Integer index = null;
225 if (searchForIndex) {
226 index = mapUTF8.get(string);
227 }
228 if (index != null) {
229 return cpUTF8Value(index.intValue());
230 }
231 if (searchForIndex) {
232 index = mapSignature.get(string);
233 }
234 if (index != null) {
235 return cpSignatureValue(index.intValue());
236 }
237 cputf8 = new CPUTF8(string, -1);
238 stringsToCPUTF8.put(string, cputf8);
239 }
240 return cputf8;
241 }
242
243 public SegmentConstantPool getConstantPool() {
244 return pool;
245 }
246
247 public String[] getCpClass() {
248 return cpClass;
249 }
250
251 public String[] getCpDescriptor() {
252 return cpDescriptor;
253 }
254
255 public int[] getCpDescriptorNameInts() {
256 return cpDescriptorNameInts;
257 }
258
259 public int[] getCpDescriptorTypeInts() {
260 return cpDescriptorTypeInts;
261 }
262
263 public String[] getCpFieldClass() {
264 return cpFieldClass;
265 }
266
267 public String[] getCpIMethodClass() {
268 return cpIMethodClass;
269 }
270
271 public int[] getCpInt() {
272 return cpInt;
273 }
274
275 public long[] getCpLong() {
276 return cpLong;
277 }
278
279 public String[] getCpMethodClass() {
280 return cpMethodClass;
281 }
282
283 public String[] getCpMethodDescriptor() {
284 return cpMethodDescriptor;
285 }
286
287 public String[] getCpSignature() {
288 return cpSignature;
289 }
290
291 public String[] getCpUTF8() {
292 return cpUTF8;
293 }
294
295
296
297
298
299
300
301
302 private void parseCpClass(final InputStream in) throws IOException, Pack200Exception {
303 final int cpClassCount = header.getCpClassCount();
304 cpClassInts = decodeBandInt("cp_Class", in, Codec.UDELTA5, cpClassCount);
305 cpClass = new String[cpClassCount];
306 mapClass = new HashMap<>(cpClassCount);
307 for (int i = 0; i < cpClassCount; i++) {
308 cpClass[i] = cpUTF8[cpClassInts[i]];
309 mapClass.put(cpClass[i], Integer.valueOf(i));
310 }
311 }
312
313
314
315
316
317
318
319
320
321
322 private void parseCpDescriptor(final InputStream in) throws IOException, Pack200Exception {
323 final int cpDescriptorCount = header.getCpDescriptorCount();
324 cpDescriptorNameInts = decodeBandInt("cp_Descr_name", in, Codec.DELTA5, cpDescriptorCount);
325 cpDescriptorTypeInts = decodeBandInt("cp_Descr_type", in, Codec.UDELTA5, cpDescriptorCount);
326 final String[] cpDescriptorNames = getReferences(cpDescriptorNameInts, cpUTF8);
327 final String[] cpDescriptorTypes = getReferences(cpDescriptorTypeInts, cpSignature);
328 cpDescriptor = new String[cpDescriptorCount];
329 mapDescriptor = new HashMap<>(cpDescriptorCount);
330 for (int i = 0; i < cpDescriptorCount; i++) {
331 cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i];
332 mapDescriptor.put(cpDescriptor[i], Integer.valueOf(i));
333 }
334 }
335
336 private void parseCpDouble(final InputStream in) throws IOException, Pack200Exception {
337 final int cpDoubleCount = header.getCpDoubleCount();
338 final long[] band = parseFlags("cp_Double", in, cpDoubleCount, Codec.UDELTA5, Codec.DELTA5);
339 cpDouble = new double[band.length];
340 Arrays.setAll(cpDouble, i -> Double.longBitsToDouble(band[i]));
341 }
342
343
344
345
346
347
348
349
350 private void parseCpField(final InputStream in) throws IOException, Pack200Exception {
351 final int cpFieldCount = header.getCpFieldCount();
352 cpFieldClassInts = decodeBandInt("cp_Field_class", in, Codec.DELTA5, cpFieldCount);
353 cpFieldDescriptorInts = decodeBandInt("cp_Field_desc", in, Codec.UDELTA5, cpFieldCount);
354 cpFieldClass = new String[cpFieldCount];
355 cpFieldDescriptor = new String[cpFieldCount];
356 for (int i = 0; i < cpFieldCount; i++) {
357 cpFieldClass[i] = cpClass[cpFieldClassInts[i]];
358 cpFieldDescriptor[i] = cpDescriptor[cpFieldDescriptorInts[i]];
359 }
360 }
361
362 private void parseCpFloat(final InputStream in) throws IOException, Pack200Exception {
363 final int cpFloatCount = header.getCpFloatCount();
364 final int[] floatBits = decodeBandInt("cp_Float", in, Codec.UDELTA5, cpFloatCount);
365 cpFloat = new float[cpFloatCount];
366 for (int i = 0; i < cpFloatCount; i++) {
367 cpFloat[i] = Float.intBitsToFloat(floatBits[i]);
368 }
369 }
370
371
372
373
374
375
376
377
378
379 private void parseCpIMethod(final InputStream in) throws IOException, Pack200Exception {
380 final int cpIMethodCount = header.getCpIMethodCount();
381 cpIMethodClassInts = decodeBandInt("cp_Imethod_class", in, Codec.DELTA5, cpIMethodCount);
382 cpIMethodDescriptorInts = decodeBandInt("cp_Imethod_desc", in, Codec.UDELTA5, cpIMethodCount);
383 cpIMethodClass = new String[cpIMethodCount];
384 cpIMethodDescriptor = new String[cpIMethodCount];
385 for (int i = 0; i < cpIMethodCount; i++) {
386 cpIMethodClass[i] = cpClass[cpIMethodClassInts[i]];
387 cpIMethodDescriptor[i] = cpDescriptor[cpIMethodDescriptorInts[i]];
388 }
389 }
390
391 private void parseCpInt(final InputStream in) throws IOException, Pack200Exception {
392 final int cpIntCount = header.getCpIntCount();
393 cpInt = decodeBandInt("cpInt", in, Codec.UDELTA5, cpIntCount);
394 }
395
396 private void parseCpLong(final InputStream in) throws IOException, Pack200Exception {
397 final int cpLongCount = header.getCpLongCount();
398 cpLong = parseFlags("cp_Long", in, cpLongCount, Codec.UDELTA5, Codec.DELTA5);
399 }
400
401
402
403
404
405
406
407
408 private void parseCpMethod(final InputStream in) throws IOException, Pack200Exception {
409 final int cpMethodCount = header.getCpMethodCount();
410 cpMethodClassInts = decodeBandInt("cp_Method_class", in, Codec.DELTA5, cpMethodCount);
411 cpMethodDescriptorInts = decodeBandInt("cp_Method_desc", in, Codec.UDELTA5, cpMethodCount);
412 cpMethodClass = new String[cpMethodCount];
413 cpMethodDescriptor = new String[cpMethodCount];
414 for (int i = 0; i < cpMethodCount; i++) {
415 cpMethodClass[i] = cpClass[cpMethodClassInts[i]];
416 cpMethodDescriptor[i] = cpDescriptor[cpMethodDescriptorInts[i]];
417 }
418 }
419
420
421
422
423
424
425
426
427
428
429
430
431 private void parseCpSignature(final InputStream in) throws IOException, Pack200Exception {
432 final int cpSignatureCount = header.getCpSignatureCount();
433 cpSignatureInts = decodeBandInt("cp_Signature_form", in, Codec.DELTA5, cpSignatureCount);
434 final String[] cpSignatureForm = getReferences(cpSignatureInts, cpUTF8);
435 cpSignature = new String[cpSignatureCount];
436 mapSignature = new HashMap<>();
437 int lCount = 0;
438 for (int i = 0; i < cpSignatureCount; i++) {
439 final String form = cpSignatureForm[i];
440 final char[] chars = form.toCharArray();
441 for (final char element : chars) {
442 if (element == 'L') {
443 cpSignatureInts[i] = -1;
444 lCount++;
445 }
446 }
447 }
448 final String[] cpSignatureClasses = parseReferences("cp_Signature_classes", in, Codec.UDELTA5, lCount, cpClass);
449 int index = 0;
450 for (int i = 0; i < cpSignatureCount; i++) {
451 final String form = cpSignatureForm[i];
452 final int len = form.length();
453 final StringBuilder signature = new StringBuilder(64);
454 for (int j = 0; j < len; j++) {
455 final char c = form.charAt(j);
456 signature.append(c);
457 if (c == 'L') {
458 final String className = cpSignatureClasses[index];
459 signature.append(className);
460 index++;
461 }
462 }
463 cpSignature[i] = signature.toString();
464 mapSignature.put(signature.toString(), Integer.valueOf(i));
465 }
466
467
468
469
470
471 }
472
473
474
475
476
477
478
479
480 private void parseCpString(final InputStream in) throws IOException, Pack200Exception {
481 final int cpStringCount = header.getCpStringCount();
482 cpStringInts = decodeBandInt("cp_String", in, Codec.UDELTA5, cpStringCount);
483 cpString = new String[cpStringCount];
484 Arrays.setAll(cpString, i -> cpUTF8[cpStringInts[i]]);
485 }
486
487 private void parseCpUtf8(final InputStream in) throws IOException, Pack200Exception {
488 final int cpUTF8Count = header.getCpUTF8Count();
489 if (cpUTF8Count <= 0) {
490 throw new IOException("cpUTF8Count value must be greater than 0");
491 }
492 final int[] prefix = decodeBandInt("cpUTF8Prefix", in, Codec.DELTA5, cpUTF8Count - 2);
493 int charCount = 0;
494 int bigSuffixCount = 0;
495 final int[] suffix = decodeBandInt("cpUTF8Suffix", in, Codec.UNSIGNED5, cpUTF8Count - 1);
496
497 for (final int element : suffix) {
498 if (element == 0) {
499 bigSuffixCount++;
500 } else {
501 charCount += element;
502 }
503 }
504 final int[] dataBand = decodeBandInt("cp_Utf8_chars", in, Codec.CHAR3, charCount);
505 final char[] data = new char[charCount];
506 for (int i = 0; i < data.length; i++) {
507 data[i] = (char) dataBand[i];
508 }
509
510
511 final int[] bigSuffixCounts = decodeBandInt("cp_Utf8_big_suffix", in, Codec.DELTA5, bigSuffixCount);
512 final int[][] bigSuffixDataBand = new int[bigSuffixCount][];
513 for (int i = 0; i < bigSuffixDataBand.length; i++) {
514 bigSuffixDataBand[i] = decodeBandInt("cp_Utf8_big_chars " + i, in, Codec.DELTA5, bigSuffixCounts[i]);
515 }
516
517
518 final char[][] bigSuffixData = new char[bigSuffixCount][];
519 for (int i = 0; i < bigSuffixDataBand.length; i++) {
520 bigSuffixData[i] = new char[bigSuffixDataBand[i].length];
521 for (int j = 0; j < bigSuffixDataBand[i].length; j++) {
522 bigSuffixData[i][j] = (char) bigSuffixDataBand[i][j];
523 }
524 }
525
526
527 mapUTF8 = new HashMap<>(cpUTF8Count + 1);
528 cpUTF8 = new String[cpUTF8Count];
529 cpUTF8[0] = EMPTY_STRING;
530 mapUTF8.put(EMPTY_STRING, Integer.valueOf(0));
531
532
533 charCount = 0;
534 bigSuffixCount = 0;
535 for (int i = 1; i < cpUTF8Count; i++) {
536 final String lastString = cpUTF8[i - 1];
537 if (suffix[i - 1] == 0) {
538
539
540 cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0) + new String(bigSuffixData[bigSuffixCount++]);
541 } else {
542 cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0) + new String(data, charCount, suffix[i - 1]);
543 charCount += suffix[i - 1];
544 }
545 mapUTF8.put(cpUTF8[i], Integer.valueOf(i));
546 }
547 }
548
549 @Override
550 public void read(final InputStream in) throws IOException, Pack200Exception {
551 parseCpUtf8(in);
552 parseCpInt(in);
553 parseCpFloat(in);
554 parseCpLong(in);
555 parseCpDouble(in);
556 parseCpString(in);
557 parseCpClass(in);
558 parseCpSignature(in);
559 parseCpDescriptor(in);
560 parseCpField(in);
561 parseCpMethod(in);
562 parseCpIMethod(in);
563
564 intOffset = cpUTF8.length;
565 floatOffset = intOffset + cpInt.length;
566 longOffset = floatOffset + cpFloat.length;
567 doubleOffset = longOffset + cpLong.length;
568 stringOffset = doubleOffset + cpDouble.length;
569 classOffset = stringOffset + cpString.length;
570 signatureOffset = classOffset + cpClass.length;
571 descrOffset = signatureOffset + cpSignature.length;
572 fieldOffset = descrOffset + cpDescriptor.length;
573 methodOffset = fieldOffset + cpFieldClass.length;
574 imethodOffset = methodOffset + cpMethodClass.length;
575 }
576
577 @Override
578 public void unpack() {
579
580 }
581
582 }