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