Segment.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements. See the NOTICE file distributed with this
  4.  * work for additional information regarding copyright ownership. The ASF
  5.  * licenses this file to You under the Apache License, Version 2.0 (the
  6.  * "License"); you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  * http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14.  * License for the specific language governing permissions and limitations under
  15.  * the License.
  16.  */
  17. package org.apache.commons.compress.harmony.pack200;

  18. import java.io.ByteArrayOutputStream;
  19. import java.io.IOException;
  20. import java.io.OutputStream;
  21. import java.util.ArrayList;
  22. import java.util.List;

  23. import org.apache.commons.compress.harmony.pack200.Archive.PackingFile;
  24. import org.apache.commons.compress.harmony.pack200.Archive.SegmentUnit;
  25. import org.objectweb.asm.AnnotationVisitor;
  26. import org.objectweb.asm.Attribute;
  27. import org.objectweb.asm.ClassReader;
  28. import org.objectweb.asm.ClassVisitor;
  29. import org.objectweb.asm.FieldVisitor;
  30. import org.objectweb.asm.Label;
  31. import org.objectweb.asm.MethodVisitor;
  32. import org.objectweb.asm.Opcodes;
  33. import org.objectweb.asm.Type;

  34. /**
  35.  * A Pack200 archive consists of one or more Segments.
  36.  */
  37. public class Segment extends ClassVisitor {

  38.     public class ArrayVisitor extends AnnotationVisitor {

  39.         private final int indexInCaseArrayN;
  40.         private final List<Integer> caseArrayN;
  41.         private final List<Object> values;
  42.         private final List<String> nameRU;
  43.         private final List<String> tags;

  44.         public ArrayVisitor(final List<Integer> caseArrayN, final List<String> tags, final List<String> nameRU, final List<Object> values) {
  45.             super(ASM_API);

  46.             this.caseArrayN = caseArrayN;
  47.             this.tags = tags;
  48.             this.nameRU = nameRU;
  49.             this.values = values;
  50.             this.indexInCaseArrayN = caseArrayN.size() - 1;
  51.         }

  52.         @Override
  53.         public void visit(String name, final Object value) {
  54.             final Integer numCases = caseArrayN.remove(indexInCaseArrayN);
  55.             caseArrayN.add(indexInCaseArrayN, Integer.valueOf(numCases.intValue() + 1));
  56.             if (name == null) {
  57.                 name = "";
  58.             }
  59.             addValueAndTag(value, tags, values);
  60.         }

  61.         @Override
  62.         public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) {
  63.             throw new UnsupportedOperationException("Not yet supported");
  64.         }

  65.         @Override
  66.         public AnnotationVisitor visitArray(String name) {
  67.             tags.add("[");
  68.             if (name == null) {
  69.                 name = "";
  70.             }
  71.             nameRU.add(name);
  72.             caseArrayN.add(Integer.valueOf(0));
  73.             return new ArrayVisitor(caseArrayN, tags, nameRU, values);
  74.         }

  75.         @Override
  76.         public void visitEnd() {
  77.             // override to noop
  78.         }

  79.         @Override
  80.         public void visitEnum(final String name, final String desc, final String value) {
  81.             final Integer numCases = caseArrayN.remove(caseArrayN.size() - 1);
  82.             caseArrayN.add(Integer.valueOf(numCases.intValue() + 1));
  83.             tags.add("e");
  84.             values.add(desc);
  85.             values.add(value);
  86.         }
  87.     }

  88.     /**
  89.      * Exception indicating that the class currently being visited contains an unknown attribute, which means that by default the class file needs to be passed
  90.      * through as-is in the file_bands rather than being packed with pack200.
  91.      */
  92.     public static class PassException extends RuntimeException {

  93.         private static final long serialVersionUID = 1L;

  94.     }

  95.     /**
  96.      * SegmentAnnotationVisitor implements {@code AnnotationVisitor} to visit Annotations found in a class file.
  97.      */
  98.     public class SegmentAnnotationVisitor extends AnnotationVisitor {

  99.         private int context = -1;
  100.         private int parameter = -1;
  101.         private String desc;
  102.         private boolean visible;

  103.         private final List<String> nameRU = new ArrayList<>();
  104.         private final List<String> tags = new ArrayList<>(); // tags
  105.         private final List<Object> values = new ArrayList<>();
  106.         private final List<Integer> caseArrayN = new ArrayList<>();
  107.         private final List<String> nestTypeRS = new ArrayList<>();
  108.         private final List<String> nestNameRU = new ArrayList<>();
  109.         private final List<Integer> nestPairN = new ArrayList<>();

  110.         public SegmentAnnotationVisitor(final int context) {
  111.             super(ASM_API);
  112.             this.context = context;
  113.         }

  114.         public SegmentAnnotationVisitor(final int context, final int parameter, final String desc, final boolean visible) {
  115.             super(ASM_API);
  116.             this.context = context;
  117.             this.parameter = parameter;
  118.             this.desc = desc;
  119.             this.visible = visible;
  120.         }

  121.         public SegmentAnnotationVisitor(final int context, final String desc, final boolean visible) {
  122.             super(ASM_API);
  123.             this.context = context;
  124.             this.desc = desc;
  125.             this.visible = visible;
  126.         }

  127.         @Override
  128.         public void visit(String name, final Object value) {
  129.             if (name == null) {
  130.                 name = "";
  131.             }
  132.             nameRU.add(name);
  133.             addValueAndTag(value, tags, values);
  134.         }

  135.         @Override
  136.         public AnnotationVisitor visitAnnotation(String name, final String desc) {
  137.             tags.add("@");
  138.             if (name == null) {
  139.                 name = "";
  140.             }
  141.             nameRU.add(name);
  142.             nestTypeRS.add(desc);
  143.             nestPairN.add(Integer.valueOf(0));
  144.             return new AnnotationVisitor(context, av) {
  145.                 @Override
  146.                 public void visit(final String name, final Object value) {
  147.                     final Integer numPairs = nestPairN.remove(nestPairN.size() - 1);
  148.                     nestPairN.add(Integer.valueOf(numPairs.intValue() + 1));
  149.                     nestNameRU.add(name);
  150.                     addValueAndTag(value, tags, values);
  151.                 }

  152.                 @Override
  153.                 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) {
  154.                     throw new UnsupportedOperationException("Not yet supported");
  155. //                    return null;
  156.                 }

  157.                 @Override
  158.                 public AnnotationVisitor visitArray(final String arg0) {
  159.                     throw new UnsupportedOperationException("Not yet supported");
  160. //                    return null;
  161.                 }

  162.                 @Override
  163.                 public void visitEnd() {
  164.                 }

  165.                 @Override
  166.                 public void visitEnum(final String name, final String desc, final String value) {
  167.                     final Integer numPairs = nestPairN.remove(nestPairN.size() - 1);
  168.                     nestPairN.add(Integer.valueOf(numPairs.intValue() + 1));
  169.                     tags.add("e");
  170.                     nestNameRU.add(name);
  171.                     values.add(desc);
  172.                     values.add(value);
  173.                 }
  174.             };
  175.         }

  176.         @Override
  177.         public AnnotationVisitor visitArray(String name) {
  178.             tags.add("[");
  179.             if (name == null) {
  180.                 name = "";
  181.             }
  182.             nameRU.add(name);
  183.             caseArrayN.add(Integer.valueOf(0));
  184.             return new ArrayVisitor(caseArrayN, tags, nameRU, values);
  185.         }

  186.         @Override
  187.         public void visitEnd() {
  188.             if (desc == null) {
  189.                 Segment.this.classBands.addAnnotationDefault(nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  190.             } else if (parameter != -1) {
  191.                 Segment.this.classBands.addParameterAnnotation(parameter, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  192.             } else {
  193.                 Segment.this.classBands.addAnnotation(context, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  194.             }
  195.         }

  196.         @Override
  197.         public void visitEnum(String name, final String desc, final String value) {
  198.             tags.add("e");
  199.             if (name == null) {
  200.                 name = "";
  201.             }
  202.             nameRU.add(name);
  203.             values.add(desc);
  204.             values.add(value);
  205.         }
  206.     }

  207.     /**
  208.      * SegmentFieldVisitor implements {@code FieldVisitor} to visit the metadata relating to fields in a class file.
  209.      */
  210.     public class SegmentFieldVisitor extends FieldVisitor {

  211.         public SegmentFieldVisitor() {
  212.             super(ASM_API);
  213.         }

  214.         @Override
  215.         public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
  216.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_FIELD, desc, visible);
  217.         }

  218.         @Override
  219.         public void visitAttribute(final Attribute attribute) {
  220.             if (attribute.isUnknown()) {
  221.                 final String action = options.getUnknownAttributeAction();
  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.             } else if (attribute instanceof NewAttribute) {
  228.                 final NewAttribute newAttribute = (NewAttribute) attribute;
  229.                 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_FIELD)) {
  230.                     final String action = options.getUnknownFieldAttributeAction(newAttribute.type);
  231.                     if (action.equals(PackingOptions.PASS)) {
  232.                         passCurrentClass();
  233.                     } else if (action.equals(PackingOptions.ERROR)) {
  234.                         throw new Error("Unknown attribute encountered");
  235.                     } // else skip
  236.                 }
  237.                 classBands.addFieldAttribute(newAttribute);
  238.             } else {
  239.                 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
  240.             }
  241.         }

  242.         @Override
  243.         public void visitEnd() {
  244.         }
  245.     }

  246.     /**
  247.      * This class implements MethodVisitor to visit the contents and metadata related to methods in a class file.
  248.      *
  249.      * It delegates to BcBands for bytecode related visits and to ClassBands for everything else.
  250.      */
  251.     public class SegmentMethodVisitor extends MethodVisitor {

  252.         public SegmentMethodVisitor() {
  253.             super(ASM_API);
  254.         }

  255.         @Override
  256.         public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
  257.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, desc, visible);
  258.         }

  259.         @Override
  260.         public AnnotationVisitor visitAnnotationDefault() {
  261.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD);
  262.         }

  263.         @Override
  264.         public void visitAttribute(final Attribute attribute) {
  265.             if (attribute.isUnknown()) {
  266.                 final String action = options.getUnknownAttributeAction();
  267.                 if (action.equals(PackingOptions.PASS)) {
  268.                     passCurrentClass();
  269.                 } else if (action.equals(PackingOptions.ERROR)) {
  270.                     throw new Error("Unknown attribute encountered");
  271.                 } // else skip
  272.             } else if (attribute instanceof NewAttribute) {
  273.                 final NewAttribute newAttribute = (NewAttribute) attribute;
  274.                 if (attribute.isCodeAttribute()) {
  275.                     if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CODE)) {
  276.                         final String action = options.getUnknownCodeAttributeAction(newAttribute.type);
  277.                         if (action.equals(PackingOptions.PASS)) {
  278.                             passCurrentClass();
  279.                         } else if (action.equals(PackingOptions.ERROR)) {
  280.                             throw new Error("Unknown attribute encountered");
  281.                         } // else skip
  282.                     }
  283.                     classBands.addCodeAttribute(newAttribute);
  284.                 } else {
  285.                     if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_METHOD)) {
  286.                         final String action = options.getUnknownMethodAttributeAction(newAttribute.type);
  287.                         if (action.equals(PackingOptions.PASS)) {
  288.                             passCurrentClass();
  289.                         } else if (action.equals(PackingOptions.ERROR)) {
  290.                             throw new Error("Unknown attribute encountered");
  291.                         } // else skip
  292.                     }
  293.                     classBands.addMethodAttribute(newAttribute);
  294.                 }
  295.             } else {
  296.                 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
  297.             }
  298.         }

  299.         @Override
  300.         public void visitCode() {
  301.             classBands.addCode();
  302.         }

  303.         @Override
  304.         public void visitEnd() {
  305.             classBands.endOfMethod();
  306.             bcBands.visitEnd();
  307.         }

  308.         @Override
  309.         public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
  310.             bcBands.visitFieldInsn(opcode, owner, name, desc);
  311.         }

  312.         @Override
  313.         public void visitFrame(final int arg0, final int arg1, final Object[] arg2, final int arg3, final Object[] arg4) {
  314.             // TODO: Java 6 - implement support for this

  315.         }

  316.         @Override
  317.         public void visitIincInsn(final int var, final int increment) {
  318.             bcBands.visitIincInsn(var, increment);
  319.         }

  320.         @Override
  321.         public void visitInsn(final int opcode) {
  322.             bcBands.visitInsn(opcode);
  323.         }

  324.         @Override
  325.         public void visitIntInsn(final int opcode, final int operand) {
  326.             bcBands.visitIntInsn(opcode, operand);
  327.         }

  328.         @Override
  329.         public void visitJumpInsn(final int opcode, final Label label) {
  330.             bcBands.visitJumpInsn(opcode, label);
  331.         }

  332.         @Override
  333.         public void visitLabel(final Label label) {
  334.             bcBands.visitLabel(label);
  335.         }

  336.         @Override
  337.         public void visitLdcInsn(final Object cst) {
  338.             bcBands.visitLdcInsn(cst);
  339.         }

  340.         @Override
  341.         public void visitLineNumber(final int line, final Label start) {
  342.             if (!stripDebug) {
  343.                 classBands.addLineNumber(line, start);
  344.             }
  345.         }

  346.         @Override
  347.         public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index) {
  348.             if (!stripDebug) {
  349.                 classBands.addLocalVariable(name, desc, signature, start, end, index);
  350.             }
  351.         }

  352.         @Override
  353.         public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
  354.             bcBands.visitLookupSwitchInsn(dflt, keys, labels);
  355.         }

  356.         @Override
  357.         public void visitMaxs(final int maxStack, final int maxLocals) {
  358.             classBands.addMaxStack(maxStack, maxLocals);
  359.         }

  360.         @Override
  361.         public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
  362.             bcBands.visitMethodInsn(opcode, owner, name, desc);
  363.         }

  364.         @Override
  365.         public void visitMultiANewArrayInsn(final String desc, final int dimensions) {
  366.             bcBands.visitMultiANewArrayInsn(desc, dimensions);
  367.         }

  368.         @Override
  369.         public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, final boolean visible) {
  370.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, parameter, desc, visible);
  371.         }

  372.         @Override
  373.         public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) {
  374.             bcBands.visitTableSwitchInsn(min, max, dflt, labels);
  375.         }

  376.         @Override
  377.         public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) {
  378.             classBands.addHandler(start, end, handler, type);
  379.         }

  380.         @Override
  381.         public void visitTypeInsn(final int opcode, final String type) {
  382.             bcBands.visitTypeInsn(opcode, type);
  383.         }

  384.         @Override
  385.         public void visitVarInsn(final int opcode, final int var) {
  386.             bcBands.visitVarInsn(opcode, var);
  387.         }

  388.     }

  389.     /** See https://asm.ow2.io/Javadoc/org/objectweb/asm/Opcodes.html#ASM4 */
  390.     public static int ASM_API = Opcodes.ASM4;
  391.     private SegmentHeader segmentHeader;
  392.     private CpBands cpBands;
  393.     private AttributeDefinitionBands attributeDefinitionBands;

  394.     private IcBands icBands;
  395.     private ClassBands classBands;
  396.     private BcBands bcBands;
  397.     private FileBands fileBands;
  398.     private final SegmentFieldVisitor fieldVisitor = new SegmentFieldVisitor();
  399.     private final SegmentMethodVisitor methodVisitor = new SegmentMethodVisitor();

  400.     private Pack200ClassReader currentClassReader;

  401.     private PackingOptions options;

  402.     private boolean stripDebug;

  403.     private Attribute[] nonStandardAttributePrototypes;

  404.     public Segment() {
  405.         super(ASM_API);
  406.     }

  407.     // helper method for annotation visitors
  408.     private void addValueAndTag(final Object value, final List<String> tags, final List<Object> values) {
  409.         if (value instanceof Integer) {
  410.             tags.add("I");
  411.             values.add(value);
  412.         } else if (value instanceof Double) {
  413.             tags.add("D");
  414.             values.add(value);
  415.         } else if (value instanceof Float) {
  416.             tags.add("F");
  417.             values.add(value);
  418.         } else if (value instanceof Long) {
  419.             tags.add("J");
  420.             values.add(value);
  421.         } else if (value instanceof Byte) {
  422.             tags.add("B");
  423.             values.add(Integer.valueOf(((Byte) value).intValue()));
  424.         } else if (value instanceof Character) {
  425.             tags.add("C");
  426.             values.add(Integer.valueOf(((Character) value).charValue()));
  427.         } else if (value instanceof Short) {
  428.             tags.add("S");
  429.             values.add(Integer.valueOf(((Short) value).intValue()));
  430.         } else if (value instanceof Boolean) {
  431.             tags.add("Z");
  432.             values.add(Integer.valueOf(((Boolean) value).booleanValue() ? 1 : 0));
  433.         } else if (value instanceof String) {
  434.             tags.add("s");
  435.             values.add(value);
  436.         } else if (value instanceof Type) {
  437.             tags.add("c");
  438.             values.add(((Type) value).toString());
  439.         }
  440.     }

  441.     public AttributeDefinitionBands getAttrBands() {
  442.         return attributeDefinitionBands;
  443.     }

  444.     public ClassBands getClassBands() {
  445.         return classBands;
  446.     }

  447.     public CpBands getCpBands() {
  448.         return cpBands;
  449.     }

  450.     public Pack200ClassReader getCurrentClassReader() {
  451.         return currentClassReader;
  452.     }

  453.     public IcBands getIcBands() {
  454.         return icBands;
  455.     }

  456.     public SegmentHeader getSegmentHeader() {
  457.         return segmentHeader;
  458.     }

  459.     public boolean lastConstantHadWideIndex() {
  460.         return currentClassReader.lastConstantHadWideIndex();
  461.     }

  462.     /**
  463.      * The main method on Segment. Reads in all the class files, packs them and then writes the packed segment out to the given OutputStream.
  464.      *
  465.      * @param segmentUnit TODO
  466.      * @param out         the OutputStream to write the packed Segment to
  467.      * @param options     packing options
  468.      * @throws IOException      If an I/O error occurs.
  469.      * @throws Pack200Exception TODO
  470.      */
  471.     public void pack(final SegmentUnit segmentUnit, final OutputStream out, final PackingOptions options) throws IOException, Pack200Exception {
  472.         this.options = options;
  473.         this.stripDebug = options.isStripDebug();
  474.         final int effort = options.getEffort();
  475.         nonStandardAttributePrototypes = options.getUnknownAttributePrototypes();

  476.         PackingUtils.log("Start to pack a new segment with " + segmentUnit.fileListSize() + " files including " + segmentUnit.classListSize() + " classes");

  477.         PackingUtils.log("Initialize a header for the segment");
  478.         segmentHeader = new SegmentHeader();
  479.         segmentHeader.setFile_count(segmentUnit.fileListSize());
  480.         segmentHeader.setHave_all_code_flags(!stripDebug);
  481.         if (!options.isKeepDeflateHint()) {
  482.             segmentHeader.setDeflate_hint(Boolean.parseBoolean(options.getDeflateHint()));
  483.         }

  484.         PackingUtils.log("Setup constant pool bands for the segment");
  485.         cpBands = new CpBands(this, effort);

  486.         PackingUtils.log("Setup attribute definition bands for the segment");
  487.         attributeDefinitionBands = new AttributeDefinitionBands(this, effort, nonStandardAttributePrototypes);

  488.         PackingUtils.log("Setup internal class bands for the segment");
  489.         icBands = new IcBands(segmentHeader, cpBands, effort);

  490.         PackingUtils.log("Setup class bands for the segment");
  491.         classBands = new ClassBands(this, segmentUnit.classListSize(), effort, stripDebug);

  492.         PackingUtils.log("Setup byte code bands for the segment");
  493.         bcBands = new BcBands(cpBands, this, effort);

  494.         PackingUtils.log("Setup file bands for the segment");
  495.         fileBands = new FileBands(cpBands, segmentHeader, options, segmentUnit, effort);

  496.         processClasses(segmentUnit, nonStandardAttributePrototypes);

  497.         cpBands.finaliseBands();
  498.         attributeDefinitionBands.finaliseBands();
  499.         icBands.finaliseBands();
  500.         classBands.finaliseBands();
  501.         bcBands.finaliseBands();
  502.         fileBands.finaliseBands();

  503.         // Using a temporary stream because we have to pack the other bands
  504.         // before segmentHeader because the band_headers band is only created
  505.         // when the other bands are packed, but comes before them in the packed
  506.         // file.
  507.         final ByteArrayOutputStream bandsOutputStream = new ByteArrayOutputStream();

  508.         PackingUtils.log("Packing...");
  509.         final int finalNumberOfClasses = classBands.numClassesProcessed();
  510.         segmentHeader.setClass_count(finalNumberOfClasses);
  511.         cpBands.pack(bandsOutputStream);
  512.         if (finalNumberOfClasses > 0) {
  513.             attributeDefinitionBands.pack(bandsOutputStream);
  514.             icBands.pack(bandsOutputStream);
  515.             classBands.pack(bandsOutputStream);
  516.             bcBands.pack(bandsOutputStream);
  517.         }
  518.         fileBands.pack(bandsOutputStream);

  519.         final ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream();
  520.         segmentHeader.pack(headerOutputStream);

  521.         headerOutputStream.writeTo(out);
  522.         bandsOutputStream.writeTo(out);

  523.         segmentUnit.addPackedByteAmount(headerOutputStream.size());
  524.         segmentUnit.addPackedByteAmount(bandsOutputStream.size());

  525.         PackingUtils.log("Wrote total of " + segmentUnit.getPackedByteAmount() + " bytes");
  526.         PackingUtils.log("Transmitted " + segmentUnit.fileListSize() + " files of " + segmentUnit.getByteAmount() + " input bytes in a segment of "
  527.                 + segmentUnit.getPackedByteAmount() + " bytes");
  528.     }

  529.     private void passCurrentClass() {
  530.         throw new PassException();
  531.     }

  532.     private void processClasses(final SegmentUnit segmentUnit, final Attribute[] attributes) throws Pack200Exception {
  533.         segmentHeader.setClass_count(segmentUnit.classListSize());
  534.         for (final Pack200ClassReader classReader : segmentUnit.getClassList()) {
  535.             currentClassReader = classReader;
  536.             int flags = 0;
  537.             if (stripDebug) {
  538.                 flags |= ClassReader.SKIP_DEBUG;
  539.             }
  540.             try {
  541.                 classReader.accept(this, attributes, flags);
  542.             } catch (final PassException pe) {
  543.                 // Pass this class through as-is rather than packing it
  544.                 // TODO: probably need to deal with any inner classes
  545.                 classBands.removeCurrentClass();
  546.                 final String name = classReader.getFileName();
  547.                 options.addPassFile(name);
  548.                 cpBands.addCPUtf8(name);
  549.                 boolean found = false;
  550.                 for (final PackingFile file : segmentUnit.getFileList()) {
  551.                     if (file.getName().equals(name)) {
  552.                         found = true;
  553.                         file.setContents(classReader.b);
  554.                         break;
  555.                     }
  556.                 }
  557.                 if (!found) {
  558.                     throw new Pack200Exception("Error passing file " + name);
  559.                 }
  560.             }
  561.         }
  562.     }

  563.     @Override
  564.     public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
  565.         bcBands.setCurrentClass(name, superName);
  566.         segmentHeader.addMajorVersion(version);
  567.         classBands.addClass(version, access, name, signature, superName, interfaces);
  568.     }

  569.     @Override
  570.     public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
  571.         return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_CLASS, desc, visible);
  572.     }

  573.     @Override
  574.     public void visitAttribute(final Attribute attribute) {
  575.         if (attribute.isUnknown()) {
  576.             final String action = options.getUnknownAttributeAction();
  577.             if (action.equals(PackingOptions.PASS)) {
  578.                 passCurrentClass();
  579.             } else if (action.equals(PackingOptions.ERROR)) {
  580.                 throw new Error("Unknown attribute encountered");
  581.             } // else skip
  582.         } else if (attribute instanceof NewAttribute) {
  583.             final NewAttribute newAttribute = (NewAttribute) attribute;
  584.             if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CLASS)) {
  585.                 final String action = options.getUnknownClassAttributeAction(newAttribute.type);
  586.                 if (action.equals(PackingOptions.PASS)) {
  587.                     passCurrentClass();
  588.                 } else if (action.equals(PackingOptions.ERROR)) {
  589.                     throw new Error("Unknown attribute encountered");
  590.                 } // else skip
  591.             }
  592.             classBands.addClassAttribute(newAttribute);
  593.         } else {
  594.             throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
  595.         }
  596.     }

  597.     @Override
  598.     public void visitEnd() {
  599.         classBands.endOfClass();
  600.     }

  601.     @Override
  602.     public FieldVisitor visitField(final int flags, final String name, final String desc, final String signature, final Object value) {
  603.         classBands.addField(flags, name, desc, signature, value);
  604.         return fieldVisitor;
  605.     }

  606.     @Override
  607.     public void visitInnerClass(final String name, final String outerName, final String innerName, final int flags) {
  608.         icBands.addInnerClass(name, outerName, innerName, flags);
  609.     }

  610.     @Override
  611.     public MethodVisitor visitMethod(final int flags, final String name, final String desc, final String signature, final String[] exceptions) {
  612.         classBands.addMethod(flags, name, desc, signature, exceptions);
  613.         return methodVisitor;
  614.     }

  615.     @Override
  616.     public void visitOuterClass(final String owner, final String name, final String desc) {
  617.         classBands.addEnclosingMethod(owner, name, desc);

  618.     }

  619.     @Override
  620.     public void visitSource(final String source, final String debug) {
  621.         if (!stripDebug) {
  622.             classBands.addSourceFile(source);
  623.         }
  624.     }
  625. }