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