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