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