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.io.StringReader;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27
28 import org.apache.commons.compress.harmony.pack200.BHSDCodec;
29 import org.apache.commons.compress.harmony.pack200.Codec;
30 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
31 import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
32 import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
33 import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
34 import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
35 import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
36 import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
37 import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
38 import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
39 import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
40 import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
41 import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
42 import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
43 import org.apache.commons.compress.harmony.unpack200.bytecode.NewAttribute;
44 import org.apache.commons.compress.utils.ParsingUtils;
45
46
47
48
49 public class NewAttributeBands extends BandSet {
50
51
52
53
54
55 private interface AttributeLayoutElement {
56
57
58
59
60
61
62
63 void addToAttribute(int index, NewAttribute attribute);
64
65
66
67
68
69
70
71
72
73 void readBands(InputStream in, int count) throws IOException, Pack200Exception;
74
75 }
76
77 public class Call extends LayoutElement {
78
79 private final int callableIndex;
80 private Callable callable;
81
82 public Call(final int callableIndex) {
83 this.callableIndex = callableIndex;
84 }
85
86 @Override
87 public void addToAttribute(final int n, final NewAttribute attribute) {
88 callable.addNextToAttribute(attribute);
89 }
90
91 public Callable getCallable() {
92 return callable;
93 }
94
95 public int getCallableIndex() {
96 return callableIndex;
97 }
98
99 @Override
100 public void readBands(final InputStream in, final int count) {
101
102
103
104
105 if (callableIndex > 0) {
106 callable.addCount(count);
107 }
108 }
109
110 public void setCallable(final Callable callable) {
111 this.callable = callable;
112 if (callableIndex < 1) {
113 callable.setBackwardsCallable();
114 }
115 }
116 }
117
118 public static class Callable implements AttributeLayoutElement {
119
120 private final List<LayoutElement> body;
121
122 private boolean isBackwardsCallable;
123
124 private boolean isFirstCallable;
125
126 private int count;
127
128 private int index;
129
130 public Callable(final List<LayoutElement> body) {
131 this.body = body;
132 }
133
134
135
136
137
138
139 public void addCount(final int count) {
140 this.count += count;
141 }
142
143
144
145
146
147
148 public void addNextToAttribute(final NewAttribute attribute) {
149 for (final LayoutElement element : body) {
150 element.addToAttribute(index, attribute);
151 }
152 index++;
153 }
154
155 @Override
156 public void addToAttribute(final int n, final NewAttribute attribute) {
157 if (isFirstCallable) {
158
159 for (final LayoutElement element : body) {
160 element.addToAttribute(index, attribute);
161 }
162 index++;
163 }
164 }
165
166 public List<LayoutElement> getBody() {
167 return body;
168 }
169
170 public boolean isBackwardsCallable() {
171 return isBackwardsCallable;
172 }
173
174 @Override
175 public void readBands(final InputStream in, int count) throws IOException, Pack200Exception {
176 if (isFirstCallable) {
177 count += this.count;
178 } else {
179 count = this.count;
180 }
181 for (final LayoutElement element : body) {
182 element.readBands(in, count);
183 }
184 }
185
186
187
188
189 public void setBackwardsCallable() {
190 this.isBackwardsCallable = true;
191 }
192
193 public void setFirstCallable(final boolean isFirstCallable) {
194 this.isFirstCallable = isFirstCallable;
195 }
196 }
197
198 public class Integral extends LayoutElement {
199
200 private final String tag;
201
202 private int[] band;
203
204 public Integral(final String tag) {
205 this.tag = tag;
206 }
207
208 @Override
209 public void addToAttribute(final int n, final NewAttribute attribute) {
210 int value = band[n];
211 switch (tag) {
212 case "B":
213 case "FB":
214 attribute.addInteger(1, value);
215 break;
216 case "SB":
217 attribute.addInteger(1, (byte) value);
218 break;
219 case "H":
220 case "FH":
221 attribute.addInteger(2, value);
222 break;
223 case "SH":
224 attribute.addInteger(2, (short) value);
225 break;
226 case "I":
227 case "FI":
228 case "SI":
229 attribute.addInteger(4, value);
230 break;
231 case "V":
232 case "FV":
233 case "SV":
234 break;
235 default:
236 if (tag.startsWith("PO")) {
237 final char uintType = tag.substring(2).toCharArray()[0];
238 final int length = getLength(uintType);
239 attribute.addBCOffset(length, value);
240 } else if (tag.startsWith("P")) {
241 final char uintType = tag.substring(1).toCharArray()[0];
242 final int length = getLength(uintType);
243 attribute.addBCIndex(length, value);
244 } else if (tag.startsWith("OS")) {
245 final char uintType = tag.substring(2).toCharArray()[0];
246 final int length = getLength(uintType);
247 switch (length) {
248 case 1:
249 value = (byte) value;
250 break;
251 case 2:
252 value = (short) value;
253 break;
254 case 4:
255 value = value;
256 break;
257 default:
258 break;
259 }
260 attribute.addBCLength(length, value);
261 } else if (tag.startsWith("O")) {
262 final char uintType = tag.substring(1).toCharArray()[0];
263 final int length = getLength(uintType);
264 attribute.addBCLength(length, value);
265 }
266 break;
267 }
268 }
269
270 public String getTag() {
271 return tag;
272 }
273
274 int getValue(final int index) {
275 return band[index];
276 }
277
278 @Override
279 public void readBands(final InputStream in, final int count) throws IOException, Pack200Exception {
280 band = decodeBandInt(attributeLayout.getName() + "_" + tag, in, getCodec(tag), count);
281 }
282
283 }
284
285 private abstract static class LayoutElement implements AttributeLayoutElement {
286
287 protected int getLength(final char uintType) {
288 int length = 0;
289 switch (uintType) {
290 case 'B':
291 length = 1;
292 break;
293 case 'H':
294 length = 2;
295 break;
296 case 'I':
297 length = 4;
298 break;
299 case 'V':
300 length = 0;
301 break;
302 }
303 return length;
304 }
305 }
306
307
308
309
310 public class Reference extends LayoutElement {
311
312 private final String tag;
313
314 private Object band;
315
316 private final int length;
317
318 public Reference(final String tag) {
319 this.tag = tag;
320 length = getLength(tag.charAt(tag.length() - 1));
321 }
322
323 @Override
324 public void addToAttribute(final int n, final NewAttribute attribute) {
325 if (tag.startsWith("KI")) {
326 attribute.addToBody(length, ((CPInteger[]) band)[n]);
327 } else if (tag.startsWith("KJ")) {
328 attribute.addToBody(length, ((CPLong[]) band)[n]);
329 } else if (tag.startsWith("KF")) {
330 attribute.addToBody(length, ((CPFloat[]) band)[n]);
331 } else if (tag.startsWith("KD")) {
332 attribute.addToBody(length, ((CPDouble[]) band)[n]);
333 } else if (tag.startsWith("KS")) {
334 attribute.addToBody(length, ((CPString[]) band)[n]);
335 } else if (tag.startsWith("RC")) {
336 attribute.addToBody(length, ((CPClass[]) band)[n]);
337 } else if (tag.startsWith("RS")) {
338 attribute.addToBody(length, ((CPUTF8[]) band)[n]);
339 } else if (tag.startsWith("RD")) {
340 attribute.addToBody(length, ((CPNameAndType[]) band)[n]);
341 } else if (tag.startsWith("RF")) {
342 attribute.addToBody(length, ((CPFieldRef[]) band)[n]);
343 } else if (tag.startsWith("RM")) {
344 attribute.addToBody(length, ((CPMethodRef[]) band)[n]);
345 } else if (tag.startsWith("RI")) {
346 attribute.addToBody(length, ((CPInterfaceMethodRef[]) band)[n]);
347 } else if (tag.startsWith("RU")) {
348 attribute.addToBody(length, ((CPUTF8[]) band)[n]);
349 }
350 }
351
352 public String getTag() {
353 return tag;
354 }
355
356 @Override
357 public void readBands(final InputStream in, final int count) throws IOException, Pack200Exception {
358 if (tag.startsWith("KI")) {
359 band = parseCPIntReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
360 } else if (tag.startsWith("KJ")) {
361 band = parseCPLongReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
362 } else if (tag.startsWith("KF")) {
363 band = parseCPFloatReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
364 } else if (tag.startsWith("KD")) {
365 band = parseCPDoubleReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
366 } else if (tag.startsWith("KS")) {
367 band = parseCPStringReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
368 } else if (tag.startsWith("RC")) {
369 band = parseCPClassReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
370 } else if (tag.startsWith("RS")) {
371 band = parseCPSignatureReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
372 } else if (tag.startsWith("RD")) {
373 band = parseCPDescriptorReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
374 } else if (tag.startsWith("RF")) {
375 band = parseCPFieldRefReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
376 } else if (tag.startsWith("RM")) {
377 band = parseCPMethodRefReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
378 } else if (tag.startsWith("RI")) {
379 band = parseCPInterfaceMethodRefReferences(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
380 } else if (tag.startsWith("RU")) {
381 band = parseCPUTF8References(attributeLayout.getName(), in, Codec.UNSIGNED5, count);
382 }
383 }
384
385 }
386
387
388
389
390 public class Replication extends LayoutElement {
391
392 private final Integral countElement;
393
394 private final List<LayoutElement> layoutElements = new ArrayList<>();
395
396 public Replication(final String tag, final String contents) throws IOException {
397 this.countElement = new Integral(tag);
398 final StringReader stream = new StringReader(contents);
399 LayoutElement e;
400 while ((e = readNextLayoutElement(stream)) != null) {
401 layoutElements.add(e);
402 }
403 }
404
405 @Override
406 public void addToAttribute(final int index, final NewAttribute attribute) {
407
408 countElement.addToAttribute(index, attribute);
409
410
411 int offset = 0;
412 for (int i = 0; i < index; i++) {
413 offset += countElement.getValue(i);
414 }
415 final long numElements = countElement.getValue(index);
416 for (int i = offset; i < offset + numElements; i++) {
417 for (final LayoutElement layoutElement : layoutElements) {
418 layoutElement.addToAttribute(i, attribute);
419 }
420 }
421 }
422
423 public Integral getCountElement() {
424 return countElement;
425 }
426
427 public List<LayoutElement> getLayoutElements() {
428 return layoutElements;
429 }
430
431 @Override
432 public void readBands(final InputStream in, final int count) throws IOException, Pack200Exception {
433 countElement.readBands(in, count);
434 int arrayCount = 0;
435 for (int i = 0; i < count; i++) {
436 arrayCount += countElement.getValue(i);
437 }
438 for (final LayoutElement layoutElement : layoutElements) {
439 layoutElement.readBands(in, arrayCount);
440 }
441 }
442 }
443
444
445
446
447 public class Union extends LayoutElement {
448
449 private final Integral unionTag;
450 private final List<UnionCase> unionCases;
451 private final List<LayoutElement> defaultCaseBody;
452 private int[] caseCounts;
453 private int defaultCount;
454
455 public Union(final String tag, final List<UnionCase> unionCases, final List<LayoutElement> body) {
456 this.unionTag = new Integral(tag);
457 this.unionCases = unionCases;
458 this.defaultCaseBody = body;
459 }
460
461 @Override
462 public void addToAttribute(final int n, final NewAttribute attribute) {
463 unionTag.addToAttribute(n, attribute);
464 int offset = 0;
465 final int[] tagBand = unionTag.band;
466 final int tag = unionTag.getValue(n);
467 boolean defaultCase = true;
468 for (final UnionCase unionCase : unionCases) {
469 if (unionCase.hasTag(tag)) {
470 defaultCase = false;
471 for (int j = 0; j < n; j++) {
472 if (unionCase.hasTag(tagBand[j])) {
473 offset++;
474 }
475 }
476 unionCase.addToAttribute(offset, attribute);
477 }
478 }
479 if (defaultCase) {
480
481 int defaultOffset = 0;
482 for (int j = 0; j < n; j++) {
483 boolean found = false;
484 for (final UnionCase unionCase : unionCases) {
485 if (unionCase.hasTag(tagBand[j])) {
486 found = true;
487 }
488 }
489 if (!found) {
490 defaultOffset++;
491 }
492 }
493 if (defaultCaseBody != null) {
494 for (final LayoutElement element : defaultCaseBody) {
495 element.addToAttribute(defaultOffset, attribute);
496 }
497 }
498 }
499 }
500
501 public List<LayoutElement> getDefaultCaseBody() {
502 return defaultCaseBody;
503 }
504
505 public List<UnionCase> getUnionCases() {
506 return unionCases;
507 }
508
509 public Integral getUnionTag() {
510 return unionTag;
511 }
512
513 @Override
514 public void readBands(final InputStream in, final int count) throws IOException, Pack200Exception {
515 unionTag.readBands(in, count);
516 final int[] values = unionTag.band;
517
518 caseCounts = new int[unionCases.size()];
519 for (int i = 0; i < caseCounts.length; i++) {
520 final UnionCase unionCase = unionCases.get(i);
521 for (final int value : values) {
522 if (unionCase.hasTag(value)) {
523 caseCounts[i]++;
524 }
525 }
526 unionCase.readBands(in, caseCounts[i]);
527 }
528
529 for (final int value : values) {
530 boolean found = false;
531 for (final UnionCase unionCase : unionCases) {
532 if (unionCase.hasTag(value)) {
533 found = true;
534 }
535 }
536 if (!found) {
537 defaultCount++;
538 }
539 }
540 if (defaultCaseBody != null) {
541 for (final LayoutElement element : defaultCaseBody) {
542 element.readBands(in, defaultCount);
543 }
544 }
545 }
546
547 }
548
549
550
551
552 public class UnionCase extends LayoutElement {
553
554 private List<LayoutElement> body;
555
556 private final List<Integer> tags;
557
558 public UnionCase(final List<Integer> tags) {
559 this.tags = tags;
560 }
561
562 public UnionCase(final List<Integer> tags, final List<LayoutElement> body) {
563 this.tags = tags;
564 this.body = body;
565 }
566
567 @Override
568 public void addToAttribute(final int index, final NewAttribute attribute) {
569 if (body != null) {
570 for (final LayoutElement element : body) {
571 element.addToAttribute(index, attribute);
572 }
573 }
574 }
575
576 public List<LayoutElement> getBody() {
577 return body == null ? Collections.EMPTY_LIST : body;
578 }
579
580 public boolean hasTag(final int i) {
581 return tags.contains(Integer.valueOf(i));
582 }
583
584 public boolean hasTag(final long l) {
585 return tags.contains(Integer.valueOf((int) l));
586 }
587
588 @Override
589 public void readBands(final InputStream in, final int count) throws IOException, Pack200Exception {
590 if (body != null) {
591 for (final LayoutElement element : body) {
592 element.readBands(in, count);
593 }
594 }
595 }
596 }
597
598 private final AttributeLayout attributeLayout;
599
600 private int backwardsCallCount;
601
602 protected List<AttributeLayoutElement> attributeLayoutElements;
603
604 public NewAttributeBands(final Segment segment, final AttributeLayout attributeLayout) throws IOException {
605 super(segment);
606 this.attributeLayout = attributeLayout;
607 parseLayout();
608 attributeLayout.setBackwardsCallCount(backwardsCallCount);
609 }
610
611 public int getBackwardsCallCount() {
612 return backwardsCallCount;
613 }
614
615
616
617
618
619
620
621 public BHSDCodec getCodec(final String layoutElement) {
622 if (layoutElement.indexOf('O') >= 0) {
623 return Codec.BRANCH5;
624 }
625 if (layoutElement.indexOf('P') >= 0) {
626 return Codec.BCI5;
627 }
628 if (layoutElement.indexOf('S') >= 0 && !layoutElement.contains("KS")
629 && !layoutElement.contains("RS")) {
630 return Codec.SIGNED5;
631 }
632 if (layoutElement.indexOf('B') >= 0) {
633 return Codec.BYTE1;
634 }
635 return Codec.UNSIGNED5;
636 }
637
638
639
640
641
642
643
644
645 private Attribute getOneAttribute(final int index, final List<AttributeLayoutElement> elements) {
646 final NewAttribute attribute = new NewAttribute(segment.getCpBands().cpUTF8Value(attributeLayout.getName()), attributeLayout.getIndex());
647 for (final AttributeLayoutElement element : elements) {
648 element.addToAttribute(index, attribute);
649 }
650 return attribute;
651 }
652
653
654
655
656
657
658
659
660 private StringReader getStreamUpToMatchingBracket(final StringReader stream) throws IOException {
661 final StringBuilder sb = new StringBuilder();
662 int foundBracket = -1;
663 while (foundBracket != 0) {
664 final int read = stream.read();
665 if (read == -1) {
666 break;
667 }
668 final char c = (char) read;
669 if (c == ']') {
670 foundBracket++;
671 }
672 if (c == '[') {
673 foundBracket--;
674 }
675 if (!(foundBracket == 0)) {
676 sb.append(c);
677 }
678 }
679 return new StringReader(sb.toString());
680 }
681
682
683
684
685
686
687
688
689
690
691 public List<Attribute> parseAttributes(final InputStream in, final int occurrenceCount) throws IOException, Pack200Exception {
692 for (final AttributeLayoutElement element : attributeLayoutElements) {
693 element.readBands(in, occurrenceCount);
694 }
695
696 final List<Attribute> attributes = new ArrayList<>(occurrenceCount);
697 for (int i = 0; i < occurrenceCount; i++) {
698 attributes.add(getOneAttribute(i, attributeLayoutElements));
699 }
700 return attributes;
701 }
702
703
704
705
706
707
708 private void parseLayout() throws IOException {
709 if (attributeLayoutElements == null) {
710 attributeLayoutElements = new ArrayList<>();
711 final StringReader stream = new StringReader(attributeLayout.getLayout());
712 AttributeLayoutElement e;
713 while ((e = readNextAttributeElement(stream)) != null) {
714 attributeLayoutElements.add(e);
715 }
716 resolveCalls();
717 }
718 }
719
720
721
722
723
724
725 @Override
726 public void read(final InputStream in) throws IOException, Pack200Exception {
727
728 }
729
730
731
732
733
734
735
736
737 private List<LayoutElement> readBody(final StringReader stream) throws IOException {
738 final List<LayoutElement> layoutElements = new ArrayList<>();
739 LayoutElement e;
740 while ((e = readNextLayoutElement(stream)) != null) {
741 layoutElements.add(e);
742 }
743 return layoutElements;
744 }
745
746 private AttributeLayoutElement readNextAttributeElement(final StringReader stream) throws IOException {
747 stream.mark(1);
748 final int next = stream.read();
749 if (next == -1) {
750 return null;
751 }
752 if (next == '[') {
753 return new Callable(readBody(getStreamUpToMatchingBracket(stream)));
754 }
755 stream.reset();
756 return readNextLayoutElement(stream);
757 }
758
759 private LayoutElement readNextLayoutElement(final StringReader stream) throws IOException {
760 final int nextChar = stream.read();
761 if (nextChar == -1) {
762 return null;
763 }
764 switch (nextChar) {
765
766 case 'B':
767 case 'H':
768 case 'I':
769 case 'V':
770 return new Integral(new String(new char[] { (char) nextChar }));
771 case 'S':
772 case 'F':
773 return new Integral(new String(new char[] { (char) nextChar, (char) stream.read() }));
774 case 'P':
775 stream.mark(1);
776 if (stream.read() != 'O') {
777 stream.reset();
778 return new Integral("P" + (char) stream.read());
779 }
780 return new Integral("PO" + (char) stream.read());
781 case 'O':
782 stream.mark(1);
783 if (stream.read() != 'S') {
784 stream.reset();
785 return new Integral("O" + (char) stream.read());
786 }
787 return new Integral("OS" + (char) stream.read());
788
789
790 case 'N':
791 final char uintType = (char) stream.read();
792 stream.read();
793 final String str = readUpToMatchingBracket(stream);
794 return new Replication("" + uintType, str);
795
796
797 case 'T':
798 String intType = "" + (char) stream.read();
799 if (intType.equals("S")) {
800 intType += (char) stream.read();
801 }
802 final List<UnionCase> unionCases = new ArrayList<>();
803 UnionCase c;
804 while ((c = readNextUnionCase(stream)) != null) {
805 unionCases.add(c);
806 }
807 stream.read();
808 stream.read();
809 stream.read();
810 List<LayoutElement> body = null;
811 stream.mark(1);
812 final char next = (char) stream.read();
813 if (next != ']') {
814 stream.reset();
815 body = readBody(getStreamUpToMatchingBracket(stream));
816 }
817 return new Union(intType, unionCases, body);
818
819
820 case '(':
821 final int number = readNumber(stream).intValue();
822 stream.read();
823 return new Call(number);
824
825 case 'K':
826 case 'R':
827 final StringBuilder string = new StringBuilder("").append((char) nextChar).append((char) stream.read());
828 final char nxt = (char) stream.read();
829 string.append(nxt);
830 if (nxt == 'N') {
831 string.append((char) stream.read());
832 }
833 return new Reference(string.toString());
834 }
835 return null;
836 }
837
838
839
840
841
842
843
844
845 private UnionCase readNextUnionCase(final StringReader stream) throws IOException {
846 stream.mark(2);
847 stream.read();
848 final int next = stream.read();
849 char ch = (char) next;
850 if (ch == ')' || next == -1) {
851 stream.reset();
852 return null;
853 }
854 stream.reset();
855 stream.read();
856 final List<Integer> tags = new ArrayList<>();
857 Integer nextTag;
858 do {
859 nextTag = readNumber(stream);
860 if (nextTag != null) {
861 tags.add(nextTag);
862 stream.read();
863 }
864 } while (nextTag != null);
865 stream.read();
866 stream.mark(1);
867 ch = (char) stream.read();
868 if (ch == ']') {
869 return new UnionCase(tags);
870 }
871 stream.reset();
872 return new UnionCase(tags, readBody(getStreamUpToMatchingBracket(stream)));
873 }
874
875
876
877
878
879
880
881
882 private Integer readNumber(final StringReader stream) throws IOException {
883 stream.mark(1);
884 final char first = (char) stream.read();
885 final boolean negative = first == '-';
886 if (!negative) {
887 stream.reset();
888 }
889 stream.mark(100);
890 int i;
891 int length = 0;
892 while ((i = stream.read()) != -1 && Character.isDigit((char) i)) {
893 length++;
894 }
895 stream.reset();
896 if (length == 0) {
897 return null;
898 }
899 final char[] digits = new char[length];
900 final int read = stream.read(digits);
901 if (read != digits.length) {
902 throw new IOException("Error reading from the input stream");
903 }
904 return ParsingUtils.parseIntValue((negative ? "-" : "") + new String(digits));
905 }
906
907
908
909
910
911
912
913
914 private String readUpToMatchingBracket(final StringReader stream) throws IOException {
915 final StringBuilder sb = new StringBuilder();
916 int foundBracket = -1;
917 while (foundBracket != 0) {
918 final int read = stream.read();
919 if (read == -1) {
920 break;
921 }
922 final char c = (char) read;
923 if (c == ']') {
924 foundBracket++;
925 }
926 if (c == '[') {
927 foundBracket--;
928 }
929 if (!(foundBracket == 0)) {
930 sb.append(c);
931 }
932 }
933 return sb.toString();
934 }
935
936
937
938
939 private void resolveCalls() {
940 int backwardsCalls = 0;
941 for (int i = 0; i < attributeLayoutElements.size(); i++) {
942 final AttributeLayoutElement element = attributeLayoutElements.get(i);
943 if (element instanceof Callable) {
944 final Callable callable = (Callable) element;
945 if (i == 0) {
946 callable.setFirstCallable(true);
947 }
948
949 for (final LayoutElement layoutElement : callable.body) {
950
951 backwardsCalls += resolveCallsForElement(i, callable, layoutElement);
952 }
953 }
954 }
955 backwardsCallCount = backwardsCalls;
956 }
957
958 private int resolveCallsForElement(final int i, final Callable currentCallable, final LayoutElement layoutElement) {
959 int backwardsCalls = 0;
960 if (layoutElement instanceof Call) {
961 final Call call = (Call) layoutElement;
962 int index = call.callableIndex;
963 if (index == 0) {
964 backwardsCalls++;
965 call.setCallable(currentCallable);
966 } else if (index > 0) {
967 for (int k = i + 1; k < attributeLayoutElements.size(); k++) {
968 final AttributeLayoutElement el = attributeLayoutElements.get(k);
969 if (el instanceof Callable) {
970 index--;
971 if (index == 0) {
972 call.setCallable((Callable) el);
973 break;
974 }
975 }
976 }
977 } else {
978 backwardsCalls++;
979 for (int k = i - 1; k >= 0; k--) {
980 final AttributeLayoutElement el = attributeLayoutElements.get(k);
981 if (el instanceof Callable) {
982 index++;
983 if (index == 0) {
984 call.setCallable((Callable) el);
985 break;
986 }
987 }
988 }
989 }
990 } else if (layoutElement instanceof Replication) {
991 final List<LayoutElement> children = ((Replication) layoutElement).layoutElements;
992 for (final LayoutElement child : children) {
993 backwardsCalls += resolveCallsForElement(i, currentCallable, child);
994 }
995 }
996 return backwardsCalls;
997 }
998
999
1000
1001
1002
1003
1004
1005
1006 public void setBackwardsCalls(final int[] backwardsCalls) throws IOException {
1007 int index = 0;
1008 parseLayout();
1009 for (final AttributeLayoutElement element : attributeLayoutElements) {
1010 if (element instanceof Callable && ((Callable) element).isBackwardsCallable()) {
1011 ((Callable) element).addCount(backwardsCalls[index]);
1012 index++;
1013 }
1014 }
1015 }
1016
1017 @Override
1018 public void unpack() throws IOException, Pack200Exception {
1019
1020 }
1021
1022 }