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