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
25 import org.apache.commons.compress.harmony.pack200.BHSDCodec;
26 import org.apache.commons.compress.harmony.pack200.Codec;
27 import org.apache.commons.compress.harmony.pack200.CodecEncoding;
28 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
29 import org.apache.commons.compress.harmony.pack200.PopulationCodec;
30 import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
31 import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
32 import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
33 import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
34 import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
35 import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
36 import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
37 import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
38 import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
39 import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
40 import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
41 import org.apache.commons.compress.utils.ExactMath;
42 import org.apache.commons.lang3.ArrayUtils;
43
44
45
46
47 public abstract class BandSet {
48
49
50
51
52 protected Segment segment;
53
54
55
56
57 protected SegmentHeader header;
58
59
60
61
62
63
64 public BandSet(final Segment segment) {
65 this.segment = segment;
66 this.header = segment.getSegmentHeader();
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80 public int[] decodeBandInt(final String name, final InputStream in, final BHSDCodec codec, final int count) throws IOException, Pack200Exception {
81 if (count < 0) {
82 throw new Pack200Exception("count < 0");
83 }
84
85
86
87
88 Codec codecUsed = codec;
89 if (codec.getB() == 1 || count == 0) {
90 return codec.decodeInts(count, in);
91 }
92 final int[] getFirst = codec.decodeInts(1, in);
93 if (getFirst.length == 0) {
94 return getFirst;
95 }
96 final int first = getFirst[0];
97 final int[] band;
98 if (codec.isSigned() && first >= -256 && first <= -1) {
99
100 codecUsed = CodecEncoding.getCodec(-1 - first, header.getBandHeadersInputStream(), codec);
101 band = codecUsed.decodeInts(count, in);
102 } else if (!codec.isSigned() && first >= codec.getL() && first <= codec.getL() + 255) {
103
104 codecUsed = CodecEncoding.getCodec(first - codec.getL(), header.getBandHeadersInputStream(), codec);
105 band = codecUsed.decodeInts(count, in);
106 } else {
107
108 band = codec.decodeInts(count - 1, in, first);
109 }
110
111
112
113
114
115 if (codecUsed instanceof PopulationCodec) {
116 final PopulationCodec popCodec = (PopulationCodec) codecUsed;
117 final int[] favoured = popCodec.getFavoured().clone();
118 Arrays.sort(favoured);
119 for (int i = 0; i < band.length; i++) {
120 final boolean favouredValue = Arrays.binarySearch(favoured, band[i]) > -1;
121 final Codec theCodec = favouredValue ? popCodec.getFavouredCodec() : popCodec.getUnfavouredCodec();
122 if (theCodec instanceof BHSDCodec && ((BHSDCodec) theCodec).isDelta()) {
123 final BHSDCodec bhsd = (BHSDCodec) theCodec;
124 final long cardinality = bhsd.cardinality();
125 while (band[i] > bhsd.largest()) {
126 band[i] -= cardinality;
127 }
128 while (band[i] < bhsd.smallest()) {
129 band[i] = ExactMath.add(band[i], cardinality);
130 }
131 }
132 }
133 }
134 return band;
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148 public int[][] decodeBandInt(final String name, final InputStream in, final BHSDCodec defaultCodec, final int[] counts)
149 throws IOException, Pack200Exception {
150 final int[][] result = new int[counts.length][];
151 int totalCount = 0;
152 for (final int count : counts) {
153 totalCount += count;
154 }
155 final int[] twoDResult = decodeBandInt(name, in, defaultCodec, totalCount);
156 int index = 0;
157 for (int i = 0; i < result.length; i++) {
158 if (counts[i] > twoDResult.length) {
159 throw new IOException("Counts value exceeds length of twoDResult");
160 }
161 result[i] = new int[counts[i]];
162 for (int j = 0; j < result[i].length; j++) {
163 result[i][j] = twoDResult[index];
164 index++;
165 }
166 }
167 return result;
168 }
169
170
171
172
173
174
175
176
177 protected String[] getReferences(final int[] ints, final String[] reference) {
178 return ArrayUtils.setAll(new String[ints.length], i -> reference[ints[i]]);
179 }
180
181
182
183
184
185
186
187
188 protected String[][] getReferences(final int[][] ints, final String[] reference) {
189 final String[][] result = new String[ints.length][];
190 for (int i = 0; i < result.length; i++) {
191 result[i] = new String[ints[i].length];
192 for (int j = 0; j < result[i].length; j++) {
193 result[i][j] = reference[ints[i][j]];
194 }
195 }
196 return result;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210 public CPClass[] parseCPClassReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
211 throws IOException, Pack200Exception {
212 final int[] indices = decodeBandInt(name, in, codec, count);
213 final CpBands cpBands = segment.getCpBands();
214 return ArrayUtils.setAll(new CPClass[indices.length], i -> cpBands.cpClassValue(indices[i]));
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228 public CPNameAndType[] parseCPDescriptorReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
229 throws IOException, Pack200Exception {
230 final int[] indices = decodeBandInt(name, in, codec, count);
231 final CpBands cpBands = segment.getCpBands();
232 return ArrayUtils.setAll(new CPNameAndType[indices.length], i -> cpBands.cpNameAndTypeValue(indices[i]));
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246 public CPDouble[] parseCPDoubleReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
247 throws IOException, Pack200Exception {
248 final int[] indices = decodeBandInt(name, in, codec, count);
249 final CpBands cpBands = segment.getCpBands();
250 return ArrayUtils.setAll(new CPDouble[indices.length], i -> cpBands.cpDoubleValue(indices[i]));
251 }
252
253
254
255
256
257
258
259
260
261
262
263
264 public CPFieldRef[] parseCPFieldRefReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
265 throws IOException, Pack200Exception {
266 final int[] indices = decodeBandInt(name, in, codec, count);
267 final CpBands cpBands = segment.getCpBands();
268 return ArrayUtils.setAll(new CPFieldRef[indices.length], i -> cpBands.cpFieldValue(indices[i]));
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282 public CPFloat[] parseCPFloatReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
283 throws IOException, Pack200Exception {
284 final int[] indices = decodeBandInt(name, in, codec, count);
285 final CpBands cpBands = segment.getCpBands();
286 return ArrayUtils.setAll(new CPFloat[indices.length], i -> cpBands.cpFloatValue(indices[i]));
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300 public CPInterfaceMethodRef[] parseCPInterfaceMethodRefReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
301 throws IOException, Pack200Exception {
302 final int[] indices = decodeBandInt(name, in, codec, count);
303 final CpBands cpBands = segment.getCpBands();
304 return ArrayUtils.setAll(new CPInterfaceMethodRef[indices.length], i -> cpBands.cpIMethodValue(indices[i]));
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318 public CPInteger[] parseCPIntReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
319 throws IOException, Pack200Exception {
320 final CpBands cpBands = segment.getCpBands();
321 final int[] reference = cpBands.getCpInt();
322 final int[] indices = decodeBandInt(name, in, codec, count);
323 final CPInteger[] result = new CPInteger[indices.length];
324 for (int i = 0; i < count; i++) {
325 final int index = indices[i];
326 if (index < 0 || index >= reference.length) {
327 throw new Pack200Exception("Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
328 }
329 result[i] = cpBands.cpIntegerValue(index);
330 }
331 return result;
332 }
333
334
335
336
337
338
339
340
341
342
343
344
345 public CPLong[] parseCPLongReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
346 throws IOException, Pack200Exception {
347 final CpBands cpBands = segment.getCpBands();
348 final long[] reference = cpBands.getCpLong();
349 final int[] indices = decodeBandInt(name, in, codec, count);
350 final CPLong[] result = new CPLong[indices.length];
351 for (int i = 0; i < count; i++) {
352 final int index = indices[i];
353 if (index < 0 || index >= reference.length) {
354 throw new Pack200Exception("Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
355 }
356 result[i] = cpBands.cpLongValue(index);
357 }
358 return result;
359 }
360
361
362
363
364
365
366
367
368
369
370
371
372 public CPMethodRef[] parseCPMethodRefReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
373 throws IOException, Pack200Exception {
374 final int[] indices = decodeBandInt(name, in, codec, count);
375 final CpBands cpBands = segment.getCpBands();
376 return ArrayUtils.setAll(new CPMethodRef[indices.length], i -> cpBands.cpMethodValue(indices[i]));
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390 public CPUTF8[] parseCPSignatureReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
391 throws IOException, Pack200Exception {
392 final int[] indices = decodeBandInt(name, in, codec, count);
393 final CpBands cpBands = segment.getCpBands();
394 return ArrayUtils.setAll(new CPUTF8[indices.length], i -> cpBands.cpSignatureValue(indices[i]));
395 }
396
397
398
399
400
401
402
403
404
405
406
407
408 protected CPUTF8[][] parseCPSignatureReferences(final String name, final InputStream in, final BHSDCodec codec, final int[] counts)
409 throws IOException, Pack200Exception {
410 int sum = 0;
411 for (final int count : counts) {
412 sum += count;
413 }
414 final int[] indices = decodeBandInt(name, in, codec, sum);
415 final CpBands cpBands = segment.getCpBands();
416 final CPUTF8[] result1 = ArrayUtils.setAll(new CPUTF8[sum], i -> cpBands.cpSignatureValue(indices[i]));
417 int pos = 0;
418 final CPUTF8[][] result = new CPUTF8[counts.length][];
419 for (int i = 0; i < counts.length; i++) {
420 final int num = counts[i];
421 result[i] = new CPUTF8[num];
422 System.arraycopy(result1, pos, result[i], 0, num);
423 pos += num;
424 }
425 return result;
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439 public CPString[] parseCPStringReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
440 throws IOException, Pack200Exception {
441 final int[] indices = decodeBandInt(name, in, codec, count);
442 final CpBands cpBands = segment.getCpBands();
443 return ArrayUtils.setAll(new CPString[indices.length], i -> cpBands.cpStringValue(indices[i]));
444 }
445
446
447
448
449
450
451
452
453
454
455
456
457 public CPUTF8[] parseCPUTF8References(final String name, final InputStream in, final BHSDCodec codec, final int count)
458 throws IOException, Pack200Exception {
459 final int[] indices = decodeBandInt(name, in, codec, count);
460 final CpBands cpBands = segment.getCpBands();
461 return ArrayUtils.setAll(new CPUTF8[indices.length], i -> cpBands.cpUTF8Value(indices[i]));
462 }
463
464
465
466
467
468
469
470
471
472
473
474
475 public CPUTF8[][] parseCPUTF8References(final String name, final InputStream in, final BHSDCodec codec, final int[] counts)
476 throws IOException, Pack200Exception {
477 final CPUTF8[][] result = new CPUTF8[counts.length][];
478 int sum = 0;
479 for (int i = 0; i < counts.length; i++) {
480 result[i] = new CPUTF8[counts[i]];
481 sum += counts[i];
482 }
483 final int[] indices = decodeBandInt(name, in, codec, sum);
484 final CpBands cpBands = segment.getCpBands();
485 final CPUTF8[] result1 = ArrayUtils.setAll(new CPUTF8[sum], i -> cpBands.cpUTF8Value(indices[i]));
486 int pos = 0;
487 for (int i = 0; i < counts.length; i++) {
488 final int num = counts[i];
489 result[i] = new CPUTF8[num];
490 System.arraycopy(result1, pos, result[i], 0, num);
491 pos += num;
492 }
493 return result;
494 }
495
496
497
498
499
500
501
502
503
504
505
506
507
508 public long[] parseFlags(final String name, final InputStream in, final int count, final BHSDCodec hiCodec, final BHSDCodec loCodec)
509 throws IOException, Pack200Exception {
510 return parseFlags(name, in, new int[] { count }, hiCodec, loCodec)[0];
511 }
512
513
514
515
516
517
518
519
520
521
522
523
524
525 public long[] parseFlags(final String name, final InputStream in, final int count, final BHSDCodec codec, final boolean hasHi)
526 throws IOException, Pack200Exception {
527 return parseFlags(name, in, new int[] { count }, hasHi ? codec : null, codec)[0];
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541
542 public long[][] parseFlags(final String name, final InputStream in, final int[] counts, final BHSDCodec hiCodec, final BHSDCodec loCodec)
543 throws IOException, Pack200Exception {
544 final int count = counts.length;
545 if (count == 0) {
546 return new long[][] { {} };
547 }
548 int sum = 0;
549 final long[][] result = new long[count][];
550 for (int i = 0; i < count; i++) {
551 sum += counts[i];
552 }
553 int[] hi = null;
554 final int[] lo;
555 if (hiCodec != null) {
556 hi = decodeBandInt(name, in, hiCodec, sum);
557 }
558 lo = decodeBandInt(name, in, loCodec, sum);
559
560 int index = 0;
561 for (int i = 0; i < count; i++) {
562 result[i] = new long[counts[i]];
563 for (int j = 0; j < result[i].length; j++) {
564 if (hi != null) {
565 result[i][j] = (long) hi[index] << 32 | lo[index] & 4294967295L;
566 } else {
567 result[i][j] = lo[index];
568 }
569 index++;
570 }
571 }
572 return result;
573 }
574
575
576
577
578
579
580
581
582
583
584
585
586
587 public long[][] parseFlags(final String name, final InputStream in, final int[] counts, final BHSDCodec codec, final boolean hasHi)
588 throws IOException, Pack200Exception {
589 return parseFlags(name, in, counts, hasHi ? codec : null, codec);
590 }
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 public String[] parseReferences(final String name, final InputStream in, final BHSDCodec codec, final int count, final String[] reference)
606 throws IOException, Pack200Exception {
607 return parseReferences(name, in, codec, new int[] { count }, reference)[0];
608 }
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624 public String[][] parseReferences(final String name, final InputStream in, final BHSDCodec codec, final int[] counts, final String[] reference)
625 throws IOException, Pack200Exception {
626 final int count = counts.length;
627 if (count == 0) {
628 return new String[][] { {} };
629 }
630 int sum = 0;
631 for (int i = 0; i < count; i++) {
632 sum += counts[i];
633 }
634
635 final int[] indices = decodeBandInt(name, in, codec, sum);
636 final String[] result1 = new String[sum];
637 for (int i1 = 0; i1 < sum; i1++) {
638 final int index = indices[i1];
639 if (index < 0 || index >= reference.length) {
640 throw new Pack200Exception("Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
641 }
642 result1[i1] = reference[index];
643 }
644
645 final String[][] result = new String[count][];
646 int pos = 0;
647 for (int i = 0; i < count; i++) {
648 final int num = counts[i];
649 result[i] = new String[num];
650 System.arraycopy(result1, pos, result[i], 0, num);
651 pos += num;
652 }
653 return result;
654 }
655
656
657
658
659
660
661
662
663 public abstract void read(InputStream inputStream) throws IOException, Pack200Exception;
664
665
666
667
668
669
670
671 public abstract void unpack() throws IOException, Pack200Exception;
672
673
674
675
676
677
678
679
680 public void unpack(final InputStream in) throws IOException, Pack200Exception {
681 read(in);
682 unpack();
683 }
684
685 }