ClassBands.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  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,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.harmony.pack200;

  18. import java.io.IOException;
  19. import java.io.OutputStream;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Comparator;
  23. import java.util.HashMap;
  24. import java.util.HashSet;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;

  28. import org.apache.commons.compress.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
  29. import org.apache.commons.compress.harmony.pack200.IcBands.IcTuple;
  30. import org.objectweb.asm.Label;
  31. import org.objectweb.asm.Opcodes;

  32. /**
  33.  * Class bands (corresponds to the {@code class_bands} set of bands in the pack200 specification)
  34.  */
  35. public class ClassBands extends BandSet {

  36.     private static final class TempParamAnnotation {

  37.         int numParams;
  38.         int[] annoN;
  39.         IntList pairN = new IntList();
  40.         List<String> typeRS = new ArrayList<>();
  41.         List<String> nameRU = new ArrayList<>();
  42.         List<String> tags = new ArrayList<>();
  43.         List<Object> values = new ArrayList<>();
  44.         List<Integer> caseArrayN = new ArrayList<>();
  45.         List<String> nestTypeRS = new ArrayList<>();
  46.         List<String> nestNameRU = new ArrayList<>();
  47.         List<Integer> nestPairN = new ArrayList<>();

  48.         TempParamAnnotation(final int numParams) {
  49.             this.numParams = numParams;
  50.             annoN = new int[numParams];
  51.         }

  52.         void addParameterAnnotation(final int parameter, final String desc, final List<String> nameRU, final List<String> tags,
  53.                 final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
  54.                 final List<Integer> nestPairN) {
  55.             annoN[parameter]++;
  56.             typeRS.add(desc);
  57.             pairN.add(nameRU.size());
  58.             this.nameRU.addAll(nameRU);
  59.             this.tags.addAll(tags);
  60.             this.values.addAll(values);
  61.             this.caseArrayN.addAll(caseArrayN);
  62.             this.nestTypeRS.addAll(nestTypeRS);
  63.             this.nestNameRU.addAll(nestNameRU);
  64.             this.nestPairN.addAll(nestPairN);
  65.         }
  66.     }

  67.     private static final long[] EMPTY_LONG_ARRAY = {};

  68.     protected static int countArgs(final String descriptor) {
  69.         final int bra = descriptor.indexOf('(');
  70.         final int ket = descriptor.indexOf(')');
  71.         if (bra == -1 || ket == -1 || ket < bra) {
  72.             throw new IllegalArgumentException("No arguments");
  73.         }

  74.         boolean inType = false;
  75.         boolean consumingNextType = false;
  76.         int count = 0;
  77.         for (int i = bra + 1; i < ket; i++) {
  78.             final char charAt = descriptor.charAt(i);
  79.             if (inType && charAt == ';') {
  80.                 inType = false;
  81.                 consumingNextType = false;
  82.             } else if (!inType && charAt == 'L') {
  83.                 inType = true;
  84.                 count++;
  85.             } else if (charAt == '[') {
  86.                 consumingNextType = true;
  87.             } else if (inType) {
  88.                 // NOP
  89.             } else if (consumingNextType) {
  90.                 count++;
  91.                 consumingNextType = false;
  92.             } else if (charAt == 'D' || charAt == 'J') {
  93.                 count += 2;
  94.             } else {
  95.                 count++;
  96.             }
  97.         }
  98.         return count;
  99.     }

  100.     private final CpBands cpBands;
  101.     private final AttributeDefinitionBands attrBands;
  102.     private final CPClass[] class_this;
  103.     private final CPClass[] class_super;

  104.     private final CPClass[][] class_interface;

  105.     private final int[] class_interface_count;
  106.     private final int[] major_versions;
  107.     private final long[] class_flags;
  108.     private int[] class_attr_calls;
  109.     private final List<CPUTF8> classSourceFile = new ArrayList<>();
  110.     private final List<ConstantPoolEntry> classEnclosingMethodClass = new ArrayList<>();

  111.     private final List<ConstantPoolEntry> classEnclosingMethodDesc = new ArrayList<>();
  112.     private final List<CPSignature> classSignature = new ArrayList<>();

  113.     private final IntList classFileVersionMinor = new IntList();
  114.     private final IntList classFileVersionMajor = new IntList();
  115.     private final int[] class_field_count;
  116.     private final CPNameAndType[][] field_descr;
  117.     private final long[][] field_flags;
  118.     private int[] field_attr_calls;

  119.     private final List<CPConstant<?>> fieldConstantValueKQ = new ArrayList<>();
  120.     private final List<CPSignature> fieldSignature = new ArrayList<>();
  121.     private final int[] class_method_count;
  122.     private final CPNameAndType[][] method_descr;
  123.     private final long[][] method_flags;
  124.     private int[] method_attr_calls;
  125.     private final List<CPSignature> methodSignature = new ArrayList<>();

  126.     private final IntList methodExceptionNumber = new IntList();
  127.     private final List<CPClass> methodExceptionClasses = new ArrayList<>();
  128.     private int[] codeHeaders;
  129.     private final IntList codeMaxStack = new IntList();
  130.     private final IntList codeMaxLocals = new IntList();
  131.     private final IntList codeHandlerCount = new IntList();
  132.     private final List codeHandlerStartP = new ArrayList();
  133.     private final List codeHandlerEndPO = new ArrayList();
  134.     private final List codeHandlerCatchPO = new ArrayList();
  135.     private final List<CPClass> codeHandlerClass = new ArrayList<>();
  136.     private final List<Long> codeFlags = new ArrayList<>();
  137.     private int[] code_attr_calls;
  138.     private final IntList codeLineNumberTableN = new IntList();
  139.     private final List codeLineNumberTableBciP = new ArrayList();
  140.     private final IntList codeLineNumberTableLine = new IntList();
  141.     private final IntList codeLocalVariableTableN = new IntList();
  142.     private final List codeLocalVariableTableBciP = new ArrayList();
  143.     private final List codeLocalVariableTableSpanO = new ArrayList();
  144.     private final List<ConstantPoolEntry> codeLocalVariableTableNameRU = new ArrayList<>();
  145.     private final List<ConstantPoolEntry> codeLocalVariableTableTypeRS = new ArrayList<>();
  146.     private final IntList codeLocalVariableTableSlot = new IntList();
  147.     private final IntList codeLocalVariableTypeTableN = new IntList();
  148.     private final List codeLocalVariableTypeTableBciP = new ArrayList();
  149.     private final List codeLocalVariableTypeTableSpanO = new ArrayList();
  150.     private final List<ConstantPoolEntry> codeLocalVariableTypeTableNameRU = new ArrayList<>();

  151.     private final List<ConstantPoolEntry> codeLocalVariableTypeTableTypeRS = new ArrayList<>();
  152.     private final IntList codeLocalVariableTypeTableSlot = new IntList();
  153.     private final MetadataBandGroup class_RVA_bands;
  154.     private final MetadataBandGroup class_RIA_bands;
  155.     private final MetadataBandGroup field_RVA_bands;
  156.     private final MetadataBandGroup field_RIA_bands;
  157.     private final MetadataBandGroup method_RVA_bands;
  158.     private final MetadataBandGroup method_RIA_bands;
  159.     private final MetadataBandGroup method_RVPA_bands;

  160.     private final MetadataBandGroup method_RIPA_bands;
  161.     private final MetadataBandGroup method_AD_bands;
  162.     private final List<NewAttributeBands> classAttributeBands = new ArrayList<>();
  163.     private final List<NewAttributeBands> methodAttributeBands = new ArrayList<>();

  164.     private final List<NewAttributeBands> fieldAttributeBands = new ArrayList<>();
  165.     private final List<NewAttributeBands> codeAttributeBands = new ArrayList<>();
  166.     private final List<Long> tempFieldFlags = new ArrayList<>();
  167.     private final List<CPNameAndType> tempFieldDesc = new ArrayList<>();
  168.     private final List<Long> tempMethodFlags = new ArrayList<>();
  169.     private final List<CPNameAndType> tempMethodDesc = new ArrayList<>();

  170.     private TempParamAnnotation tempMethodRVPA;
  171.     private TempParamAnnotation tempMethodRIPA;
  172.     private boolean anySyntheticClasses;
  173.     private boolean anySyntheticFields;

  174.     private boolean anySyntheticMethods;
  175.     private final Segment segment;

  176.     private final Map<CPClass, Set<CPClass>> classReferencesInnerClass = new HashMap<>();

  177.     private final boolean stripDebug;
  178.     private int index;
  179.     private int numMethodArgs;
  180.     private int[] class_InnerClasses_N;
  181.     private CPClass[] class_InnerClasses_RC;
  182.     private int[] class_InnerClasses_F;

  183.     private List<CPClass> classInnerClassesOuterRCN;

  184.     private List<CPUTF8> classInnerClassesNameRUN;

  185.     public ClassBands(final Segment segment, final int numClasses, final int effort, final boolean stripDebug) throws IOException {
  186.         super(effort, segment.getSegmentHeader());
  187.         this.stripDebug = stripDebug;
  188.         this.segment = segment;
  189.         this.cpBands = segment.getCpBands();
  190.         this.attrBands = segment.getAttrBands();
  191.         class_this = new CPClass[numClasses];
  192.         class_super = new CPClass[numClasses];
  193.         class_interface_count = new int[numClasses];
  194.         class_interface = new CPClass[numClasses][];
  195.         class_field_count = new int[numClasses];
  196.         class_method_count = new int[numClasses];
  197.         field_descr = new CPNameAndType[numClasses][];
  198.         field_flags = new long[numClasses][];
  199.         method_descr = new CPNameAndType[numClasses][];
  200.         method_flags = new long[numClasses][];
  201.         for (int i = 0; i < numClasses; i++) {
  202.             field_flags[i] = EMPTY_LONG_ARRAY;
  203.             method_flags[i] = EMPTY_LONG_ARRAY;
  204.         }
  205.         // minor_versions = new int[numClasses];
  206.         major_versions = new int[numClasses];
  207.         class_flags = new long[numClasses];

  208.         class_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_CLASS, cpBands, segmentHeader, effort);
  209.         class_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_CLASS, cpBands, segmentHeader, effort);
  210.         field_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_FIELD, cpBands, segmentHeader, effort);
  211.         field_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_FIELD, cpBands, segmentHeader, effort);
  212.         method_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
  213.         method_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
  214.         method_RVPA_bands = new MetadataBandGroup("RVPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
  215.         method_RIPA_bands = new MetadataBandGroup("RIPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
  216.         method_AD_bands = new MetadataBandGroup("AD", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);

  217.         createNewAttributeBands();
  218.     }

  219.     public void addAnnotation(final int context, final String desc, final boolean visible, final List<String> nameRU, final List<String> tags,
  220.             final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
  221.             final List<Integer> nestPairN) {
  222.         switch (context) {
  223.         case MetadataBandGroup.CONTEXT_CLASS:
  224.             if (visible) {
  225.                 class_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  226.                 if ((class_flags[index] & 1 << 21) != 0) {
  227.                     class_RVA_bands.incrementAnnoN();
  228.                 } else {
  229.                     class_RVA_bands.newEntryInAnnoN();
  230.                     class_flags[index] = class_flags[index] | 1 << 21;
  231.                 }
  232.             } else {
  233.                 class_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  234.                 if ((class_flags[index] & 1 << 22) != 0) {
  235.                     class_RIA_bands.incrementAnnoN();
  236.                 } else {
  237.                     class_RIA_bands.newEntryInAnnoN();
  238.                     class_flags[index] = class_flags[index] | 1 << 22;
  239.                 }
  240.             }
  241.             break;
  242.         case MetadataBandGroup.CONTEXT_FIELD:
  243.             if (visible) {
  244.                 field_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  245.                 final Long flag = tempFieldFlags.remove(tempFieldFlags.size() - 1);
  246.                 if ((flag.intValue() & 1 << 21) != 0) {
  247.                     field_RVA_bands.incrementAnnoN();
  248.                 } else {
  249.                     field_RVA_bands.newEntryInAnnoN();
  250.                 }
  251.                 tempFieldFlags.add(Long.valueOf(flag.intValue() | 1 << 21));
  252.             } else {
  253.                 field_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  254.                 final Long flag = tempFieldFlags.remove(tempFieldFlags.size() - 1);
  255.                 if ((flag.intValue() & 1 << 22) != 0) {
  256.                     field_RIA_bands.incrementAnnoN();
  257.                 } else {
  258.                     field_RIA_bands.newEntryInAnnoN();
  259.                 }
  260.                 tempFieldFlags.add(Long.valueOf(flag.intValue() | 1 << 22));
  261.             }
  262.             break;
  263.         case MetadataBandGroup.CONTEXT_METHOD:
  264.             if (visible) {
  265.                 method_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  266.                 final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  267.                 if ((flag.intValue() & 1 << 21) != 0) {
  268.                     method_RVA_bands.incrementAnnoN();
  269.                 } else {
  270.                     method_RVA_bands.newEntryInAnnoN();
  271.                 }
  272.                 tempMethodFlags.add(Long.valueOf(flag.intValue() | 1 << 21));
  273.             } else {
  274.                 method_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  275.                 final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  276.                 if ((flag.intValue() & 1 << 22) != 0) {
  277.                     method_RIA_bands.incrementAnnoN();
  278.                 } else {
  279.                     method_RIA_bands.newEntryInAnnoN();
  280.                 }
  281.                 tempMethodFlags.add(Long.valueOf(flag.intValue() | 1 << 22));
  282.             }
  283.             break;
  284.         }
  285.     }

  286.     public void addAnnotationDefault(final List<String> nameRU, final List<String> tags, final List<Object> values, final List<Integer> caseArrayN,
  287.             final List<String> nestTypeRS, final List<String> nestNameRU, final List<Integer> nestPairN) {
  288.         method_AD_bands.addAnnotation(null, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  289.         final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  290.         tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 25));
  291.     }

  292.     public void addClass(final int major, final int flags, final String className, final String signature, final String superName, final String[] interfaces) {
  293.         class_this[index] = cpBands.getCPClass(className);
  294.         class_super[index] = cpBands.getCPClass(superName);
  295.         class_interface_count[index] = interfaces.length;
  296.         class_interface[index] = new CPClass[interfaces.length];
  297.         Arrays.setAll(class_interface[index], i -> cpBands.getCPClass(interfaces[i]));
  298.         major_versions[index] = major;
  299.         class_flags[index] = flags;
  300.         if (!anySyntheticClasses && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
  301.             cpBands.addCPUtf8("Synthetic");
  302.             anySyntheticClasses = true;
  303.         }
  304. //        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
  305. //            flags &= ~Opcodes.ACC_DEPRECATED;
  306. //            flags |= (1 << 20);
  307. //        }
  308.         if (signature != null) {
  309.             class_flags[index] |= 1 << 19;
  310.             classSignature.add(cpBands.getCPSignature(signature));
  311.         }
  312.     }

  313.     public void addClassAttribute(final NewAttribute attribute) {
  314.         // TODO: backwards calls
  315.         final String attributeName = attribute.type;
  316.         for (final NewAttributeBands bands : classAttributeBands) {
  317.             if (bands.getAttributeName().equals(attributeName)) {
  318.                 bands.addAttribute(attribute);
  319.                 final int flagIndex = bands.getFlagIndex();
  320.                 class_flags[index] |= 1 << flagIndex;
  321.                 return;
  322.             }
  323.         }
  324.         throw new IllegalArgumentException("No suitable definition for " + attributeName);
  325.     }

  326.     public void addCode() {
  327.         codeHandlerCount.add(0);
  328.         if (!stripDebug) {
  329.             codeFlags.add(Long.valueOf(1 << 2));
  330.             codeLocalVariableTableN.add(0);
  331.         }
  332.     }

  333.     public void addCodeAttribute(final NewAttribute attribute) {
  334.         final String attributeName = attribute.type;
  335.         for (final NewAttributeBands bands : codeAttributeBands) {
  336.             if (bands.getAttributeName().equals(attributeName)) {
  337.                 bands.addAttribute(attribute);
  338.                 final int flagIndex = bands.getFlagIndex();
  339.                 final Long flags = codeFlags.remove(codeFlags.size() - 1);
  340.                 codeFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
  341.                 return;
  342.             }
  343.         }
  344.         throw new IllegalArgumentException("No suitable definition for " + attributeName);
  345.     }

  346.     public void addEnclosingMethod(final String owner, final String name, final String desc) {
  347.         class_flags[index] |= 1 << 18;
  348.         classEnclosingMethodClass.add(cpBands.getCPClass(owner));
  349.         classEnclosingMethodDesc.add(name == null ? null : cpBands.getCPNameAndType(name, desc));
  350.     }

  351.     public void addField(int flags, final String name, final String desc, final String signature, final Object value) {
  352.         flags &= 0xFFFF;
  353.         tempFieldDesc.add(cpBands.getCPNameAndType(name, desc));
  354.         if (signature != null) {
  355.             fieldSignature.add(cpBands.getCPSignature(signature));
  356.             flags |= 1 << 19;
  357.         }
  358.         if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
  359.             flags &= ~Opcodes.ACC_DEPRECATED;
  360.             flags |= 1 << 20;
  361.         }
  362.         if (value != null) {
  363.             fieldConstantValueKQ.add(cpBands.getConstant(value));
  364.             flags |= 1 << 17;
  365.         }
  366.         if (!anySyntheticFields && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
  367.             cpBands.addCPUtf8("Synthetic");
  368.             anySyntheticFields = true;
  369.         }
  370.         tempFieldFlags.add(Long.valueOf(flags));
  371.     }

  372.     public void addFieldAttribute(final NewAttribute attribute) {
  373.         final String attributeName = attribute.type;
  374.         for (final NewAttributeBands bands : fieldAttributeBands) {
  375.             if (bands.getAttributeName().equals(attributeName)) {
  376.                 bands.addAttribute(attribute);
  377.                 final int flagIndex = bands.getFlagIndex();
  378.                 final Long flags = tempFieldFlags.remove(tempFieldFlags.size() - 1);
  379.                 tempFieldFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
  380.                 return;
  381.             }
  382.         }
  383.         throw new IllegalArgumentException("No suitable definition for " + attributeName);
  384.     }

  385.     public void addHandler(final Label start, final Label end, final Label handler, final String type) {
  386.         final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
  387.         codeHandlerCount.add(handlers + 1);
  388.         codeHandlerStartP.add(start);
  389.         codeHandlerEndPO.add(end);
  390.         codeHandlerCatchPO.add(handler);
  391.         codeHandlerClass.add(type == null ? null : cpBands.getCPClass(type));
  392.     }

  393.     public void addLineNumber(final int line, final Label start) {
  394.         final Long latestCodeFlag = codeFlags.get(codeFlags.size() - 1);
  395.         if ((latestCodeFlag.intValue() & 1 << 1) == 0) {
  396.             codeFlags.remove(codeFlags.size() - 1);
  397.             codeFlags.add(Long.valueOf(latestCodeFlag.intValue() | 1 << 1));
  398.             codeLineNumberTableN.add(1);
  399.         } else {
  400.             codeLineNumberTableN.increment(codeLineNumberTableN.size() - 1);
  401.         }
  402.         codeLineNumberTableLine.add(line);
  403.         codeLineNumberTableBciP.add(start);
  404.     }

  405.     public void addLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int indx) {
  406.         if (signature != null) { // LocalVariableTypeTable attribute
  407.             final Long latestCodeFlag = codeFlags.get(codeFlags.size() - 1);
  408.             if ((latestCodeFlag.intValue() & 1 << 3) == 0) {
  409.                 codeFlags.remove(codeFlags.size() - 1);
  410.                 codeFlags.add(Long.valueOf(latestCodeFlag.intValue() | 1 << 3));
  411.                 codeLocalVariableTypeTableN.add(1);
  412.             } else {
  413.                 codeLocalVariableTypeTableN.increment(codeLocalVariableTypeTableN.size() - 1);
  414.             }
  415.             codeLocalVariableTypeTableBciP.add(start);
  416.             codeLocalVariableTypeTableSpanO.add(end);
  417.             codeLocalVariableTypeTableNameRU.add(cpBands.getCPUtf8(name));
  418.             codeLocalVariableTypeTableTypeRS.add(cpBands.getCPSignature(signature));
  419.             codeLocalVariableTypeTableSlot.add(indx);
  420.         }
  421.         // LocalVariableTable attribute
  422.         codeLocalVariableTableN.increment(codeLocalVariableTableN.size() - 1);
  423.         codeLocalVariableTableBciP.add(start);
  424.         codeLocalVariableTableSpanO.add(end);
  425.         codeLocalVariableTableNameRU.add(cpBands.getCPUtf8(name));
  426.         codeLocalVariableTableTypeRS.add(cpBands.getCPSignature(desc));
  427.         codeLocalVariableTableSlot.add(indx);
  428.     }

  429.     public void addMaxStack(final int maxStack, int maxLocals) {
  430.         final Long latestFlag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  431.         final Long newFlag = Long.valueOf(latestFlag.intValue() | 1 << 17);
  432.         tempMethodFlags.add(newFlag);
  433.         codeMaxStack.add(maxStack);
  434.         if ((newFlag.longValue() & 1 << 3) == 0) { // not static
  435.             maxLocals--; // minus 'this' local
  436.         }
  437.         maxLocals -= numMethodArgs;
  438.         codeMaxLocals.add(maxLocals);
  439.     }

  440.     public void addMethod(int flags, final String name, final String desc, final String signature, final String[] exceptions) {
  441.         final CPNameAndType nt = cpBands.getCPNameAndType(name, desc);
  442.         tempMethodDesc.add(nt);
  443.         if (signature != null) {
  444.             methodSignature.add(cpBands.getCPSignature(signature));
  445.             flags |= 1 << 19;
  446.         }
  447.         if (exceptions != null) {
  448.             methodExceptionNumber.add(exceptions.length);
  449.             for (final String exception : exceptions) {
  450.                 methodExceptionClasses.add(cpBands.getCPClass(exception));
  451.             }
  452.             flags |= 1 << 18;
  453.         }
  454.         if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
  455.             flags &= ~Opcodes.ACC_DEPRECATED;
  456.             flags |= 1 << 20;
  457.         }
  458.         tempMethodFlags.add(Long.valueOf(flags));
  459.         numMethodArgs = countArgs(desc);
  460.         if (!anySyntheticMethods && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
  461.             cpBands.addCPUtf8("Synthetic");
  462.             anySyntheticMethods = true;
  463.         }
  464.     }

  465.     public void addMethodAttribute(final NewAttribute attribute) {
  466.         final String attributeName = attribute.type;
  467.         for (final NewAttributeBands bands : methodAttributeBands) {
  468.             if (bands.getAttributeName().equals(attributeName)) {
  469.                 bands.addAttribute(attribute);
  470.                 final int flagIndex = bands.getFlagIndex();
  471.                 final Long flags = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  472.                 tempMethodFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
  473.                 return;
  474.             }
  475.         }
  476.         throw new IllegalArgumentException("No suitable definition for " + attributeName);
  477.     }

  478.     public void addParameterAnnotation(final int parameter, final String desc, final boolean visible, final List<String> nameRU, final List<String> tags,
  479.             final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
  480.             final List<Integer> nestPairN) {
  481.         if (visible) {
  482.             if (tempMethodRVPA == null) {
  483.                 tempMethodRVPA = new TempParamAnnotation(numMethodArgs);
  484.                 tempMethodRVPA.addParameterAnnotation(parameter, desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  485.             }
  486.             final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  487.             tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 23));
  488.         } else {
  489.             if (tempMethodRIPA == null) {
  490.                 tempMethodRIPA = new TempParamAnnotation(numMethodArgs);
  491.                 tempMethodRIPA.addParameterAnnotation(parameter, desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
  492.             }
  493.             final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
  494.             tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 24));
  495.         }
  496.     }

  497.     public void addSourceFile(final String source) {
  498.         String implicitSourceFileName = class_this[index].toString();
  499.         if (implicitSourceFileName.indexOf('$') != -1) {
  500.             implicitSourceFileName = implicitSourceFileName.substring(0, implicitSourceFileName.indexOf('$'));
  501.         }
  502.         implicitSourceFileName = implicitSourceFileName.substring(implicitSourceFileName.lastIndexOf('/') + 1) + ".java";
  503.         if (source.equals(implicitSourceFileName)) {
  504.             classSourceFile.add(null);
  505.         } else {
  506.             classSourceFile.add(cpBands.getCPUtf8(source));
  507.         }
  508.         class_flags[index] |= 1 << 17;
  509.     }

  510.     private void createNewAttributeBands() throws IOException {
  511.         for (final AttributeDefinition def : attrBands.getClassAttributeLayouts()) {
  512.             classAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
  513.         }
  514.         for (final AttributeDefinition def : attrBands.getMethodAttributeLayouts()) {
  515.             methodAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
  516.         }
  517.         for (final AttributeDefinition def : attrBands.getFieldAttributeLayouts()) {
  518.             fieldAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
  519.         }
  520.         for (final AttributeDefinition def : attrBands.getCodeAttributeLayouts()) {
  521.             codeAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
  522.         }
  523.     }

  524.     public void currentClassReferencesInnerClass(final CPClass inner) {
  525.         if (!(index >= class_this.length)) {
  526.             final CPClass currentClass = class_this[index];
  527.             if (currentClass != null && !currentClass.equals(inner) && !isInnerClassOf(currentClass.toString(), inner)) {
  528.                 classReferencesInnerClass.computeIfAbsent(currentClass, c -> new HashSet<>()).add(inner);
  529.             }
  530.         }
  531.     }

  532.     public void doBciRenumbering(final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
  533.         renumberBci(codeLineNumberTableBciP, bciRenumbering, labelsToOffsets);
  534.         renumberBci(codeLocalVariableTableBciP, bciRenumbering, labelsToOffsets);
  535.         renumberOffsetBci(codeLocalVariableTableBciP, codeLocalVariableTableSpanO, bciRenumbering, labelsToOffsets);
  536.         renumberBci(codeLocalVariableTypeTableBciP, bciRenumbering, labelsToOffsets);
  537.         renumberOffsetBci(codeLocalVariableTypeTableBciP, codeLocalVariableTypeTableSpanO, bciRenumbering, labelsToOffsets);
  538.         renumberBci(codeHandlerStartP, bciRenumbering, labelsToOffsets);
  539.         renumberOffsetBci(codeHandlerStartP, codeHandlerEndPO, bciRenumbering, labelsToOffsets);
  540.         renumberDoubleOffsetBci(codeHandlerStartP, codeHandlerEndPO, codeHandlerCatchPO, bciRenumbering, labelsToOffsets);

  541.         for (final NewAttributeBands newAttributeBandSet : classAttributeBands) {
  542.             newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
  543.         }
  544.         for (final NewAttributeBands newAttributeBandSet : methodAttributeBands) {
  545.             newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
  546.         }
  547.         for (final NewAttributeBands newAttributeBandSet : fieldAttributeBands) {
  548.             newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
  549.         }
  550.         for (final NewAttributeBands newAttributeBandSet : codeAttributeBands) {
  551.             newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
  552.         }
  553.     }

  554.     public void endOfClass() { // All the data for the current class has been
  555.                                // read
  556.         final int numFields = tempFieldDesc.size();
  557.         class_field_count[index] = numFields;
  558.         field_descr[index] = new CPNameAndType[numFields];
  559.         field_flags[index] = new long[numFields];
  560.         for (int i = 0; i < numFields; i++) {
  561.             field_descr[index][i] = tempFieldDesc.get(i);
  562.             field_flags[index][i] = tempFieldFlags.get(i).longValue();
  563.         }
  564.         final int numMethods = tempMethodDesc.size();
  565.         class_method_count[index] = numMethods;
  566.         method_descr[index] = new CPNameAndType[numMethods];
  567.         method_flags[index] = new long[numMethods];
  568.         for (int i = 0; i < numMethods; i++) {
  569.             method_descr[index][i] = tempMethodDesc.get(i);
  570.             method_flags[index][i] = tempMethodFlags.get(i).longValue();
  571.         }
  572.         tempFieldDesc.clear();
  573.         tempFieldFlags.clear();
  574.         tempMethodDesc.clear();
  575.         tempMethodFlags.clear();
  576.         index++;
  577.     }

  578.     public void endOfMethod() {
  579.         if (tempMethodRVPA != null) {
  580.             method_RVPA_bands.addParameterAnnotation(tempMethodRVPA.numParams, tempMethodRVPA.annoN, tempMethodRVPA.pairN, tempMethodRVPA.typeRS,
  581.                     tempMethodRVPA.nameRU, tempMethodRVPA.tags, tempMethodRVPA.values, tempMethodRVPA.caseArrayN, tempMethodRVPA.nestTypeRS,
  582.                     tempMethodRVPA.nestNameRU, tempMethodRVPA.nestPairN);
  583.             tempMethodRVPA = null;
  584.         }
  585.         if (tempMethodRIPA != null) {
  586.             method_RIPA_bands.addParameterAnnotation(tempMethodRIPA.numParams, tempMethodRIPA.annoN, tempMethodRIPA.pairN, tempMethodRIPA.typeRS,
  587.                     tempMethodRIPA.nameRU, tempMethodRIPA.tags, tempMethodRIPA.values, tempMethodRIPA.caseArrayN, tempMethodRIPA.nestTypeRS,
  588.                     tempMethodRIPA.nestNameRU, tempMethodRIPA.nestPairN);
  589.             tempMethodRIPA = null;
  590.         }
  591.         if (codeFlags.size() > 0) {
  592.             final long latestCodeFlag = codeFlags.get(codeFlags.size() - 1).longValue();
  593.             final int latestLocalVariableTableN = codeLocalVariableTableN.get(codeLocalVariableTableN.size() - 1);
  594.             if (latestCodeFlag == 1 << 2 && latestLocalVariableTableN == 0) {
  595.                 codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
  596.                 codeFlags.remove(codeFlags.size() - 1);
  597.                 codeFlags.add(Long.valueOf(0));
  598.             }
  599.         }
  600.     }

  601.     /**
  602.      * All input classes for the segment have now been read in, so this method is called so that this class can calculate/complete anything it could not do
  603.      * while classes were being read.
  604.      */
  605.     public void finaliseBands() {
  606.         final int defaultMajorVersion = segmentHeader.getDefaultMajorVersion();
  607.         for (int i = 0; i < class_flags.length; i++) {
  608.             final int major = major_versions[i];
  609.             if (major != defaultMajorVersion) {
  610.                 class_flags[i] |= 1 << 24;
  611.                 classFileVersionMajor.add(major);
  612.                 classFileVersionMinor.add(0);
  613.             }
  614.         }
  615.         // Calculate code headers
  616.         codeHeaders = new int[codeHandlerCount.size()];
  617.         int removed = 0;
  618.         for (int i = 0; i < codeHeaders.length; i++) {
  619.             final int numHandlers = codeHandlerCount.get(i - removed);
  620.             final int maxLocals = codeMaxLocals.get(i - removed);
  621.             final int maxStack = codeMaxStack.get(i - removed);
  622.             switch (numHandlers) {
  623.             case 0: {
  624.                 final int header = maxLocals * 12 + maxStack + 1;
  625.                 if (header < 145 && maxStack < 12) {
  626.                     codeHeaders[i] = header;
  627.                 }
  628.                 break;
  629.             }
  630.             case 1: {
  631.                 final int header = maxLocals * 8 + maxStack + 145;
  632.                 if (header < 209 && maxStack < 8) {
  633.                     codeHeaders[i] = header;
  634.                 }
  635.                 break;
  636.             }
  637.             case 2: {
  638.                 final int header = maxLocals * 7 + maxStack + 209;
  639.                 if (header < 256 && maxStack < 7) {
  640.                     codeHeaders[i] = header;
  641.                 }
  642.                 break;
  643.             }
  644.             default:
  645.                 break;
  646.             }
  647.             if (codeHeaders[i] != 0) { // Remove the redundant values from
  648.                                        // codeHandlerCount, codeMaxLocals and
  649.                                        // codeMaxStack
  650.                 codeHandlerCount.remove(i - removed);
  651.                 codeMaxLocals.remove(i - removed);
  652.                 codeMaxStack.remove(i - removed);
  653.                 removed++;
  654.             } else if (!segment.getSegmentHeader().have_all_code_flags()) {
  655.                 codeFlags.add(Long.valueOf(0));
  656.             }
  657.         }

  658.         // Compute any required IcLocals
  659.         final IntList innerClassesN = new IntList();
  660.         final List<IcTuple> icLocal = new ArrayList<>();
  661.         for (int i = 0; i < class_this.length; i++) {
  662.             final CPClass cpClass = class_this[i];
  663.             final Set<CPClass> referencedInnerClasses = classReferencesInnerClass.get(cpClass);
  664.             if (referencedInnerClasses != null) {
  665.                 int innerN = 0;
  666.                 final List<IcTuple> innerClasses = segment.getIcBands().getInnerClassesForOuter(cpClass.toString());
  667.                 if (innerClasses != null) {
  668.                     for (final IcTuple element : innerClasses) {
  669.                         referencedInnerClasses.remove(element.C);
  670.                     }
  671.                 }
  672.                 for (final CPClass inner : referencedInnerClasses) {
  673.                     final IcTuple icTuple = segment.getIcBands().getIcTuple(inner);
  674.                     if (icTuple != null && !icTuple.isAnonymous()) {
  675.                         // should transmit an icLocal entry
  676.                         icLocal.add(icTuple);
  677.                         innerN++;
  678.                     }
  679.                 }
  680.                 if (innerN != 0) {
  681.                     innerClassesN.add(innerN);
  682.                     class_flags[i] |= 1 << 23;
  683.                 }
  684.             }
  685.         }
  686.         class_InnerClasses_N = innerClassesN.toArray();
  687.         class_InnerClasses_RC = new CPClass[icLocal.size()];
  688.         class_InnerClasses_F = new int[icLocal.size()];
  689.         classInnerClassesOuterRCN = new ArrayList<>();
  690.         classInnerClassesNameRUN = new ArrayList<>();
  691.         for (int i = 0; i < class_InnerClasses_RC.length; i++) {
  692.             final IcTuple icTuple = icLocal.get(i);
  693.             class_InnerClasses_RC[i] = icTuple.C;
  694.             if (icTuple.C2 == null && icTuple.N == null) {
  695.                 class_InnerClasses_F[i] = 0;
  696.             } else {
  697.                 if (icTuple.F == 0) {
  698.                     class_InnerClasses_F[i] = 0x00010000;
  699.                 } else {
  700.                     class_InnerClasses_F[i] = icTuple.F;
  701.                 }
  702.                 classInnerClassesOuterRCN.add(icTuple.C2);
  703.                 classInnerClassesNameRUN.add(icTuple.N);
  704.             }
  705.         }
  706.         // Calculate any backwards calls from metadata bands
  707.         final IntList classAttrCalls = new IntList();
  708.         final IntList fieldAttrCalls = new IntList();
  709.         final IntList methodAttrCalls = new IntList();
  710.         final IntList codeAttrCalls = new IntList();

  711.         if (class_RVA_bands.hasContent()) {
  712.             classAttrCalls.add(class_RVA_bands.numBackwardsCalls());
  713.         }
  714.         if (class_RIA_bands.hasContent()) {
  715.             classAttrCalls.add(class_RIA_bands.numBackwardsCalls());
  716.         }
  717.         if (field_RVA_bands.hasContent()) {
  718.             fieldAttrCalls.add(field_RVA_bands.numBackwardsCalls());
  719.         }
  720.         if (field_RIA_bands.hasContent()) {
  721.             fieldAttrCalls.add(field_RIA_bands.numBackwardsCalls());
  722.         }
  723.         if (method_RVA_bands.hasContent()) {
  724.             methodAttrCalls.add(method_RVA_bands.numBackwardsCalls());
  725.         }
  726.         if (method_RIA_bands.hasContent()) {
  727.             methodAttrCalls.add(method_RIA_bands.numBackwardsCalls());
  728.         }
  729.         if (method_RVPA_bands.hasContent()) {
  730.             methodAttrCalls.add(method_RVPA_bands.numBackwardsCalls());
  731.         }
  732.         if (method_RIPA_bands.hasContent()) {
  733.             methodAttrCalls.add(method_RIPA_bands.numBackwardsCalls());
  734.         }
  735.         if (method_AD_bands.hasContent()) {
  736.             methodAttrCalls.add(method_AD_bands.numBackwardsCalls());
  737.         }

  738.         // Sort non-predefined attribute bands
  739.         final Comparator<NewAttributeBands> comparator = (arg0, arg1) -> arg0.getFlagIndex() - arg1.getFlagIndex();
  740.         classAttributeBands.sort(comparator);
  741.         methodAttributeBands.sort(comparator);
  742.         fieldAttributeBands.sort(comparator);
  743.         codeAttributeBands.sort(comparator);

  744.         for (final NewAttributeBands bands : classAttributeBands) {
  745.             if (bands.isUsedAtLeastOnce()) {
  746.                 for (final int backwardsCallCount : bands.numBackwardsCalls()) {
  747.                     classAttrCalls.add(backwardsCallCount);
  748.                 }
  749.             }
  750.         }
  751.         for (final NewAttributeBands bands : methodAttributeBands) {
  752.             if (bands.isUsedAtLeastOnce()) {
  753.                 for (final int backwardsCallCount : bands.numBackwardsCalls()) {
  754.                     methodAttrCalls.add(backwardsCallCount);
  755.                 }
  756.             }
  757.         }
  758.         for (final NewAttributeBands bands : fieldAttributeBands) {
  759.             if (bands.isUsedAtLeastOnce()) {
  760.                 for (final int backwardsCallCount : bands.numBackwardsCalls()) {
  761.                     fieldAttrCalls.add(backwardsCallCount);
  762.                 }
  763.             }
  764.         }
  765.         for (final NewAttributeBands bands : codeAttributeBands) {
  766.             if (bands.isUsedAtLeastOnce()) {
  767.                 for (final int backwardsCallCount : bands.numBackwardsCalls()) {
  768.                     codeAttrCalls.add(backwardsCallCount);
  769.                 }
  770.             }
  771.         }

  772.         class_attr_calls = classAttrCalls.toArray();
  773.         field_attr_calls = fieldAttrCalls.toArray();
  774.         method_attr_calls = methodAttrCalls.toArray();
  775.         code_attr_calls = codeAttrCalls.toArray();
  776.     }

  777.     private int[] getInts(final CPClass[] cpClasses) {
  778.         final int[] ints = new int[cpClasses.length];
  779.         for (int i = 0; i < ints.length; i++) {
  780.             if (cpClasses[i] != null) {
  781.                 ints[i] = cpClasses[i].getIndex();
  782.             }
  783.         }
  784.         return ints;
  785.     }

  786.     public boolean isAnySyntheticClasses() {
  787.         return anySyntheticClasses;
  788.     }

  789.     public boolean isAnySyntheticFields() {
  790.         return anySyntheticFields;
  791.     }

  792.     public boolean isAnySyntheticMethods() {
  793.         return anySyntheticMethods;
  794.     }

  795.     private boolean isInnerClass(final String possibleInner) {
  796.         return possibleInner.indexOf('$') != -1;
  797.     }

  798.     private boolean isInnerClassOf(final String possibleInner, final CPClass possibleOuter) {
  799.         if (isInnerClass(possibleInner)) {
  800.             final String superClassName = possibleInner.substring(0, possibleInner.lastIndexOf('$'));
  801.             if (superClassName.equals(possibleOuter.toString())) {
  802.                 return true;
  803.             }
  804.             return isInnerClassOf(superClassName, possibleOuter);
  805.         }
  806.         return false;
  807.     }

  808.     public int numClassesProcessed() {
  809.         return index;
  810.     }

  811.     @Override
  812.     public void pack(final OutputStream out) throws IOException, Pack200Exception {
  813.         PackingUtils.log("Writing class bands...");

  814.         byte[] encodedBand = encodeBandInt("class_this", getInts(class_this), Codec.DELTA5);
  815.         out.write(encodedBand);
  816.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_this[" + class_this.length + "]");

  817.         encodedBand = encodeBandInt("class_super", getInts(class_super), Codec.DELTA5);
  818.         out.write(encodedBand);
  819.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_super[" + class_super.length + "]");

  820.         encodedBand = encodeBandInt("class_interface_count", class_interface_count, Codec.DELTA5);
  821.         out.write(encodedBand);
  822.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface_count[" + class_interface_count.length + "]");

  823.         final int totalInterfaces = sum(class_interface_count);
  824.         final int[] classInterface = new int[totalInterfaces];
  825.         int k = 0;
  826.         for (final CPClass[] element : class_interface) {
  827.             if (element != null) {
  828.                 for (final CPClass cpClass : element) {
  829.                     classInterface[k] = cpClass.getIndex();
  830.                     k++;
  831.                 }
  832.             }
  833.         }

  834.         encodedBand = encodeBandInt("class_interface", classInterface, Codec.DELTA5);
  835.         out.write(encodedBand);
  836.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface[" + classInterface.length + "]");

  837.         encodedBand = encodeBandInt("class_field_count", class_field_count, Codec.DELTA5);
  838.         out.write(encodedBand);
  839.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_field_count[" + class_field_count.length + "]");

  840.         encodedBand = encodeBandInt("class_method_count", class_method_count, Codec.DELTA5);
  841.         out.write(encodedBand);
  842.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_method_count[" + class_method_count.length + "]");

  843.         final int totalFields = sum(class_field_count);
  844.         final int[] fieldDescr = new int[totalFields];
  845.         k = 0;
  846.         for (int i = 0; i < index; i++) {
  847.             for (int j = 0; j < field_descr[i].length; j++) {
  848.                 final CPNameAndType descr = field_descr[i][j];
  849.                 fieldDescr[k] = descr.getIndex();
  850.                 k++;
  851.             }
  852.         }

  853.         encodedBand = encodeBandInt("field_descr", fieldDescr, Codec.DELTA5);
  854.         out.write(encodedBand);
  855.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_descr[" + fieldDescr.length + "]");

  856.         writeFieldAttributeBands(out);

  857.         final int totalMethods = sum(class_method_count);
  858.         final int[] methodDescr = new int[totalMethods];
  859.         k = 0;
  860.         for (int i = 0; i < index; i++) {
  861.             for (int j = 0; j < method_descr[i].length; j++) {
  862.                 final CPNameAndType descr = method_descr[i][j];
  863.                 methodDescr[k] = descr.getIndex();
  864.                 k++;
  865.             }
  866.         }

  867.         encodedBand = encodeBandInt("method_descr", methodDescr, Codec.MDELTA5);
  868.         out.write(encodedBand);
  869.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_descr[" + methodDescr.length + "]");

  870.         writeMethodAttributeBands(out);
  871.         writeClassAttributeBands(out);
  872.         writeCodeBands(out);
  873.     }

  874.     /**
  875.      * Remove all entries for the current class
  876.      */
  877.     public void removeCurrentClass() {
  878.         // Note - this doesn't remove any entries added to the constant pool but
  879.         // that shouldn't be a problem
  880.         if ((class_flags[index] & 1 << 17) != 0) {
  881.             classSourceFile.remove(classSourceFile.size() - 1);
  882.         }
  883.         if ((class_flags[index] & 1 << 18) != 0) {
  884.             classEnclosingMethodClass.remove(classEnclosingMethodClass.size() - 1);
  885.             classEnclosingMethodDesc.remove(classEnclosingMethodDesc.size() - 1);
  886.         }
  887.         if ((class_flags[index] & 1 << 19) != 0) {
  888.             classSignature.remove(classSignature.size() - 1);
  889.         }
  890.         if ((class_flags[index] & 1 << 21) != 0) {
  891.             class_RVA_bands.removeLatest();
  892.         }
  893.         if ((class_flags[index] & 1 << 22) != 0) {
  894.             class_RIA_bands.removeLatest();
  895.         }
  896.         for (final Long flagsL : tempFieldFlags) {
  897.             final long flags = flagsL.longValue();
  898.             if ((flags & 1 << 19) != 0) {
  899.                 fieldSignature.remove(fieldSignature.size() - 1);
  900.             }
  901.             if ((flags & 1 << 17) != 0) {
  902.                 fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1);
  903.             }
  904.             if ((flags & 1 << 21) != 0) {
  905.                 field_RVA_bands.removeLatest();
  906.             }
  907.             if ((flags & 1 << 22) != 0) {
  908.                 field_RIA_bands.removeLatest();
  909.             }
  910.         }
  911.         for (final Long flagsL : tempMethodFlags) {
  912.             final long flags = flagsL.longValue();
  913.             if ((flags & 1 << 19) != 0) {
  914.                 methodSignature.remove(methodSignature.size() - 1);
  915.             }
  916.             if ((flags & 1 << 18) != 0) {
  917.                 final int exceptions = methodExceptionNumber.remove(methodExceptionNumber.size() - 1);
  918.                 for (int i = 0; i < exceptions; i++) {
  919.                     methodExceptionClasses.remove(methodExceptionClasses.size() - 1);
  920.                 }
  921.             }
  922.             if ((flags & 1 << 17) != 0) { // has code attribute
  923.                 codeMaxLocals.remove(codeMaxLocals.size() - 1);
  924.                 codeMaxStack.remove(codeMaxStack.size() - 1);
  925.                 final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
  926.                 for (int i = 0; i < handlers; i++) {
  927.                     final int index = codeHandlerStartP.size() - 1;
  928.                     codeHandlerStartP.remove(index);
  929.                     codeHandlerEndPO.remove(index);
  930.                     codeHandlerCatchPO.remove(index);
  931.                     codeHandlerClass.remove(index);
  932.                 }
  933.                 if (!stripDebug) {
  934.                     final long cdeFlags = codeFlags.remove(codeFlags.size() - 1).longValue();
  935.                     final int numLocalVariables = codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
  936.                     for (int i = 0; i < numLocalVariables; i++) {
  937.                         final int location = codeLocalVariableTableBciP.size() - 1;
  938.                         codeLocalVariableTableBciP.remove(location);
  939.                         codeLocalVariableTableSpanO.remove(location);
  940.                         codeLocalVariableTableNameRU.remove(location);
  941.                         codeLocalVariableTableTypeRS.remove(location);
  942.                         codeLocalVariableTableSlot.remove(location);
  943.                     }
  944.                     if ((cdeFlags & 1 << 3) != 0) {
  945.                         final int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN.remove(codeLocalVariableTypeTableN.size() - 1);
  946.                         for (int i = 0; i < numLocalVariablesInTypeTable; i++) {
  947.                             final int location = codeLocalVariableTypeTableBciP.size() - 1;
  948.                             codeLocalVariableTypeTableBciP.remove(location);
  949.                             codeLocalVariableTypeTableSpanO.remove(location);
  950.                             codeLocalVariableTypeTableNameRU.remove(location);
  951.                             codeLocalVariableTypeTableTypeRS.remove(location);
  952.                             codeLocalVariableTypeTableSlot.remove(location);
  953.                         }
  954.                     }
  955.                     if ((cdeFlags & 1 << 1) != 0) {
  956.                         final int numLineNumbers = codeLineNumberTableN.remove(codeLineNumberTableN.size() - 1);
  957.                         for (int i = 0; i < numLineNumbers; i++) {
  958.                             final int location = codeLineNumberTableBciP.size() - 1;
  959.                             codeLineNumberTableBciP.remove(location);
  960.                             codeLineNumberTableLine.remove(location);
  961.                         }
  962.                     }
  963.                 }
  964.             }
  965.             if ((flags & 1 << 21) != 0) {
  966.                 method_RVA_bands.removeLatest();
  967.             }
  968.             if ((flags & 1 << 22) != 0) {
  969.                 method_RIA_bands.removeLatest();
  970.             }
  971.             if ((flags & 1 << 23) != 0) {
  972.                 method_RVPA_bands.removeLatest();
  973.             }
  974.             if ((flags & 1 << 24) != 0) {
  975.                 method_RIPA_bands.removeLatest();
  976.             }
  977.             if ((flags & 1 << 25) != 0) {
  978.                 method_AD_bands.removeLatest();
  979.             }
  980.         }
  981.         class_this[index] = null;
  982.         class_super[index] = null;
  983.         class_interface_count[index] = 0;
  984.         class_interface[index] = null;
  985.         major_versions[index] = 0;
  986.         class_flags[index] = 0;
  987.         tempFieldDesc.clear();
  988.         tempFieldFlags.clear();
  989.         tempMethodDesc.clear();
  990.         tempMethodFlags.clear();
  991.         if (index > 0) {
  992.             index--;
  993.         }
  994.     }

  995.     private void renumberBci(final List<Integer> list, final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
  996.         for (int i = list.size() - 1; i >= 0; i--) {
  997.             final Object label = list.get(i);
  998.             if (label instanceof Integer) {
  999.                 break;
  1000.             }
  1001.             if (label instanceof Label) {
  1002.                 list.remove(i);
  1003.                 final Integer bytecodeIndex = labelsToOffsets.get(label);
  1004.                 list.add(i, Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue())));
  1005.             }
  1006.         }
  1007.     }

  1008.     private void renumberDoubleOffsetBci(final List<Integer> relative, final List<Integer> firstOffset, final List<Object> list, final IntList bciRenumbering,
  1009.             final Map<Label, Integer> labelsToOffsets) {
  1010.         // TODO: There's probably a nicer way of doing this...
  1011.         for (int i = list.size() - 1; i >= 0; i--) {
  1012.             final Object label = list.get(i);
  1013.             if (label instanceof Integer) {
  1014.                 break;
  1015.             }
  1016.             if (label instanceof Label) {
  1017.                 list.remove(i);
  1018.                 final Integer bytecodeIndex = labelsToOffsets.get(label);
  1019.                 final Integer renumberedOffset = Integer
  1020.                         .valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue() - firstOffset.get(i).intValue());
  1021.                 list.add(i, renumberedOffset);
  1022.             }
  1023.         }
  1024.     }

  1025.     private void renumberOffsetBci(final List<Integer> relative, final List<Integer> list, final IntList bciRenumbering,
  1026.             final Map<Label, Integer> labelsToOffsets) {
  1027.         for (int i = list.size() - 1; i >= 0; i--) {
  1028.             final Object label = list.get(i);
  1029.             if (label instanceof Integer) {
  1030.                 break;
  1031.             }
  1032.             if (label instanceof Label) {
  1033.                 list.remove(i);
  1034.                 final Integer bytecodeIndex = labelsToOffsets.get(label);
  1035.                 final Integer renumberedOffset = Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue());
  1036.                 list.add(i, renumberedOffset);
  1037.             }
  1038.         }
  1039.     }

  1040.     private int sum(final int[] ints) {
  1041.         int sum = 0;
  1042.         for (final int j : ints) {
  1043.             sum += j;
  1044.         }
  1045.         return sum;
  1046.     }

  1047.     private void writeClassAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
  1048.         byte[] encodedBand = encodeFlags("class_flags", class_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_class_flags_hi());
  1049.         out.write(encodedBand);
  1050.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_flags[" + class_flags.length + "]");

  1051.         // These bands are not needed, but could be used to reduce the size of
  1052.         // the archive if there are enough different non-standard attributes
  1053.         // defined that segmentHeader.have_class_flags_hi() is true. The same
  1054.         // applies to method_attr_count, field_attr_count, code_attr_count etc.

  1055.         // *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
  1056.         // *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]

  1057.         encodedBand = encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5);
  1058.         out.write(encodedBand);
  1059.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_attr_calls[" + class_attr_calls.length + "]");

  1060.         encodedBand = encodeBandInt("classSourceFile", cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5);
  1061.         out.write(encodedBand);
  1062.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from classSourceFile[" + classSourceFile.size() + "]");

  1063.         encodedBand = encodeBandInt("class_enclosing_method_RC", cpEntryListToArray(classEnclosingMethodClass), Codec.UNSIGNED5);
  1064.         out.write(encodedBand);
  1065.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_enclosing_method_RC[" + classEnclosingMethodClass.size() + "]");

  1066.         encodedBand = encodeBandInt("class_EnclosingMethod_RDN", cpEntryOrNullListToArray(classEnclosingMethodDesc), Codec.UNSIGNED5);
  1067.         out.write(encodedBand);
  1068.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_EnclosingMethod_RDN[" + classEnclosingMethodDesc.size() + "]");

  1069.         encodedBand = encodeBandInt("class_Signature_RS", cpEntryListToArray(classSignature), Codec.UNSIGNED5);
  1070.         out.write(encodedBand);
  1071.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_Signature_RS[" + classSignature.size() + "]");

  1072.         class_RVA_bands.pack(out);
  1073.         class_RIA_bands.pack(out);

  1074.         encodedBand = encodeBandInt("class_InnerClasses_N", class_InnerClasses_N, Codec.UNSIGNED5);
  1075.         out.write(encodedBand);
  1076.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_N[" + class_InnerClasses_N.length + "]");

  1077.         encodedBand = encodeBandInt("class_InnerClasses_RC", getInts(class_InnerClasses_RC), Codec.UNSIGNED5);
  1078.         out.write(encodedBand);
  1079.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_RC[" + class_InnerClasses_RC.length + "]");

  1080.         encodedBand = encodeBandInt("class_InnerClasses_F", class_InnerClasses_F, Codec.UNSIGNED5);
  1081.         out.write(encodedBand);
  1082.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_F[" + class_InnerClasses_F.length + "]");

  1083.         encodedBand = encodeBandInt("class_InnerClasses_outer_RCN", cpEntryOrNullListToArray(classInnerClassesOuterRCN), Codec.UNSIGNED5);
  1084.         out.write(encodedBand);
  1085.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_outer_RCN[" + classInnerClassesOuterRCN.size() + "]");

  1086.         encodedBand = encodeBandInt("class_InnerClasses_name_RUN", cpEntryOrNullListToArray(classInnerClassesNameRUN), Codec.UNSIGNED5);
  1087.         out.write(encodedBand);
  1088.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_name_RUN[" + classInnerClassesNameRUN.size() + "]");

  1089.         encodedBand = encodeBandInt("classFileVersionMinor", classFileVersionMinor.toArray(), Codec.UNSIGNED5);
  1090.         out.write(encodedBand);
  1091.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMinor[" + classFileVersionMinor.size() + "]");

  1092.         encodedBand = encodeBandInt("classFileVersionMajor", classFileVersionMajor.toArray(), Codec.UNSIGNED5);
  1093.         out.write(encodedBand);
  1094.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMajor[" + classFileVersionMajor.size() + "]");

  1095.         for (final NewAttributeBands classAttributeBand : classAttributeBands) {
  1096.             classAttributeBand.pack(out);
  1097.         }
  1098.     }

  1099.     private void writeCodeAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
  1100.         byte[] encodedBand = encodeFlags("codeFlags", longListToArray(codeFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_code_flags_hi());
  1101.         out.write(encodedBand);
  1102.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeFlags[" + codeFlags.size() + "]");

  1103.         // *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
  1104.         // *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
  1105.         encodedBand = encodeBandInt("code_attr_calls", code_attr_calls, Codec.UNSIGNED5);
  1106.         out.write(encodedBand);
  1107.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_attr_calls[" + code_attr_calls.length + "]");

  1108.         encodedBand = encodeBandInt("code_LineNumberTable_N", codeLineNumberTableN.toArray(), Codec.UNSIGNED5);
  1109.         out.write(encodedBand);
  1110.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_N[" + codeLineNumberTableN.size() + "]");

  1111.         encodedBand = encodeBandInt("code_LineNumberTable_bci_P", integerListToArray(codeLineNumberTableBciP), Codec.BCI5);
  1112.         out.write(encodedBand);
  1113.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_bci_P[" + codeLineNumberTableBciP.size() + "]");

  1114.         encodedBand = encodeBandInt("code_LineNumberTable_line", codeLineNumberTableLine.toArray(), Codec.UNSIGNED5);
  1115.         out.write(encodedBand);
  1116.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_line[" + codeLineNumberTableLine.size() + "]");

  1117.         encodedBand = encodeBandInt("code_LocalVariableTable_N", codeLocalVariableTableN.toArray(), Codec.UNSIGNED5);
  1118.         out.write(encodedBand);
  1119.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_N[" + codeLocalVariableTableN.size() + "]");

  1120.         encodedBand = encodeBandInt("code_LocalVariableTable_bci_P", integerListToArray(codeLocalVariableTableBciP), Codec.BCI5);
  1121.         out.write(encodedBand);
  1122.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_bci_P[" + codeLocalVariableTableBciP.size() + "]");

  1123.         encodedBand = encodeBandInt("code_LocalVariableTable_span_O", integerListToArray(codeLocalVariableTableSpanO), Codec.BRANCH5);
  1124.         out.write(encodedBand);
  1125.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_span_O[" + codeLocalVariableTableSpanO.size() + "]");

  1126.         encodedBand = encodeBandInt("code_LocalVariableTable_name_RU", cpEntryListToArray(codeLocalVariableTableNameRU), Codec.UNSIGNED5);
  1127.         out.write(encodedBand);
  1128.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_name_RU[" + codeLocalVariableTableNameRU.size() + "]");

  1129.         encodedBand = encodeBandInt("code_LocalVariableTable_type_RS", cpEntryListToArray(codeLocalVariableTableTypeRS), Codec.UNSIGNED5);
  1130.         out.write(encodedBand);
  1131.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_type_RS[" + codeLocalVariableTableTypeRS.size() + "]");

  1132.         encodedBand = encodeBandInt("code_LocalVariableTable_slot", codeLocalVariableTableSlot.toArray(), Codec.UNSIGNED5);
  1133.         out.write(encodedBand);
  1134.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_slot[" + codeLocalVariableTableSlot.size() + "]");

  1135.         encodedBand = encodeBandInt("code_LocalVariableTypeTable_N", codeLocalVariableTypeTableN.toArray(), Codec.UNSIGNED5);
  1136.         out.write(encodedBand);
  1137.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_N[" + codeLocalVariableTypeTableN.size() + "]");

  1138.         encodedBand = encodeBandInt("code_LocalVariableTypeTable_bci_P", integerListToArray(codeLocalVariableTypeTableBciP), Codec.BCI5);
  1139.         out.write(encodedBand);
  1140.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_bci_P[" + codeLocalVariableTypeTableBciP.size() + "]");

  1141.         encodedBand = encodeBandInt("code_LocalVariableTypeTable_span_O", integerListToArray(codeLocalVariableTypeTableSpanO), Codec.BRANCH5);
  1142.         out.write(encodedBand);
  1143.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_span_O[" + codeLocalVariableTypeTableSpanO.size() + "]");

  1144.         encodedBand = encodeBandInt("code_LocalVariableTypeTable_name_RU", cpEntryListToArray(codeLocalVariableTypeTableNameRU), Codec.UNSIGNED5);
  1145.         out.write(encodedBand);
  1146.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_name_RU[" + codeLocalVariableTypeTableNameRU.size() + "]");

  1147.         encodedBand = encodeBandInt("code_LocalVariableTypeTable_type_RS", cpEntryListToArray(codeLocalVariableTypeTableTypeRS), Codec.UNSIGNED5);
  1148.         out.write(encodedBand);
  1149.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_type_RS[" + codeLocalVariableTypeTableTypeRS.size() + "]");

  1150.         encodedBand = encodeBandInt("code_LocalVariableTypeTable_slot", codeLocalVariableTypeTableSlot.toArray(), Codec.UNSIGNED5);
  1151.         out.write(encodedBand);
  1152.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_slot[" + codeLocalVariableTypeTableSlot.size() + "]");

  1153.         for (final NewAttributeBands bands : codeAttributeBands) {
  1154.             bands.pack(out);
  1155.         }
  1156.     }

  1157.     private void writeCodeBands(final OutputStream out) throws IOException, Pack200Exception {
  1158.         byte[] encodedBand = encodeBandInt("codeHeaders", codeHeaders, Codec.BYTE1);
  1159.         out.write(encodedBand);
  1160.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHeaders[" + codeHeaders.length + "]");

  1161.         encodedBand = encodeBandInt("codeMaxStack", codeMaxStack.toArray(), Codec.UNSIGNED5);
  1162.         out.write(encodedBand);
  1163.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxStack[" + codeMaxStack.size() + "]");

  1164.         encodedBand = encodeBandInt("codeMaxLocals", codeMaxLocals.toArray(), Codec.UNSIGNED5);
  1165.         out.write(encodedBand);
  1166.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxLocals[" + codeMaxLocals.size() + "]");

  1167.         encodedBand = encodeBandInt("codeHandlerCount", codeHandlerCount.toArray(), Codec.UNSIGNED5);
  1168.         out.write(encodedBand);
  1169.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerCount[" + codeHandlerCount.size() + "]");

  1170.         encodedBand = encodeBandInt("codeHandlerStartP", integerListToArray(codeHandlerStartP), Codec.BCI5);
  1171.         out.write(encodedBand);
  1172.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerStartP[" + codeHandlerStartP.size() + "]");

  1173.         encodedBand = encodeBandInt("codeHandlerEndPO", integerListToArray(codeHandlerEndPO), Codec.BRANCH5);
  1174.         out.write(encodedBand);
  1175.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerEndPO[" + codeHandlerEndPO.size() + "]");

  1176.         encodedBand = encodeBandInt("codeHandlerCatchPO", integerListToArray(codeHandlerCatchPO), Codec.BRANCH5);
  1177.         out.write(encodedBand);
  1178.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerCatchPO[" + codeHandlerCatchPO.size() + "]");

  1179.         encodedBand = encodeBandInt("codeHandlerClass", cpEntryOrNullListToArray(codeHandlerClass), Codec.UNSIGNED5);
  1180.         out.write(encodedBand);
  1181.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerClass[" + codeHandlerClass.size() + "]");

  1182.         writeCodeAttributeBands(out);
  1183.     }

  1184.     private void writeFieldAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
  1185.         byte[] encodedBand = encodeFlags("field_flags", field_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_field_flags_hi());
  1186.         out.write(encodedBand);
  1187.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_flags[" + field_flags.length + "]");

  1188.         // *field_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
  1189.         // *field_attr_indexes :UNSIGNED5 [SUM(*field_attr_count)]
  1190.         encodedBand = encodeBandInt("field_attr_calls", field_attr_calls, Codec.UNSIGNED5);
  1191.         out.write(encodedBand);
  1192.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_attr_calls[" + field_attr_calls.length + "]");

  1193.         encodedBand = encodeBandInt("fieldConstantValueKQ", cpEntryListToArray(fieldConstantValueKQ), Codec.UNSIGNED5);
  1194.         out.write(encodedBand);
  1195.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldConstantValueKQ[" + fieldConstantValueKQ.size() + "]");

  1196.         encodedBand = encodeBandInt("fieldSignature", cpEntryListToArray(fieldSignature), Codec.UNSIGNED5);
  1197.         out.write(encodedBand);
  1198.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldSignature[" + fieldSignature.size() + "]");

  1199.         field_RVA_bands.pack(out);
  1200.         field_RIA_bands.pack(out);
  1201.         for (final NewAttributeBands bands : fieldAttributeBands) {
  1202.             bands.pack(out);
  1203.         }
  1204.     }

  1205.     private void writeMethodAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
  1206.         byte[] encodedBand = encodeFlags("method_flags", method_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_method_flags_hi());
  1207.         out.write(encodedBand);
  1208.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_flags[" + method_flags.length + "]");

  1209.         // *method_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
  1210.         // *method_attr_indexes :UNSIGNED5 [SUM(*method_attr_count)]
  1211.         encodedBand = encodeBandInt("method_attr_calls", method_attr_calls, Codec.UNSIGNED5);
  1212.         out.write(encodedBand);
  1213.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_attr_calls[" + method_attr_calls.length + "]");

  1214.         encodedBand = encodeBandInt("methodExceptionNumber", methodExceptionNumber.toArray(), Codec.UNSIGNED5);
  1215.         out.write(encodedBand);
  1216.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionNumber[" + methodExceptionNumber.size() + "]");

  1217.         encodedBand = encodeBandInt("methodExceptionClasses", cpEntryListToArray(methodExceptionClasses), Codec.UNSIGNED5);
  1218.         out.write(encodedBand);
  1219.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionClasses[" + methodExceptionClasses.size() + "]");

  1220.         encodedBand = encodeBandInt("methodSignature", cpEntryListToArray(methodSignature), Codec.UNSIGNED5);
  1221.         out.write(encodedBand);
  1222.         PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodSignature[" + methodSignature.size() + "]");

  1223.         method_RVA_bands.pack(out);
  1224.         method_RIA_bands.pack(out);
  1225.         method_RVPA_bands.pack(out);
  1226.         method_RIPA_bands.pack(out);
  1227.         method_AD_bands.pack(out);
  1228.         for (final NewAttributeBands bands : methodAttributeBands) {
  1229.             bands.pack(out);
  1230.         }
  1231.     }
  1232. }