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 * A Pack200 archive consists of one or more Segments. 039 */ 040public class Segment extends ClassVisitor { 041 042 public class ArrayVisitor extends AnnotationVisitor { 043 044 private final int indexInCaseArrayN; 045 private final List<Integer> caseArrayN; 046 private final List<Object> values; 047 private final List<String> nameRU; 048 private final List<String> tags; 049 050 public ArrayVisitor(final List<Integer> caseArrayN, final List<String> tags, final List<String> nameRU, final List<Object> values) { 051 super(ASM_API); 052 053 this.caseArrayN = caseArrayN; 054 this.tags = tags; 055 this.nameRU = nameRU; 056 this.values = values; 057 this.indexInCaseArrayN = caseArrayN.size() - 1; 058 } 059 060 @Override 061 public void visit(String name, final Object value) { 062 final Integer numCases = caseArrayN.remove(indexInCaseArrayN); 063 caseArrayN.add(indexInCaseArrayN, Integer.valueOf(numCases.intValue() + 1)); 064 if (name == null) { 065 name = ""; 066 } 067 addValueAndTag(value, tags, values); 068 } 069 070 @Override 071 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) { 072 throw new UnsupportedOperationException("Not yet supported"); 073 } 074 075 @Override 076 public AnnotationVisitor visitArray(String name) { 077 tags.add("["); 078 if (name == null) { 079 name = ""; 080 } 081 nameRU.add(name); 082 caseArrayN.add(Integer.valueOf(0)); 083 return new ArrayVisitor(caseArrayN, tags, nameRU, values); 084 } 085 086 @Override 087 public void visitEnd() { 088 } 089 090 @Override 091 public void visitEnum(final String name, final String desc, final String value) { 092 final Integer numCases = caseArrayN.remove(caseArrayN.size() - 1); 093 caseArrayN.add(Integer.valueOf(numCases.intValue() + 1)); 094 tags.add("e"); 095 values.add(desc); 096 values.add(value); 097 } 098 } 099 100 /** 101 * Exception indicating that the class currently being visited contains an unknown attribute, which means that by default the class file needs to be passed 102 * through as-is in the file_bands rather than being packed with pack200. 103 */ 104 public static class PassException extends RuntimeException { 105 106 private static final long serialVersionUID = 1L; 107 108 } 109 110 /** 111 * SegmentAnnotationVisitor implements {@code AnnotationVisitor} to visit Annotations found in a class file. 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<>(); // tags 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// return null; 179 } 180 181 @Override 182 public AnnotationVisitor visitArray(final String arg0) { 183 throw new UnsupportedOperationException("Not yet supported"); 184// return null; 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 * SegmentFieldVisitor implements {@code FieldVisitor} to visit the metadata relating to fields in a class file. 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 } // else skip 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 } // else skip 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 * This class implements MethodVisitor to visit the contents and metadata related to methods in a class file. 283 * 284 * It delegates to BcBands for bytecode related visits and to ClassBands for everything else. 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 } // else skip 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 } // else skip 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 } // else skip 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 // TODO: Java 6 - implement support for this 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 /** See https://asm.ow2.io/Javadoc/org/objectweb/asm/Opcodes.html#ASM4 */ 453 public static int ASM_API = Opcodes.ASM4; 454 private SegmentHeader segmentHeader; 455 private CpBands cpBands; 456 private AttributeDefinitionBands attributeDefinitionBands; 457 458 private IcBands icBands; 459 private ClassBands classBands; 460 private BcBands bcBands; 461 private FileBands fileBands; 462 private final SegmentFieldVisitor fieldVisitor = new SegmentFieldVisitor(); 463 private final SegmentMethodVisitor methodVisitor = new SegmentMethodVisitor(); 464 465 private Pack200ClassReader currentClassReader; 466 467 private PackingOptions options; 468 469 private boolean stripDebug; 470 471 private Attribute[] nonStandardAttributePrototypes; 472 473 public Segment() { 474 super(ASM_API); 475 } 476 477 // helper method for annotation visitors 478 private void addValueAndTag(final Object value, final List<String> tags, final List<Object> values) { 479 if (value instanceof Integer) { 480 tags.add("I"); 481 values.add(value); 482 } else if (value instanceof Double) { 483 tags.add("D"); 484 values.add(value); 485 } else if (value instanceof Float) { 486 tags.add("F"); 487 values.add(value); 488 } else if (value instanceof Long) { 489 tags.add("J"); 490 values.add(value); 491 } else if (value instanceof Byte) { 492 tags.add("B"); 493 values.add(Integer.valueOf(((Byte) value).intValue())); 494 } else if (value instanceof Character) { 495 tags.add("C"); 496 values.add(Integer.valueOf(((Character) value).charValue())); 497 } else if (value instanceof Short) { 498 tags.add("S"); 499 values.add(Integer.valueOf(((Short) value).intValue())); 500 } else if (value instanceof Boolean) { 501 tags.add("Z"); 502 values.add(Integer.valueOf(((Boolean) value).booleanValue() ? 1 : 0)); 503 } else if (value instanceof String) { 504 tags.add("s"); 505 values.add(value); 506 } else if (value instanceof Type) { 507 tags.add("c"); 508 values.add(((Type) value).toString()); 509 } 510 } 511 512 public AttributeDefinitionBands getAttrBands() { 513 return attributeDefinitionBands; 514 } 515 516 public ClassBands getClassBands() { 517 return classBands; 518 } 519 520 public CpBands getCpBands() { 521 return cpBands; 522 } 523 524 public Pack200ClassReader getCurrentClassReader() { 525 return currentClassReader; 526 } 527 528 public IcBands getIcBands() { 529 return icBands; 530 } 531 532 public SegmentHeader getSegmentHeader() { 533 return segmentHeader; 534 } 535 536 public boolean lastConstantHadWideIndex() { 537 return currentClassReader.lastConstantHadWideIndex(); 538 } 539 540 /** 541 * The main method on Segment. Reads in all the class files, packs them and then writes the packed segment out to the given OutputStream. 542 * 543 * @param segmentUnit TODO 544 * @param out the OutputStream to write the packed Segment to 545 * @param options packing options 546 * @throws IOException If an I/O error occurs. 547 * @throws Pack200Exception TODO 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 // Using a temporary stream because we have to pack the other bands 593 // before segmentHeader because the band_headers band is only created 594 // when the other bands are packed, but comes before them in the packed 595 // file. 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 // Pass this class through as-is rather than packing it 640 // TODO: probably need to deal with any inner classes 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 } // else skip 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 } // else skip 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}