1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.harmony.pack200;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.OutputStream;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.apache.commons.compress.harmony.pack200.Archive.PackingFile;
26 import org.apache.commons.compress.harmony.pack200.Archive.SegmentUnit;
27 import org.objectweb.asm.AnnotationVisitor;
28 import org.objectweb.asm.Attribute;
29 import org.objectweb.asm.ClassReader;
30 import org.objectweb.asm.ClassVisitor;
31 import org.objectweb.asm.FieldVisitor;
32 import org.objectweb.asm.Label;
33 import org.objectweb.asm.MethodVisitor;
34 import org.objectweb.asm.Opcodes;
35 import org.objectweb.asm.Type;
36
37
38
39
40 public class Segment extends ClassVisitor {
41
42 public class ArrayVisitor extends AnnotationVisitor {
43
44 private final int indexInCaseArrayN;
45 private final List<Integer> caseArrayN;
46 private final List<Object> values;
47 private final List<String> nameRU;
48 private final List<String> tags;
49
50 public ArrayVisitor(final List<Integer> caseArrayN, final List<String> tags, final List<String> nameRU, final List<Object> values) {
51 super(ASM_API);
52
53 this.caseArrayN = caseArrayN;
54 this.tags = tags;
55 this.nameRU = nameRU;
56 this.values = values;
57 this.indexInCaseArrayN = caseArrayN.size() - 1;
58 }
59
60 @Override
61 public void visit(String name, final Object value) {
62 final Integer numCases = caseArrayN.remove(indexInCaseArrayN);
63 caseArrayN.add(indexInCaseArrayN, Integer.valueOf(numCases.intValue() + 1));
64 if (name == null) {
65 name = "";
66 }
67 addValueAndTag(value, tags, values);
68 }
69
70 @Override
71 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) {
72 throw new UnsupportedOperationException("Not yet supported");
73 }
74
75 @Override
76 public AnnotationVisitor visitArray(String name) {
77 tags.add("[");
78 if (name == null) {
79 name = "";
80 }
81 nameRU.add(name);
82 caseArrayN.add(Integer.valueOf(0));
83 return new ArrayVisitor(caseArrayN, tags, nameRU, values);
84 }
85
86 @Override
87 public void visitEnd() {
88 }
89
90 @Override
91 public void visitEnum(final String name, final String desc, final String value) {
92 final Integer numCases = caseArrayN.remove(caseArrayN.size() - 1);
93 caseArrayN.add(Integer.valueOf(numCases.intValue() + 1));
94 tags.add("e");
95 values.add(desc);
96 values.add(value);
97 }
98 }
99
100
101
102
103
104 public static class PassException extends RuntimeException {
105
106 private static final long serialVersionUID = 1L;
107
108 }
109
110
111
112
113 public class SegmentAnnotationVisitor extends AnnotationVisitor {
114
115 private int context = -1;
116 private int parameter = -1;
117 private String desc;
118 private boolean visible;
119
120 private final List<String> nameRU = new ArrayList<>();
121 private final List<String> tags = new ArrayList<>();
122 private final List<Object> values = new ArrayList<>();
123 private final List<Integer> caseArrayN = new ArrayList<>();
124 private final List<String> nestTypeRS = new ArrayList<>();
125 private final List<String> nestNameRU = new ArrayList<>();
126 private final List<Integer> nestPairN = new ArrayList<>();
127
128 public SegmentAnnotationVisitor(final int context) {
129 super(ASM_API);
130 this.context = context;
131 }
132
133 public SegmentAnnotationVisitor(final int context, final int parameter, final String desc, final boolean visible) {
134 super(ASM_API);
135 this.context = context;
136 this.parameter = parameter;
137 this.desc = desc;
138 this.visible = visible;
139 }
140
141 public SegmentAnnotationVisitor(final int context, final String desc, final boolean visible) {
142 super(ASM_API);
143 this.context = context;
144 this.desc = desc;
145 this.visible = visible;
146 }
147
148 @Override
149 public void visit(String name, final Object value) {
150 if (name == null) {
151 name = "";
152 }
153 nameRU.add(name);
154 addValueAndTag(value, tags, values);
155 }
156
157 @Override
158 public AnnotationVisitor visitAnnotation(String name, final String desc) {
159 tags.add("@");
160 if (name == null) {
161 name = "";
162 }
163 nameRU.add(name);
164 nestTypeRS.add(desc);
165 nestPairN.add(Integer.valueOf(0));
166 return new AnnotationVisitor(context, av) {
167 @Override
168 public void visit(final String name, final Object value) {
169 final Integer numPairs = nestPairN.remove(nestPairN.size() - 1);
170 nestPairN.add(Integer.valueOf(numPairs.intValue() + 1));
171 nestNameRU.add(name);
172 addValueAndTag(value, tags, values);
173 }
174
175 @Override
176 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) {
177 throw new UnsupportedOperationException("Not yet supported");
178
179 }
180
181 @Override
182 public AnnotationVisitor visitArray(final String arg0) {
183 throw new UnsupportedOperationException("Not yet supported");
184
185 }
186
187 @Override
188 public void visitEnd() {
189 }
190
191 @Override
192 public void visitEnum(final String name, final String desc, final String value) {
193 final Integer numPairs = nestPairN.remove(nestPairN.size() - 1);
194 nestPairN.add(Integer.valueOf(numPairs.intValue() + 1));
195 tags.add("e");
196 nestNameRU.add(name);
197 values.add(desc);
198 values.add(value);
199 }
200 };
201 }
202
203 @Override
204 public AnnotationVisitor visitArray(String name) {
205 tags.add("[");
206 if (name == null) {
207 name = "";
208 }
209 nameRU.add(name);
210 caseArrayN.add(Integer.valueOf(0));
211 return new ArrayVisitor(caseArrayN, tags, nameRU, values);
212 }
213
214 @Override
215 public void visitEnd() {
216 if (desc == null) {
217 Segment.this.classBands.addAnnotationDefault(nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
218 } else if (parameter != -1) {
219 Segment.this.classBands.addParameterAnnotation(parameter, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
220 } else {
221 Segment.this.classBands.addAnnotation(context, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
222 }
223 }
224
225 @Override
226 public void visitEnum(String name, final String desc, final String value) {
227 tags.add("e");
228 if (name == null) {
229 name = "";
230 }
231 nameRU.add(name);
232 values.add(desc);
233 values.add(value);
234 }
235 }
236
237
238
239
240 public class SegmentFieldVisitor extends FieldVisitor {
241
242 public SegmentFieldVisitor() {
243 super(ASM_API);
244 }
245
246 @Override
247 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
248 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_FIELD, desc, visible);
249 }
250
251 @Override
252 public void visitAttribute(final Attribute attribute) {
253 if (attribute.isUnknown()) {
254 final String action = options.getUnknownAttributeAction();
255 if (action.equals(PackingOptions.PASS)) {
256 passCurrentClass();
257 } else if (action.equals(PackingOptions.ERROR)) {
258 throw new Error("Unknown attribute encountered");
259 }
260 } else if (attribute instanceof NewAttribute) {
261 final NewAttribute newAttribute = (NewAttribute) attribute;
262 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_FIELD)) {
263 final String action = options.getUnknownFieldAttributeAction(newAttribute.type);
264 if (action.equals(PackingOptions.PASS)) {
265 passCurrentClass();
266 } else if (action.equals(PackingOptions.ERROR)) {
267 throw new Error("Unknown attribute encountered");
268 }
269 }
270 classBands.addFieldAttribute(newAttribute);
271 } else {
272 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
273 }
274 }
275
276 @Override
277 public void visitEnd() {
278 }
279 }
280
281
282
283
284
285
286 public class SegmentMethodVisitor extends MethodVisitor {
287
288 public SegmentMethodVisitor() {
289 super(ASM_API);
290 }
291
292 @Override
293 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
294 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, desc, visible);
295 }
296
297 @Override
298 public AnnotationVisitor visitAnnotationDefault() {
299 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD);
300 }
301
302 @Override
303 public void visitAttribute(final Attribute attribute) {
304 if (attribute.isUnknown()) {
305 final String action = options.getUnknownAttributeAction();
306 if (action.equals(PackingOptions.PASS)) {
307 passCurrentClass();
308 } else if (action.equals(PackingOptions.ERROR)) {
309 throw new Error("Unknown attribute encountered");
310 }
311 } else if (attribute instanceof NewAttribute) {
312 final NewAttribute newAttribute = (NewAttribute) attribute;
313 if (attribute.isCodeAttribute()) {
314 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CODE)) {
315 final String action = options.getUnknownCodeAttributeAction(newAttribute.type);
316 if (action.equals(PackingOptions.PASS)) {
317 passCurrentClass();
318 } else if (action.equals(PackingOptions.ERROR)) {
319 throw new Error("Unknown attribute encountered");
320 }
321 }
322 classBands.addCodeAttribute(newAttribute);
323 } else {
324 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_METHOD)) {
325 final String action = options.getUnknownMethodAttributeAction(newAttribute.type);
326 if (action.equals(PackingOptions.PASS)) {
327 passCurrentClass();
328 } else if (action.equals(PackingOptions.ERROR)) {
329 throw new Error("Unknown attribute encountered");
330 }
331 }
332 classBands.addMethodAttribute(newAttribute);
333 }
334 } else {
335 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
336 }
337 }
338
339 @Override
340 public void visitCode() {
341 classBands.addCode();
342 }
343
344 @Override
345 public void visitEnd() {
346 classBands.endOfMethod();
347 bcBands.visitEnd();
348 }
349
350 @Override
351 public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
352 bcBands.visitFieldInsn(opcode, owner, name, desc);
353 }
354
355 @Override
356 public void visitFrame(final int arg0, final int arg1, final Object[] arg2, final int arg3, final Object[] arg4) {
357
358
359 }
360
361 @Override
362 public void visitIincInsn(final int var, final int increment) {
363 bcBands.visitIincInsn(var, increment);
364 }
365
366 @Override
367 public void visitInsn(final int opcode) {
368 bcBands.visitInsn(opcode);
369 }
370
371 @Override
372 public void visitIntInsn(final int opcode, final int operand) {
373 bcBands.visitIntInsn(opcode, operand);
374 }
375
376 @Override
377 public void visitJumpInsn(final int opcode, final Label label) {
378 bcBands.visitJumpInsn(opcode, label);
379 }
380
381 @Override
382 public void visitLabel(final Label label) {
383 bcBands.visitLabel(label);
384 }
385
386 @Override
387 public void visitLdcInsn(final Object cst) {
388 bcBands.visitLdcInsn(cst);
389 }
390
391 @Override
392 public void visitLineNumber(final int line, final Label start) {
393 if (!stripDebug) {
394 classBands.addLineNumber(line, start);
395 }
396 }
397
398 @Override
399 public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index) {
400 if (!stripDebug) {
401 classBands.addLocalVariable(name, desc, signature, start, end, index);
402 }
403 }
404
405 @Override
406 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
407 bcBands.visitLookupSwitchInsn(dflt, keys, labels);
408 }
409
410 @Override
411 public void visitMaxs(final int maxStack, final int maxLocals) {
412 classBands.addMaxStack(maxStack, maxLocals);
413 }
414
415 @Override
416 public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
417 bcBands.visitMethodInsn(opcode, owner, name, desc);
418 }
419
420 @Override
421 public void visitMultiANewArrayInsn(final String desc, final int dimensions) {
422 bcBands.visitMultiANewArrayInsn(desc, dimensions);
423 }
424
425 @Override
426 public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, final boolean visible) {
427 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, parameter, desc, visible);
428 }
429
430 @Override
431 public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) {
432 bcBands.visitTableSwitchInsn(min, max, dflt, labels);
433 }
434
435 @Override
436 public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) {
437 classBands.addHandler(start, end, handler, type);
438 }
439
440 @Override
441 public void visitTypeInsn(final int opcode, final String type) {
442 bcBands.visitTypeInsn(opcode, type);
443 }
444
445 @Override
446 public void visitVarInsn(final int opcode, final int var) {
447 bcBands.visitVarInsn(opcode, var);
448 }
449
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549 public void pack(final SegmentUnit segmentUnit, final OutputStream out, final PackingOptions options) throws IOException, Pack200Exception {
550 this.options = options;
551 this.stripDebug = options.isStripDebug();
552 final int effort = options.getEffort();
553 nonStandardAttributePrototypes = options.getUnknownAttributePrototypes();
554
555 PackingUtils.log("Start to pack a new segment with " + segmentUnit.fileListSize() + " files including " + segmentUnit.classListSize() + " classes");
556
557 PackingUtils.log("Initialize a header for the segment");
558 segmentHeader = new SegmentHeader();
559 segmentHeader.setFile_count(segmentUnit.fileListSize());
560 segmentHeader.setHave_all_code_flags(!stripDebug);
561 if (!options.isKeepDeflateHint()) {
562 segmentHeader.setDeflate_hint(Boolean.parseBoolean(options.getDeflateHint()));
563 }
564
565 PackingUtils.log("Setup constant pool bands for the segment");
566 cpBands = new CpBands(this, effort);
567
568 PackingUtils.log("Setup attribute definition bands for the segment");
569 attributeDefinitionBands = new AttributeDefinitionBands(this, effort, nonStandardAttributePrototypes);
570
571 PackingUtils.log("Setup internal class bands for the segment");
572 icBands = new IcBands(segmentHeader, cpBands, effort);
573
574 PackingUtils.log("Setup class bands for the segment");
575 classBands = new ClassBands(this, segmentUnit.classListSize(), effort, stripDebug);
576
577 PackingUtils.log("Setup byte code bands for the segment");
578 bcBands = new BcBands(cpBands, this, effort);
579
580 PackingUtils.log("Setup file bands for the segment");
581 fileBands = new FileBands(cpBands, segmentHeader, options, segmentUnit, effort);
582
583 processClasses(segmentUnit, nonStandardAttributePrototypes);
584
585 cpBands.finaliseBands();
586 attributeDefinitionBands.finaliseBands();
587 icBands.finaliseBands();
588 classBands.finaliseBands();
589 bcBands.finaliseBands();
590 fileBands.finaliseBands();
591
592
593
594
595
596 final ByteArrayOutputStream bandsOutputStream = new ByteArrayOutputStream();
597
598 PackingUtils.log("Packing...");
599 final int finalNumberOfClasses = classBands.numClassesProcessed();
600 segmentHeader.setClass_count(finalNumberOfClasses);
601 cpBands.pack(bandsOutputStream);
602 if (finalNumberOfClasses > 0) {
603 attributeDefinitionBands.pack(bandsOutputStream);
604 icBands.pack(bandsOutputStream);
605 classBands.pack(bandsOutputStream);
606 bcBands.pack(bandsOutputStream);
607 }
608 fileBands.pack(bandsOutputStream);
609
610 final ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream();
611 segmentHeader.pack(headerOutputStream);
612
613 headerOutputStream.writeTo(out);
614 bandsOutputStream.writeTo(out);
615
616 segmentUnit.addPackedByteAmount(headerOutputStream.size());
617 segmentUnit.addPackedByteAmount(bandsOutputStream.size());
618
619 PackingUtils.log("Wrote total of " + segmentUnit.getPackedByteAmount() + " bytes");
620 PackingUtils.log("Transmitted " + segmentUnit.fileListSize() + " files of " + segmentUnit.getByteAmount() + " input bytes in a segment of "
621 + segmentUnit.getPackedByteAmount() + " bytes");
622 }
623
624 private void passCurrentClass() {
625 throw new PassException();
626 }
627
628 private void processClasses(final SegmentUnit segmentUnit, final Attribute[] attributes) throws Pack200Exception {
629 segmentHeader.setClass_count(segmentUnit.classListSize());
630 for (final Pack200ClassReader classReader : segmentUnit.getClassList()) {
631 currentClassReader = classReader;
632 int flags = 0;
633 if (stripDebug) {
634 flags |= ClassReader.SKIP_DEBUG;
635 }
636 try {
637 classReader.accept(this, attributes, flags);
638 } catch (final PassException pe) {
639
640
641 classBands.removeCurrentClass();
642 final String name = classReader.getFileName();
643 options.addPassFile(name);
644 cpBands.addCPUtf8(name);
645 boolean found = false;
646 for (final PackingFile file : segmentUnit.getFileList()) {
647 if (file.getName().equals(name)) {
648 found = true;
649 file.setContents(classReader.b);
650 break;
651 }
652 }
653 if (!found) {
654 throw new Pack200Exception("Error passing file " + name);
655 }
656 }
657 }
658 }
659
660 @Override
661 public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
662 bcBands.setCurrentClass(name, superName);
663 segmentHeader.addMajorVersion(version);
664 classBands.addClass(version, access, name, signature, superName, interfaces);
665 }
666
667 @Override
668 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
669 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_CLASS, desc, visible);
670 }
671
672 @Override
673 public void visitAttribute(final Attribute attribute) {
674 if (attribute.isUnknown()) {
675 final String action = options.getUnknownAttributeAction();
676 if (action.equals(PackingOptions.PASS)) {
677 passCurrentClass();
678 } else if (action.equals(PackingOptions.ERROR)) {
679 throw new Error("Unknown attribute encountered");
680 }
681 } else if (attribute instanceof NewAttribute) {
682 final NewAttribute newAttribute = (NewAttribute) attribute;
683 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CLASS)) {
684 final String action = options.getUnknownClassAttributeAction(newAttribute.type);
685 if (action.equals(PackingOptions.PASS)) {
686 passCurrentClass();
687 } else if (action.equals(PackingOptions.ERROR)) {
688 throw new Error("Unknown attribute encountered");
689 }
690 }
691 classBands.addClassAttribute(newAttribute);
692 } else {
693 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
694 }
695 }
696
697 @Override
698 public void visitEnd() {
699 classBands.endOfClass();
700 }
701
702 @Override
703 public FieldVisitor visitField(final int flags, final String name, final String desc, final String signature, final Object value) {
704 classBands.addField(flags, name, desc, signature, value);
705 return fieldVisitor;
706 }
707
708 @Override
709 public void visitInnerClass(final String name, final String outerName, final String innerName, final int flags) {
710 icBands.addInnerClass(name, outerName, innerName, flags);
711 }
712
713 @Override
714 public MethodVisitor visitMethod(final int flags, final String name, final String desc, final String signature, final String[] exceptions) {
715 classBands.addMethod(flags, name, desc, signature, exceptions);
716 return methodVisitor;
717 }
718
719 @Override
720 public void visitOuterClass(final String owner, final String name, final String desc) {
721 classBands.addEnclosingMethod(owner, name, desc);
722
723 }
724
725 @Override
726 public void visitSource(final String source, final String debug) {
727 if (!stripDebug) {
728 classBands.addSourceFile(source);
729 }
730 }
731 }