001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with this 004 * work for additional information regarding copyright ownership. The ASF 005 * licenses this file to You under the Apache License, Version 2.0 (the 006 * "License"); you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations under 015 * the License. 016 */ 017package org.apache.commons.compress.harmony.pack200; 018 019import java.io.ByteArrayOutputStream; 020import java.io.IOException; 021import java.io.OutputStream; 022import java.util.ArrayList; 023import java.util.List; 024 025import org.apache.commons.compress.harmony.pack200.Archive.PackingFile; 026import org.apache.commons.compress.harmony.pack200.Archive.SegmentUnit; 027import org.objectweb.asm.AnnotationVisitor; 028import org.objectweb.asm.Attribute; 029import org.objectweb.asm.ClassReader; 030import org.objectweb.asm.ClassVisitor; 031import org.objectweb.asm.FieldVisitor; 032import org.objectweb.asm.Label; 033import org.objectweb.asm.MethodVisitor; 034import org.objectweb.asm.Opcodes; 035import org.objectweb.asm.Type; 036 037 038/** 039 * A Pack200 archive consists of one or more Segments. 040 */ 041public class Segment extends ClassVisitor { 042 043 public class ArrayVisitor extends AnnotationVisitor { 044 045 private final int indexInCaseArrayN; 046 private final List<Integer> caseArrayN; 047 private final List<Object> values; 048 private final List<String> nameRU; 049 private final List<String> tags; 050 051 public ArrayVisitor(final List<Integer> caseArrayN, final List<String> tags, final List<String> nameRU, final List<Object> values) { 052 super(ASM_API); 053 054 this.caseArrayN = caseArrayN; 055 this.tags = tags; 056 this.nameRU = nameRU; 057 this.values = values; 058 this.indexInCaseArrayN = caseArrayN.size() - 1; 059 } 060 061 @Override 062 public void visit(String name, final Object value) { 063 final Integer numCases = caseArrayN.remove(indexInCaseArrayN); 064 caseArrayN.add(indexInCaseArrayN, Integer.valueOf(numCases.intValue() + 1)); 065 if (name == null) { 066 name = ""; 067 } 068 addValueAndTag(value, tags, values); 069 } 070 071 @Override 072 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) { 073 throw new UnsupportedOperationException("Not yet supported"); 074 } 075 076 @Override 077 public AnnotationVisitor visitArray(String name) { 078 tags.add("["); 079 if (name == null) { 080 name = ""; 081 } 082 nameRU.add(name); 083 caseArrayN.add(Integer.valueOf(0)); 084 return new ArrayVisitor(caseArrayN, tags, nameRU, values); 085 } 086 087 @Override 088 public void visitEnd() { 089 } 090 091 @Override 092 public void visitEnum(final String name, final String desc, final String value) { 093 final Integer numCases = caseArrayN.remove(caseArrayN.size() - 1); 094 caseArrayN.add(Integer.valueOf(numCases.intValue() + 1)); 095 tags.add("e"); 096 values.add(desc); 097 values.add(value); 098 } 099 } 100 101 /** 102 * Exception indicating that the class currently being visited contains an unknown attribute, which means that by 103 * default the class file needs to be passed through as-is in the file_bands rather than being packed with pack200. 104 */ 105 public static class PassException extends RuntimeException { 106 107 private static final long serialVersionUID = 1L; 108 109 } 110 111 /** 112 * SegmentAnnotationVisitor implements {@code AnnotationVisitor} to visit Annotations found in a class file. 113 */ 114 public class SegmentAnnotationVisitor extends AnnotationVisitor { 115 116 private int context = -1; 117 private int parameter = -1; 118 private String desc; 119 private boolean visible; 120 121 private final List<String> nameRU = new ArrayList<>(); 122 private final List<String> tags = new ArrayList<>(); // tags 123 private final List<Object> values = new ArrayList<>(); 124 private final List<Integer> caseArrayN = new ArrayList<>(); 125 private final List<String> nestTypeRS = new ArrayList<>(); 126 private final List<String> nestNameRU = new ArrayList<>(); 127 private final List<Integer> nestPairN = new ArrayList<>(); 128 129 public SegmentAnnotationVisitor(final int context) { 130 super(ASM_API); 131 this.context = context; 132 } 133 134 public SegmentAnnotationVisitor(final int context, final int parameter, final String desc, 135 final boolean visible) { 136 super(ASM_API); 137 this.context = context; 138 this.parameter = parameter; 139 this.desc = desc; 140 this.visible = visible; 141 } 142 143 public SegmentAnnotationVisitor(final int context, final String desc, final boolean visible) { 144 super(ASM_API); 145 this.context = context; 146 this.desc = desc; 147 this.visible = visible; 148 } 149 150 @Override 151 public void visit(String name, final Object value) { 152 if (name == null) { 153 name = ""; 154 } 155 nameRU.add(name); 156 addValueAndTag(value, tags, values); 157 } 158 159 @Override 160 public AnnotationVisitor visitAnnotation(String name, final String desc) { 161 tags.add("@"); 162 if (name == null) { 163 name = ""; 164 } 165 nameRU.add(name); 166 nestTypeRS.add(desc); 167 nestPairN.add(Integer.valueOf(0)); 168 return new AnnotationVisitor(context, av) { 169 @Override 170 public void visit(final String name, final Object value) { 171 final Integer numPairs = nestPairN.remove(nestPairN.size() - 1); 172 nestPairN.add(Integer.valueOf(numPairs.intValue() + 1)); 173 nestNameRU.add(name); 174 addValueAndTag(value, tags, values); 175 } 176 177 @Override 178 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) { 179 throw new UnsupportedOperationException("Not yet supported"); 180// return null; 181 } 182 183 @Override 184 public AnnotationVisitor visitArray(final String arg0) { 185 throw new UnsupportedOperationException("Not yet supported"); 186// return null; 187 } 188 189 @Override 190 public void visitEnd() { 191 } 192 193 @Override 194 public void visitEnum(final String name, final String desc, final String value) { 195 final Integer numPairs = nestPairN.remove(nestPairN.size() - 1); 196 nestPairN.add(Integer.valueOf(numPairs.intValue() + 1)); 197 tags.add("e"); 198 nestNameRU.add(name); 199 values.add(desc); 200 values.add(value); 201 } 202 }; 203 } 204 205 @Override 206 public AnnotationVisitor visitArray(String name) { 207 tags.add("["); 208 if (name == null) { 209 name = ""; 210 } 211 nameRU.add(name); 212 caseArrayN.add(Integer.valueOf(0)); 213 return new ArrayVisitor(caseArrayN, tags, nameRU, values); 214 } 215 216 @Override 217 public void visitEnd() { 218 if (desc == null) { 219 Segment.this.classBands.addAnnotationDefault(nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, 220 nestPairN); 221 } else if (parameter != -1) { 222 Segment.this.classBands.addParameterAnnotation(parameter, desc, visible, nameRU, tags, values, caseArrayN, 223 nestTypeRS, nestNameRU, nestPairN); 224 } else { 225 Segment.this.classBands.addAnnotation(context, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, 226 nestNameRU, nestPairN); 227 } 228 } 229 230 @Override 231 public void visitEnum(String name, final String desc, final String value) { 232 tags.add("e"); 233 if (name == null) { 234 name = ""; 235 } 236 nameRU.add(name); 237 values.add(desc); 238 values.add(value); 239 } 240 } 241 /** 242 * SegmentFieldVisitor implements {@code FieldVisitor} to visit the metadata relating to fields in a class 243 * file. 244 */ 245 public class SegmentFieldVisitor extends FieldVisitor { 246 247 public SegmentFieldVisitor() { 248 super(ASM_API); 249 } 250 251 @Override 252 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { 253 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_FIELD, desc, visible); 254 } 255 256 @Override 257 public void visitAttribute(final Attribute attribute) { 258 if (attribute.isUnknown()) { 259 final String action = options.getUnknownAttributeAction(); 260 if (action.equals(PackingOptions.PASS)) { 261 passCurrentClass(); 262 } else if (action.equals(PackingOptions.ERROR)) { 263 throw new Error("Unknown attribute encountered"); 264 } // else skip 265 } else if (attribute instanceof NewAttribute) { 266 final NewAttribute newAttribute = (NewAttribute) attribute; 267 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_FIELD)) { 268 final String action = options.getUnknownFieldAttributeAction(newAttribute.type); 269 if (action.equals(PackingOptions.PASS)) { 270 passCurrentClass(); 271 } else if (action.equals(PackingOptions.ERROR)) { 272 throw new Error("Unknown attribute encountered"); 273 } // else skip 274 } 275 classBands.addFieldAttribute(newAttribute); 276 } else { 277 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type); 278 } 279 } 280 281 @Override 282 public void visitEnd() { 283 } 284 } 285 /** 286 * This class implements MethodVisitor to visit the contents and metadata related to methods in a class file. 287 * 288 * It delegates to BcBands for bytecode related visits and to ClassBands for everything else. 289 */ 290 public class SegmentMethodVisitor extends MethodVisitor { 291 292 public SegmentMethodVisitor() { 293 super(ASM_API); 294 } 295 296 @Override 297 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { 298 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, desc, visible); 299 } 300 301 @Override 302 public AnnotationVisitor visitAnnotationDefault() { 303 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD); 304 } 305 306 @Override 307 public void visitAttribute(final Attribute attribute) { 308 if (attribute.isUnknown()) { 309 final String action = options.getUnknownAttributeAction(); 310 if (action.equals(PackingOptions.PASS)) { 311 passCurrentClass(); 312 } else if (action.equals(PackingOptions.ERROR)) { 313 throw new Error("Unknown attribute encountered"); 314 } // else skip 315 } else if (attribute instanceof NewAttribute) { 316 final NewAttribute newAttribute = (NewAttribute) attribute; 317 if (attribute.isCodeAttribute()) { 318 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CODE)) { 319 final String action = options.getUnknownCodeAttributeAction(newAttribute.type); 320 if (action.equals(PackingOptions.PASS)) { 321 passCurrentClass(); 322 } else if (action.equals(PackingOptions.ERROR)) { 323 throw new Error("Unknown attribute encountered"); 324 } // else skip 325 } 326 classBands.addCodeAttribute(newAttribute); 327 } else { 328 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_METHOD)) { 329 final String action = options.getUnknownMethodAttributeAction(newAttribute.type); 330 if (action.equals(PackingOptions.PASS)) { 331 passCurrentClass(); 332 } else if (action.equals(PackingOptions.ERROR)) { 333 throw new Error("Unknown attribute encountered"); 334 } // else skip 335 } 336 classBands.addMethodAttribute(newAttribute); 337 } 338 } else { 339 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type); 340 } 341 } 342 343 @Override 344 public void visitCode() { 345 classBands.addCode(); 346 } 347 348 @Override 349 public void visitEnd() { 350 classBands.endOfMethod(); 351 bcBands.visitEnd(); 352 } 353 354 @Override 355 public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { 356 bcBands.visitFieldInsn(opcode, owner, name, desc); 357 } 358 359 @Override 360 public void visitFrame(final int arg0, final int arg1, final Object[] arg2, final int arg3, 361 final Object[] arg4) { 362 // TODO: Java 6 - implement support for this 363 364 } 365 366 @Override 367 public void visitIincInsn(final int var, final int increment) { 368 bcBands.visitIincInsn(var, increment); 369 } 370 371 @Override 372 public void visitInsn(final int opcode) { 373 bcBands.visitInsn(opcode); 374 } 375 376 @Override 377 public void visitIntInsn(final int opcode, final int operand) { 378 bcBands.visitIntInsn(opcode, operand); 379 } 380 381 @Override 382 public void visitJumpInsn(final int opcode, final Label label) { 383 bcBands.visitJumpInsn(opcode, label); 384 } 385 386 @Override 387 public void visitLabel(final Label label) { 388 bcBands.visitLabel(label); 389 } 390 391 @Override 392 public void visitLdcInsn(final Object cst) { 393 bcBands.visitLdcInsn(cst); 394 } 395 396 @Override 397 public void visitLineNumber(final int line, final Label start) { 398 if (!stripDebug) { 399 classBands.addLineNumber(line, start); 400 } 401 } 402 403 @Override 404 public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, 405 final Label end, final int index) { 406 if (!stripDebug) { 407 classBands.addLocalVariable(name, desc, signature, start, end, index); 408 } 409 } 410 411 @Override 412 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { 413 bcBands.visitLookupSwitchInsn(dflt, keys, labels); 414 } 415 416 @Override 417 public void visitMaxs(final int maxStack, final int maxLocals) { 418 classBands.addMaxStack(maxStack, maxLocals); 419 } 420 421 @Override 422 public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { 423 bcBands.visitMethodInsn(opcode, owner, name, desc); 424 } 425 426 @Override 427 public void visitMultiANewArrayInsn(final String desc, final int dimensions) { 428 bcBands.visitMultiANewArrayInsn(desc, dimensions); 429 } 430 431 @Override 432 public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, 433 final boolean visible) { 434 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, parameter, desc, visible); 435 } 436 437 @Override 438 public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) { 439 bcBands.visitTableSwitchInsn(min, max, dflt, labels); 440 } 441 442 @Override 443 public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) { 444 classBands.addHandler(start, end, handler, type); 445 } 446 447 @Override 448 public void visitTypeInsn(final int opcode, final String type) { 449 bcBands.visitTypeInsn(opcode, type); 450 } 451 452 @Override 453 public void visitVarInsn(final int opcode, final int var) { 454 bcBands.visitVarInsn(opcode, var); 455 } 456 457 } 458 /** See https://asm.ow2.io/javadoc/org/objectweb/asm/Opcodes.html#ASM4 */ 459 public static int ASM_API = Opcodes.ASM4; 460 private SegmentHeader segmentHeader; 461 private CpBands cpBands; 462 private AttributeDefinitionBands attributeDefinitionBands; 463 464 private IcBands icBands; 465 private ClassBands classBands; 466 private BcBands bcBands; 467 private FileBands fileBands; 468 private final SegmentFieldVisitor fieldVisitor = new SegmentFieldVisitor(); 469 private final SegmentMethodVisitor methodVisitor = new SegmentMethodVisitor(); 470 471 private Pack200ClassReader currentClassReader; 472 473 private PackingOptions options; 474 475 private boolean stripDebug; 476 477 private Attribute[] nonStandardAttributePrototypes; 478 479 public Segment() { 480 super(ASM_API); 481 } 482 483 // helper method for annotation visitors 484 private void addValueAndTag(final Object value, final List<String> tags, final List<Object> values) { 485 if (value instanceof Integer) { 486 tags.add("I"); 487 values.add(value); 488 } else if (value instanceof Double) { 489 tags.add("D"); 490 values.add(value); 491 } else if (value instanceof Float) { 492 tags.add("F"); 493 values.add(value); 494 } else if (value instanceof Long) { 495 tags.add("J"); 496 values.add(value); 497 } else if (value instanceof Byte) { 498 tags.add("B"); 499 values.add(Integer.valueOf(((Byte) value).intValue())); 500 } else if (value instanceof Character) { 501 tags.add("C"); 502 values.add(Integer.valueOf(((Character) value).charValue())); 503 } else if (value instanceof Short) { 504 tags.add("S"); 505 values.add(Integer.valueOf(((Short) value).intValue())); 506 } else if (value instanceof Boolean) { 507 tags.add("Z"); 508 values.add(Integer.valueOf(((Boolean) value).booleanValue() ? 1 : 0)); 509 } else if (value instanceof String) { 510 tags.add("s"); 511 values.add(value); 512 } else if (value instanceof Type) { 513 tags.add("c"); 514 values.add(((Type) value).toString()); 515 } 516 } 517 518 public AttributeDefinitionBands getAttrBands() { 519 return attributeDefinitionBands; 520 } 521 522 public ClassBands getClassBands() { 523 return classBands; 524 } 525 526 public CpBands getCpBands() { 527 return cpBands; 528 } 529 530 public Pack200ClassReader getCurrentClassReader() { 531 return currentClassReader; 532 } 533 534 public IcBands getIcBands() { 535 return icBands; 536 } 537 538 public SegmentHeader getSegmentHeader() { 539 return segmentHeader; 540 } 541 542 public boolean lastConstantHadWideIndex() { 543 return currentClassReader.lastConstantHadWideIndex(); 544 } 545 546 /** 547 * The main method on Segment. Reads in all the class files, packs them and then writes the packed segment out to 548 * the given OutputStream. 549 * 550 * @param segmentUnit TODO 551 * @param out the OutputStream to write the packed Segment to 552 * @param options packing options 553 * @throws IOException If an I/O error occurs. 554 * @throws Pack200Exception TODO 555 */ 556 public void pack(final SegmentUnit segmentUnit, final OutputStream out, final PackingOptions options) 557 throws IOException, Pack200Exception { 558 this.options = options; 559 this.stripDebug = options.isStripDebug(); 560 final int effort = options.getEffort(); 561 nonStandardAttributePrototypes = options.getUnknownAttributePrototypes(); 562 563 PackingUtils.log("Start to pack a new segment with " + segmentUnit.fileListSize() + " files including " 564 + segmentUnit.classListSize() + " classes"); 565 566 PackingUtils.log("Initialize a header for the segment"); 567 segmentHeader = new SegmentHeader(); 568 segmentHeader.setFile_count(segmentUnit.fileListSize()); 569 segmentHeader.setHave_all_code_flags(!stripDebug); 570 if (!options.isKeepDeflateHint()) { 571 segmentHeader.setDeflate_hint("true".equals(options.getDeflateHint())); 572 } 573 574 PackingUtils.log("Setup constant pool bands for the segment"); 575 cpBands = new CpBands(this, effort); 576 577 PackingUtils.log("Setup attribute definition bands for the segment"); 578 attributeDefinitionBands = new AttributeDefinitionBands(this, effort, nonStandardAttributePrototypes); 579 580 PackingUtils.log("Setup internal class bands for the segment"); 581 icBands = new IcBands(segmentHeader, cpBands, effort); 582 583 PackingUtils.log("Setup class bands for the segment"); 584 classBands = new ClassBands(this, segmentUnit.classListSize(), effort, stripDebug); 585 586 PackingUtils.log("Setup byte code bands for the segment"); 587 bcBands = new BcBands(cpBands, this, effort); 588 589 PackingUtils.log("Setup file bands for the segment"); 590 fileBands = new FileBands(cpBands, segmentHeader, options, segmentUnit, effort); 591 592 processClasses(segmentUnit, nonStandardAttributePrototypes); 593 594 cpBands.finaliseBands(); 595 attributeDefinitionBands.finaliseBands(); 596 icBands.finaliseBands(); 597 classBands.finaliseBands(); 598 bcBands.finaliseBands(); 599 fileBands.finaliseBands(); 600 601 // Using a temporary stream because we have to pack the other bands 602 // before segmentHeader because the band_headers band is only created 603 // when the other bands are packed, but comes before them in the packed 604 // file. 605 final ByteArrayOutputStream bandsOutputStream = new ByteArrayOutputStream(); 606 607 PackingUtils.log("Packing..."); 608 final int finalNumberOfClasses = classBands.numClassesProcessed(); 609 segmentHeader.setClass_count(finalNumberOfClasses); 610 cpBands.pack(bandsOutputStream); 611 if (finalNumberOfClasses > 0) { 612 attributeDefinitionBands.pack(bandsOutputStream); 613 icBands.pack(bandsOutputStream); 614 classBands.pack(bandsOutputStream); 615 bcBands.pack(bandsOutputStream); 616 } 617 fileBands.pack(bandsOutputStream); 618 619 final ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream(); 620 segmentHeader.pack(headerOutputStream); 621 622 headerOutputStream.writeTo(out); 623 bandsOutputStream.writeTo(out); 624 625 segmentUnit.addPackedByteAmount(headerOutputStream.size()); 626 segmentUnit.addPackedByteAmount(bandsOutputStream.size()); 627 628 PackingUtils.log("Wrote total of " + segmentUnit.getPackedByteAmount() + " bytes"); 629 PackingUtils.log("Transmitted " + segmentUnit.fileListSize() + " files of " + segmentUnit.getByteAmount() 630 + " input bytes in a segment of " + segmentUnit.getPackedByteAmount() + " bytes"); 631 } 632 633 private void passCurrentClass() { 634 throw new PassException(); 635 } 636 637 private void processClasses(final SegmentUnit segmentUnit, final Attribute[] attributes) throws Pack200Exception { 638 segmentHeader.setClass_count(segmentUnit.classListSize()); 639 for (final Pack200ClassReader classReader : segmentUnit.getClassList()) { 640 currentClassReader = classReader; 641 int flags = 0; 642 if (stripDebug) { 643 flags |= ClassReader.SKIP_DEBUG; 644 } 645 try { 646 classReader.accept(this, attributes, flags); 647 } catch (final PassException pe) { 648 // Pass this class through as-is rather than packing it 649 // TODO: probably need to deal with any inner classes 650 classBands.removeCurrentClass(); 651 final String name = classReader.getFileName(); 652 options.addPassFile(name); 653 cpBands.addCPUtf8(name); 654 boolean found = false; 655 for (final PackingFile file : segmentUnit.getFileList()) { 656 if (file.getName().equals(name)) { 657 found = true; 658 file.setContents(classReader.b); 659 break; 660 } 661 } 662 if (!found) { 663 throw new Pack200Exception("Error passing file " + name); 664 } 665 } 666 } 667 } 668 669 @Override 670 public void visit(final int version, final int access, final String name, final String signature, 671 final String superName, final String[] interfaces) { 672 bcBands.setCurrentClass(name, superName); 673 segmentHeader.addMajorVersion(version); 674 classBands.addClass(version, access, name, signature, superName, interfaces); 675 } 676 677 @Override 678 public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { 679 return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_CLASS, desc, visible); 680 } 681 682 @Override 683 public void visitAttribute(final Attribute attribute) { 684 if (attribute.isUnknown()) { 685 final String action = options.getUnknownAttributeAction(); 686 if (action.equals(PackingOptions.PASS)) { 687 passCurrentClass(); 688 } else if (action.equals(PackingOptions.ERROR)) { 689 throw new Error("Unknown attribute encountered"); 690 } // else skip 691 } else if (attribute instanceof NewAttribute) { 692 final NewAttribute newAttribute = (NewAttribute) attribute; 693 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CLASS)) { 694 final String action = options.getUnknownClassAttributeAction(newAttribute.type); 695 if (action.equals(PackingOptions.PASS)) { 696 passCurrentClass(); 697 } else if (action.equals(PackingOptions.ERROR)) { 698 throw new Error("Unknown attribute encountered"); 699 } // else skip 700 } 701 classBands.addClassAttribute(newAttribute); 702 } else { 703 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type); 704 } 705 } 706 707 @Override 708 public void visitEnd() { 709 classBands.endOfClass(); 710 } 711 712 @Override 713 public FieldVisitor visitField(final int flags, final String name, final String desc, final String signature, 714 final Object value) { 715 classBands.addField(flags, name, desc, signature, value); 716 return fieldVisitor; 717 } 718 719 @Override 720 public void visitInnerClass(final String name, final String outerName, final String innerName, final int flags) { 721 icBands.addInnerClass(name, outerName, innerName, flags); 722 } 723 724 @Override 725 public MethodVisitor visitMethod(final int flags, final String name, final String desc, final String signature, 726 final String[] exceptions) { 727 classBands.addMethod(flags, name, desc, signature, exceptions); 728 return methodVisitor; 729 } 730 731 @Override 732 public void visitOuterClass(final String owner, final String name, final String desc) { 733 classBands.addEnclosingMethod(owner, name, desc); 734 735 } 736 737 @Override 738 public void visitSource(final String source, final String debug) { 739 if (!stripDebug) { 740 classBands.addSourceFile(source); 741 } 742 } 743}