Segment.java

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

  19. package org.apache.commons.compress.harmony.pack200;

  20. import java.io.ByteArrayOutputStream;
  21. import java.io.IOException;
  22. import java.io.OutputStream;
  23. import java.util.ArrayList;
  24. import java.util.List;

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

  36. /**
  37.  * A Pack200 archive consists of one or more Segments.
  38.  * <p>
  39.  * Format:
  40.  * </p>
  41.  * <pre>
  42.  *   pack200_archive:
  43.  *      (pack200_segment)+
  44.  *
  45.  *   pack200_segment:
  46.  *      segment_header
  47.  *      *band_headers :BYTE1
  48.  *      cp_bands
  49.  *      attr_definition_bands
  50.  *      ic_bands
  51.  *      class_bands
  52.  *      bc_bands
  53.  *      file_bands
  54.  * </pre>
  55.  */
  56. public class Segment extends ClassVisitor {

  57.     public class ArrayVisitor extends AnnotationVisitor {

  58.         private final int indexInCaseArrayN;
  59.         private final List<Integer> caseArrayN;
  60.         private final List<Object> values;
  61.         private final List<String> nameRU;
  62.         private final List<String> tags;

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

  65.             this.caseArrayN = caseArrayN;
  66.             this.tags = tags;
  67.             this.nameRU = nameRU;
  68.             this.values = values;
  69.             this.indexInCaseArrayN = caseArrayN.size() - 1;
  70.         }

  71.         @Override
  72.         public void visit(String name, final Object value) {
  73.             final Integer numCases = caseArrayN.remove(indexInCaseArrayN);
  74.             caseArrayN.add(indexInCaseArrayN, Integer.valueOf(numCases.intValue() + 1));
  75.             if (name == null) {
  76.                 name = "";
  77.             }
  78.             addValueAndTag(value, tags, values);
  79.         }

  80.         @Override
  81.         public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) {
  82.             throw new UnsupportedOperationException("Not yet supported");
  83.         }

  84.         @Override
  85.         public AnnotationVisitor visitArray(String name) {
  86.             tags.add("[");
  87.             if (name == null) {
  88.                 name = "";
  89.             }
  90.             nameRU.add(name);
  91.             caseArrayN.add(Integer.valueOf(0));
  92.             return new ArrayVisitor(caseArrayN, tags, nameRU, values);
  93.         }

  94.         @Override
  95.         public void visitEnd() {
  96.             // override to noop
  97.         }

  98.         @Override
  99.         public void visitEnum(final String name, final String desc, final String value) {
  100.             final Integer numCases = caseArrayN.remove(caseArrayN.size() - 1);
  101.             caseArrayN.add(Integer.valueOf(numCases.intValue() + 1));
  102.             tags.add("e");
  103.             values.add(desc);
  104.             values.add(value);
  105.         }
  106.     }

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

  112.         private static final long serialVersionUID = 1L;

  113.     }

  114.     /**
  115.      * SegmentAnnotationVisitor implements {@code AnnotationVisitor} to visit Annotations found in a class file.
  116.      */
  117.     public class SegmentAnnotationVisitor extends AnnotationVisitor {

  118.         private int context = -1;
  119.         private int parameter = -1;
  120.         private String desc;
  121.         private boolean visible;

  122.         private final List<String> nameRU = new ArrayList<>();
  123.         private final List<String> tags = new ArrayList<>(); // tags
  124.         private final List<Object> values = new ArrayList<>();
  125.         private final List<Integer> caseArrayN = new ArrayList<>();
  126.         private final List<String> nestTypeRS = new ArrayList<>();
  127.         private final List<String> nestNameRU = new ArrayList<>();
  128.         private final List<Integer> nestPairN = new ArrayList<>();

  129.         public SegmentAnnotationVisitor(final int context) {
  130.             super(ASM_API);
  131.             this.context = context;
  132.         }

  133.         public SegmentAnnotationVisitor(final int context, final int parameter, final String desc, final boolean visible) {
  134.             super(ASM_API);
  135.             this.context = context;
  136.             this.parameter = parameter;
  137.             this.desc = desc;
  138.             this.visible = visible;
  139.         }

  140.         public SegmentAnnotationVisitor(final int context, final String desc, final boolean visible) {
  141.             super(ASM_API);
  142.             this.context = context;
  143.             this.desc = desc;
  144.             this.visible = visible;
  145.         }

  146.         @Override
  147.         public void visit(String name, final Object value) {
  148.             if (name == null) {
  149.                 name = "";
  150.             }
  151.             nameRU.add(name);
  152.             addValueAndTag(value, tags, values);
  153.         }

  154.         @Override
  155.         public AnnotationVisitor visitAnnotation(String name, final String desc) {
  156.             tags.add("@");
  157.             if (name == null) {
  158.                 name = "";
  159.             }
  160.             nameRU.add(name);
  161.             nestTypeRS.add(desc);
  162.             nestPairN.add(Integer.valueOf(0));
  163.             return new AnnotationVisitor(context, av) {
  164.                 @Override
  165.                 public void visit(final String name, final Object value) {
  166.                     final Integer numPairs = nestPairN.remove(nestPairN.size() - 1);
  167.                     nestPairN.add(Integer.valueOf(numPairs.intValue() + 1));
  168.                     nestNameRU.add(name);
  169.                     addValueAndTag(value, tags, values);
  170.                 }

  171.                 @Override
  172.                 public AnnotationVisitor visitAnnotation(final String arg0, final String arg1) {
  173.                     throw new UnsupportedOperationException("Not yet supported");
  174. //                    return null;
  175.                 }

  176.                 @Override
  177.                 public AnnotationVisitor visitArray(final String arg0) {
  178.                     throw new UnsupportedOperationException("Not yet supported");
  179. //                    return null;
  180.                 }

  181.                 @Override
  182.                 public void visitEnd() {
  183.                 }

  184.                 @Override
  185.                 public void visitEnum(final String name, final String desc, final String value) {
  186.                     final Integer numPairs = nestPairN.remove(nestPairN.size() - 1);
  187.                     nestPairN.add(Integer.valueOf(numPairs.intValue() + 1));
  188.                     tags.add("e");
  189.                     nestNameRU.add(name);
  190.                     values.add(desc);
  191.                     values.add(value);
  192.                 }
  193.             };
  194.         }

  195.         @Override
  196.         public AnnotationVisitor visitArray(String name) {
  197.             tags.add("[");
  198.             if (name == null) {
  199.                 name = "";
  200.             }
  201.             nameRU.add(name);
  202.             caseArrayN.add(Integer.valueOf(0));
  203.             return new ArrayVisitor(caseArrayN, tags, nameRU, values);
  204.         }

  205.         @Override
  206.         public void visitEnd() {
  207.             if (desc == null) {
  208.                 Segment.this.classBands.addAnnotationDefault(nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  209.             } else if (parameter != -1) {
  210.                 Segment.this.classBands.addParameterAnnotation(parameter, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  211.             } else {
  212.                 Segment.this.classBands.addAnnotation(context, desc, visible, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  213.             }
  214.         }

  215.         @Override
  216.         public void visitEnum(String name, final String desc, final String value) {
  217.             tags.add("e");
  218.             if (name == null) {
  219.                 name = "";
  220.             }
  221.             nameRU.add(name);
  222.             values.add(desc);
  223.             values.add(value);
  224.         }
  225.     }

  226.     /**
  227.      * SegmentFieldVisitor implements {@code FieldVisitor} to visit the metadata relating to fields in a class file.
  228.      */
  229.     public class SegmentFieldVisitor extends FieldVisitor {

  230.         public SegmentFieldVisitor() {
  231.             super(ASM_API);
  232.         }

  233.         @Override
  234.         public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
  235.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_FIELD, desc, visible);
  236.         }

  237.         @Override
  238.         public void visitAttribute(final Attribute attribute) {
  239.             if (attribute.isUnknown()) {
  240.                 final String action = options.getUnknownAttributeAction();
  241.                 if (action.equals(PackingOptions.PASS)) {
  242.                     passCurrentClass();
  243.                 } else if (action.equals(PackingOptions.ERROR)) {
  244.                     throw new Error("Unknown attribute encountered");
  245.                 } // else skip
  246.             } else if (attribute instanceof NewAttribute) {
  247.                 final NewAttribute newAttribute = (NewAttribute) attribute;
  248.                 if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_FIELD)) {
  249.                     final String action = options.getUnknownFieldAttributeAction(newAttribute.type);
  250.                     if (action.equals(PackingOptions.PASS)) {
  251.                         passCurrentClass();
  252.                     } else if (action.equals(PackingOptions.ERROR)) {
  253.                         throw new Error("Unknown attribute encountered");
  254.                     } // else skip
  255.                 }
  256.                 classBands.addFieldAttribute(newAttribute);
  257.             } else {
  258.                 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
  259.             }
  260.         }

  261.         @Override
  262.         public void visitEnd() {
  263.         }
  264.     }

  265.     /**
  266.      * This class implements MethodVisitor to visit the contents and metadata related to methods in a class file.
  267.      *
  268.      * It delegates to BcBands for bytecode related visits and to ClassBands for everything else.
  269.      */
  270.     public class SegmentMethodVisitor extends MethodVisitor {

  271.         public SegmentMethodVisitor() {
  272.             super(ASM_API);
  273.         }

  274.         @Override
  275.         public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
  276.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, desc, visible);
  277.         }

  278.         @Override
  279.         public AnnotationVisitor visitAnnotationDefault() {
  280.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD);
  281.         }

  282.         @Override
  283.         public void visitAttribute(final Attribute attribute) {
  284.             if (attribute.isUnknown()) {
  285.                 final String action = options.getUnknownAttributeAction();
  286.                 if (action.equals(PackingOptions.PASS)) {
  287.                     passCurrentClass();
  288.                 } else if (action.equals(PackingOptions.ERROR)) {
  289.                     throw new Error("Unknown attribute encountered");
  290.                 } // else skip
  291.             } else if (attribute instanceof NewAttribute) {
  292.                 final NewAttribute newAttribute = (NewAttribute) attribute;
  293.                 if (attribute.isCodeAttribute()) {
  294.                     if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CODE)) {
  295.                         final String action = options.getUnknownCodeAttributeAction(newAttribute.type);
  296.                         if (action.equals(PackingOptions.PASS)) {
  297.                             passCurrentClass();
  298.                         } else if (action.equals(PackingOptions.ERROR)) {
  299.                             throw new Error("Unknown attribute encountered");
  300.                         } // else skip
  301.                     }
  302.                     classBands.addCodeAttribute(newAttribute);
  303.                 } else {
  304.                     if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_METHOD)) {
  305.                         final String action = options.getUnknownMethodAttributeAction(newAttribute.type);
  306.                         if (action.equals(PackingOptions.PASS)) {
  307.                             passCurrentClass();
  308.                         } else if (action.equals(PackingOptions.ERROR)) {
  309.                             throw new Error("Unknown attribute encountered");
  310.                         } // else skip
  311.                     }
  312.                     classBands.addMethodAttribute(newAttribute);
  313.                 }
  314.             } else {
  315.                 throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
  316.             }
  317.         }

  318.         @Override
  319.         public void visitCode() {
  320.             classBands.addCode();
  321.         }

  322.         @Override
  323.         public void visitEnd() {
  324.             classBands.endOfMethod();
  325.             bcBands.visitEnd();
  326.         }

  327.         @Override
  328.         public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
  329.             bcBands.visitFieldInsn(opcode, owner, name, desc);
  330.         }

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

  334.         }

  335.         @Override
  336.         public void visitIincInsn(final int var, final int increment) {
  337.             bcBands.visitIincInsn(var, increment);
  338.         }

  339.         @Override
  340.         public void visitInsn(final int opcode) {
  341.             bcBands.visitInsn(opcode);
  342.         }

  343.         @Override
  344.         public void visitIntInsn(final int opcode, final int operand) {
  345.             bcBands.visitIntInsn(opcode, operand);
  346.         }

  347.         @Override
  348.         public void visitJumpInsn(final int opcode, final Label label) {
  349.             bcBands.visitJumpInsn(opcode, label);
  350.         }

  351.         @Override
  352.         public void visitLabel(final Label label) {
  353.             bcBands.visitLabel(label);
  354.         }

  355.         @Override
  356.         public void visitLdcInsn(final Object cst) {
  357.             bcBands.visitLdcInsn(cst);
  358.         }

  359.         @Override
  360.         public void visitLineNumber(final int line, final Label start) {
  361.             if (!stripDebug) {
  362.                 classBands.addLineNumber(line, start);
  363.             }
  364.         }

  365.         @Override
  366.         public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index) {
  367.             if (!stripDebug) {
  368.                 classBands.addLocalVariable(name, desc, signature, start, end, index);
  369.             }
  370.         }

  371.         @Override
  372.         public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
  373.             bcBands.visitLookupSwitchInsn(dflt, keys, labels);
  374.         }

  375.         @Override
  376.         public void visitMaxs(final int maxStack, final int maxLocals) {
  377.             classBands.addMaxStack(maxStack, maxLocals);
  378.         }

  379.         @Override
  380.         public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) {
  381.             bcBands.visitMethodInsn(opcode, owner, name, desc);
  382.         }

  383.         @Override
  384.         public void visitMultiANewArrayInsn(final String desc, final int dimensions) {
  385.             bcBands.visitMultiANewArrayInsn(desc, dimensions);
  386.         }

  387.         @Override
  388.         public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, final boolean visible) {
  389.             return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_METHOD, parameter, desc, visible);
  390.         }

  391.         @Override
  392.         public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) {
  393.             bcBands.visitTableSwitchInsn(min, max, dflt, labels);
  394.         }

  395.         @Override
  396.         public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) {
  397.             classBands.addHandler(start, end, handler, type);
  398.         }

  399.         @Override
  400.         public void visitTypeInsn(final int opcode, final String type) {
  401.             bcBands.visitTypeInsn(opcode, type);
  402.         }

  403.         @Override
  404.         public void visitVarInsn(final int opcode, final int var) {
  405.             bcBands.visitVarInsn(opcode, var);
  406.         }

  407.     }

  408.     /** See https://asm.ow2.io/Javadoc/org/objectweb/asm/Opcodes.html#ASM4 */
  409.     public static int ASM_API = Opcodes.ASM4;
  410.     private SegmentHeader segmentHeader;
  411.     private CpBands cpBands;
  412.     private AttributeDefinitionBands attributeDefinitionBands;

  413.     private IcBands icBands;
  414.     private ClassBands classBands;
  415.     private BcBands bcBands;
  416.     private FileBands fileBands;
  417.     private final SegmentFieldVisitor fieldVisitor = new SegmentFieldVisitor();
  418.     private final SegmentMethodVisitor methodVisitor = new SegmentMethodVisitor();

  419.     private Pack200ClassReader currentClassReader;

  420.     private PackingOptions options;

  421.     private boolean stripDebug;

  422.     private Attribute[] nonStandardAttributePrototypes;

  423.     public Segment() {
  424.         super(ASM_API);
  425.     }

  426.     // helper method for annotation visitors
  427.     private void addValueAndTag(final Object value, final List<String> tags, final List<Object> values) {
  428.         if (value instanceof Integer) {
  429.             tags.add("I");
  430.             values.add(value);
  431.         } else if (value instanceof Double) {
  432.             tags.add("D");
  433.             values.add(value);
  434.         } else if (value instanceof Float) {
  435.             tags.add("F");
  436.             values.add(value);
  437.         } else if (value instanceof Long) {
  438.             tags.add("J");
  439.             values.add(value);
  440.         } else if (value instanceof Byte) {
  441.             tags.add("B");
  442.             values.add(Integer.valueOf(((Byte) value).intValue()));
  443.         } else if (value instanceof Character) {
  444.             tags.add("C");
  445.             values.add(Integer.valueOf(((Character) value).charValue()));
  446.         } else if (value instanceof Short) {
  447.             tags.add("S");
  448.             values.add(Integer.valueOf(((Short) value).intValue()));
  449.         } else if (value instanceof Boolean) {
  450.             tags.add("Z");
  451.             values.add(Integer.valueOf(((Boolean) value).booleanValue() ? 1 : 0));
  452.         } else if (value instanceof String) {
  453.             tags.add("s");
  454.             values.add(value);
  455.         } else if (value instanceof Type) {
  456.             tags.add("c");
  457.             values.add(((Type) value).toString());
  458.         }
  459.     }

  460.     public AttributeDefinitionBands getAttrBands() {
  461.         return attributeDefinitionBands;
  462.     }

  463.     public ClassBands getClassBands() {
  464.         return classBands;
  465.     }

  466.     public CpBands getCpBands() {
  467.         return cpBands;
  468.     }

  469.     public Pack200ClassReader getCurrentClassReader() {
  470.         return currentClassReader;
  471.     }

  472.     public IcBands getIcBands() {
  473.         return icBands;
  474.     }

  475.     public SegmentHeader getSegmentHeader() {
  476.         return segmentHeader;
  477.     }

  478.     public boolean lastConstantHadWideIndex() {
  479.         return currentClassReader.lastConstantHadWideIndex();
  480.     }

  481.     /**
  482.      * The main method on Segment. Reads in all the class files, packs them and then writes the packed segment out to the given OutputStream.
  483.      *
  484.      * @param segmentUnit TODO
  485.      * @param out         the OutputStream to write the packed Segment to.
  486.      * @param options     packing options.
  487.      * @throws IOException      If an I/O error occurs.
  488.      * @throws Pack200Exception If a Pack200 semantic error occurs.
  489.      */
  490.     public void pack(final SegmentUnit segmentUnit, final OutputStream out, final PackingOptions options) throws IOException, Pack200Exception {
  491.         this.options = options;
  492.         this.stripDebug = options.isStripDebug();
  493.         final int effort = options.getEffort();
  494.         nonStandardAttributePrototypes = options.getUnknownAttributePrototypes();

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

  496.         PackingUtils.log("Initialize a header for the segment");
  497.         segmentHeader = new SegmentHeader();
  498.         segmentHeader.setFile_count(segmentUnit.fileListSize());
  499.         segmentHeader.setHave_all_code_flags(!stripDebug);
  500.         if (!options.isKeepDeflateHint()) {
  501.             segmentHeader.setDeflate_hint(Boolean.parseBoolean(options.getDeflateHint()));
  502.         }

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

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

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

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

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

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

  515.         processClasses(segmentUnit, nonStandardAttributePrototypes);

  516.         cpBands.finaliseBands();
  517.         attributeDefinitionBands.finaliseBands();
  518.         icBands.finaliseBands();
  519.         classBands.finaliseBands();
  520.         bcBands.finaliseBands();
  521.         fileBands.finaliseBands();

  522.         // Using a temporary stream because we have to pack the other bands
  523.         // before segmentHeader because the band_headers band is only created
  524.         // when the other bands are packed, but comes before them in the packed
  525.         // file.
  526.         final ByteArrayOutputStream bandsOutputStream = new ByteArrayOutputStream();

  527.         PackingUtils.log("Packing...");
  528.         final int finalNumberOfClasses = classBands.numClassesProcessed();
  529.         segmentHeader.setClass_count(finalNumberOfClasses);
  530.         cpBands.pack(bandsOutputStream);
  531.         if (finalNumberOfClasses > 0) {
  532.             attributeDefinitionBands.pack(bandsOutputStream);
  533.             icBands.pack(bandsOutputStream);
  534.             classBands.pack(bandsOutputStream);
  535.             bcBands.pack(bandsOutputStream);
  536.         }
  537.         fileBands.pack(bandsOutputStream);

  538.         final ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream();
  539.         segmentHeader.pack(headerOutputStream);

  540.         headerOutputStream.writeTo(out);
  541.         bandsOutputStream.writeTo(out);

  542.         segmentUnit.addPackedByteAmount(headerOutputStream.size());
  543.         segmentUnit.addPackedByteAmount(bandsOutputStream.size());

  544.         PackingUtils.log("Wrote total of " + segmentUnit.getPackedByteAmount() + " bytes");
  545.         PackingUtils.log("Transmitted " + segmentUnit.fileListSize() + " files of " + segmentUnit.getByteAmount() + " input bytes in a segment of "
  546.                 + segmentUnit.getPackedByteAmount() + " bytes");
  547.     }

  548.     private void passCurrentClass() {
  549.         throw new PassException();
  550.     }

  551.     private void processClasses(final SegmentUnit segmentUnit, final Attribute[] attributes) throws Pack200Exception {
  552.         segmentHeader.setClass_count(segmentUnit.classListSize());
  553.         for (final Pack200ClassReader classReader : segmentUnit.getClassList()) {
  554.             currentClassReader = classReader;
  555.             int flags = 0;
  556.             if (stripDebug) {
  557.                 flags |= ClassReader.SKIP_DEBUG;
  558.             }
  559.             try {
  560.                 classReader.accept(this, attributes, flags);
  561.             } catch (final PassException pe) {
  562.                 // Pass this class through as-is rather than packing it
  563.                 // TODO: probably need to deal with any inner classes
  564.                 classBands.removeCurrentClass();
  565.                 final String name = classReader.getFileName();
  566.                 options.addPassFile(name);
  567.                 cpBands.addCPUtf8(name);
  568.                 boolean found = false;
  569.                 for (final PackingFile file : segmentUnit.getFileList()) {
  570.                     if (file.getName().equals(name)) {
  571.                         found = true;
  572.                         file.setContents(classReader.b);
  573.                         break;
  574.                     }
  575.                 }
  576.                 if (!found) {
  577.                     throw new Pack200Exception("Error passing file " + name);
  578.                 }
  579.             }
  580.         }
  581.     }

  582.     @Override
  583.     public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
  584.         bcBands.setCurrentClass(name, superName);
  585.         segmentHeader.addMajorVersion(version);
  586.         classBands.addClass(version, access, name, signature, superName, interfaces);
  587.     }

  588.     @Override
  589.     public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
  590.         return new SegmentAnnotationVisitor(MetadataBandGroup.CONTEXT_CLASS, desc, visible);
  591.     }

  592.     @Override
  593.     public void visitAttribute(final Attribute attribute) {
  594.         if (attribute.isUnknown()) {
  595.             final String action = options.getUnknownAttributeAction();
  596.             if (action.equals(PackingOptions.PASS)) {
  597.                 passCurrentClass();
  598.             } else if (action.equals(PackingOptions.ERROR)) {
  599.                 throw new Error("Unknown attribute encountered");
  600.             } // else skip
  601.         } else if (attribute instanceof NewAttribute) {
  602.             final NewAttribute newAttribute = (NewAttribute) attribute;
  603.             if (newAttribute.isUnknown(AttributeDefinitionBands.CONTEXT_CLASS)) {
  604.                 final String action = options.getUnknownClassAttributeAction(newAttribute.type);
  605.                 if (action.equals(PackingOptions.PASS)) {
  606.                     passCurrentClass();
  607.                 } else if (action.equals(PackingOptions.ERROR)) {
  608.                     throw new Error("Unknown attribute encountered");
  609.                 } // else skip
  610.             }
  611.             classBands.addClassAttribute(newAttribute);
  612.         } else {
  613.             throw new IllegalArgumentException("Unexpected attribute encountered: " + attribute.type);
  614.         }
  615.     }

  616.     @Override
  617.     public void visitEnd() {
  618.         classBands.endOfClass();
  619.     }

  620.     @Override
  621.     public FieldVisitor visitField(final int flags, final String name, final String desc, final String signature, final Object value) {
  622.         classBands.addField(flags, name, desc, signature, value);
  623.         return fieldVisitor;
  624.     }

  625.     @Override
  626.     public void visitInnerClass(final String name, final String outerName, final String innerName, final int flags) {
  627.         icBands.addInnerClass(name, outerName, innerName, flags);
  628.     }

  629.     @Override
  630.     public MethodVisitor visitMethod(final int flags, final String name, final String desc, final String signature, final String[] exceptions) {
  631.         classBands.addMethod(flags, name, desc, signature, exceptions);
  632.         return methodVisitor;
  633.     }

  634.     @Override
  635.     public void visitOuterClass(final String owner, final String name, final String desc) {
  636.         classBands.addEnclosingMethod(owner, name, desc);

  637.     }

  638.     @Override
  639.     public void visitSource(final String source, final String debug) {
  640.         if (!stripDebug) {
  641.             classBands.addSourceFile(source);
  642.         }
  643.     }
  644. }