    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one
    003 * or more contributor license agreements.  See the NOTICE file
    004 * distributed with this work for additional information
    005 * regarding copyright ownership.  The ASF licenses this file
    006 * to you under the Apache License, Version 2.0 (the
    007 * "License"); you may not use this file except in compliance
    008 * with the License.  You may obtain a copy of the License at
    009 *
    010 *   https://www.apache.org/licenses/LICENSE-2.0
    011 *
    012 * Unless required by applicable law or agreed to in writing,
    013 * software distributed under the License is distributed on an
    014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015 * KIND, either express or implied.  See the License for the
    016 * specific language governing permissions and limitations
    017 * under the License.
    018 */
    019package org.apache.commons.compress.harmony.pack200;
    020
    021import java.io.IOException;
    022import java.io.OutputStream;
    023import java.util.ArrayList;
    024import java.util.Arrays;
    025import java.util.Comparator;
    026import java.util.HashMap;
    027import java.util.HashSet;
    028import java.util.List;
    029import java.util.Map;
    030import java.util.Set;
    031
    032import org.apache.commons.compress.harmony.pack200.AttributeDefinitionBands.AttributeDefinition;
    033import org.apache.commons.compress.harmony.pack200.IcBands.IcTuple;
    034import org.apache.commons.compress.harmony.pack200.Segment.SegmentMethodVisitor;
    035import org.objectweb.asm.Label;
    036import org.objectweb.asm.Opcodes;
    037
    038/**
    039 * Class bands (corresponds to the {@code class_bands} set of bands in the pack200 specification)
    040 */
    041public class ClassBands extends BandSet {
    042
    043    private static final class TempParamAnnotation {
    044
    045        int numParams;
    046        int[] annoN;
    047        IntList pairN = new IntList();
    048        List<String> typeRS = new ArrayList<>();
    049        List<String> nameRU = new ArrayList<>();
    050        List<String> tags = new ArrayList<>();
    051        List<Object> values = new ArrayList<>();
    052        List<Integer> caseArrayN = new ArrayList<>();
    053        List<String> nestTypeRS = new ArrayList<>();
    054        List<String> nestNameRU = new ArrayList<>();
    055        List<Integer> nestPairN = new ArrayList<>();
    056
    057        TempParamAnnotation(final int numParams) {
    058            this.numParams = numParams;
    059            annoN = new int[numParams];
    060        }
    061
    062        void addParameterAnnotation(final int parameter, final String desc, final List<String> nameRU, final List<String> tags,
    063                final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
    064                final List<Integer> nestPairN) {
    065            annoN[parameter]++;
    066            typeRS.add(desc);
    067            pairN.add(nameRU.size());
    068            this.nameRU.addAll(nameRU);
    069            this.tags.addAll(tags);
    070            this.values.addAll(values);
    071            this.caseArrayN.addAll(caseArrayN);
    072            this.nestTypeRS.addAll(nestTypeRS);
    073            this.nestNameRU.addAll(nestNameRU);
    074            this.nestPairN.addAll(nestPairN);
    075        }
    076    }
    077
    078    private static final long[] EMPTY_LONG_ARRAY = {};
    079
    080    /**
    081     * Counts arguments in a descriptor.
    082     *
    083     * @param descriptor the descriptor to parse.
    084     * @return the argument count.
    085     */
    086    protected static int countArgs(final String descriptor) {
    087        final int bra = descriptor.indexOf('(');
    088        final int ket = descriptor.indexOf(')');
    089        if (bra == -1 || ket == -1 || ket < bra) {
    090            throw new IllegalArgumentException("No arguments");
    091        }
    092
    093        boolean inType = false;
    094        boolean consumingNextType = false;
    095        int count = 0;
    096        for (int i = bra + 1; i < ket; i++) {
    097            final char charAt = descriptor.charAt(i);
    098            if (inType && charAt == ';') {
    099                inType = false;
    100                consumingNextType = false;
    101            } else if (!inType && charAt == 'L') {
    102                inType = true;
    103                count++;
    104            } else if (charAt == '[') {
    105                consumingNextType = true;
    106            } else if (inType) {
    107                // NOP
    108            } else if (consumingNextType) {
    109                count++;
    110                consumingNextType = false;
    111            } else if (charAt == 'D' || charAt == 'J') {
    112                count += 2;
    113            } else {
    114                count++;
    115            }
    116        }
    117        return count;
    118    }
    119
    120    private final CpBands cpBands;
    121    private final AttributeDefinitionBands attrBands;
    122    private final CPClass[] class_this;
    123    private final CPClass[] class_super;
    124
    125    private final CPClass[][] class_interface;
    126
    127    private final int[] class_interface_count;
    128    private final int[] major_versions;
    129    private final long[] class_flags;
    130    private int[] class_attr_calls;
    131    private final List<CPUTF8> classSourceFile = new ArrayList<>();
    132    private final List<ConstantPoolEntry> classEnclosingMethodClass = new ArrayList<>();
    133
    134    private final List<ConstantPoolEntry> classEnclosingMethodDesc = new ArrayList<>();
    135    private final List<CPSignature> classSignature = new ArrayList<>();
    136
    137    private final IntList classFileVersionMinor = new IntList();
    138    private final IntList classFileVersionMajor = new IntList();
    139    private final int[] class_field_count;
    140    private final CPNameAndType[][] field_descr;
    141    private final long[][] field_flags;
    142    private int[] field_attr_calls;
    143
    144    private final List<CPConstant<?>> fieldConstantValueKQ = new ArrayList<>();
    145    private final List<CPSignature> fieldSignature = new ArrayList<>();
    146    private final int[] class_method_count;
    147    private final CPNameAndType[][] method_descr;
    148    private final long[][] method_flags;
    149    private int[] method_attr_calls;
    150    private final List<CPSignature> methodSignature = new ArrayList<>();
    151
    152    private final IntList methodExceptionNumber = new IntList();
    153    private final List<CPClass> methodExceptionClasses = new ArrayList<>();
    154    private int[] codeHeaders;
    155    private final IntList codeMaxStack = new IntList();
    156    private final IntList codeMaxLocals = new IntList();
    157    private final IntList codeHandlerCount = new IntList();
    158    private final List codeHandlerStartP = new ArrayList();
    159    private final List codeHandlerEndPO = new ArrayList();
    160    private final List codeHandlerCatchPO = new ArrayList();
    161    private final List<CPClass> codeHandlerClass = new ArrayList<>();
    162    private final List<Long> codeFlags = new ArrayList<>();
    163    private int[] code_attr_calls;
    164    private final IntList codeLineNumberTableN = new IntList();
    165    private final List codeLineNumberTableBciP = new ArrayList();
    166    private final IntList codeLineNumberTableLine = new IntList();
    167    private final IntList codeLocalVariableTableN = new IntList();
    168    private final List codeLocalVariableTableBciP = new ArrayList();
    169    private final List codeLocalVariableTableSpanO = new ArrayList();
    170    private final List<ConstantPoolEntry> codeLocalVariableTableNameRU = new ArrayList<>();
    171    private final List<ConstantPoolEntry> codeLocalVariableTableTypeRS = new ArrayList<>();
    172    private final IntList codeLocalVariableTableSlot = new IntList();
    173    private final IntList codeLocalVariableTypeTableN = new IntList();
    174    private final List codeLocalVariableTypeTableBciP = new ArrayList();
    175    private final List codeLocalVariableTypeTableSpanO = new ArrayList();
    176    private final List<ConstantPoolEntry> codeLocalVariableTypeTableNameRU = new ArrayList<>();
    177
    178    private final List<ConstantPoolEntry> codeLocalVariableTypeTableTypeRS = new ArrayList<>();
    179    private final IntList codeLocalVariableTypeTableSlot = new IntList();
    180    private final MetadataBandGroup class_RVA_bands;
    181    private final MetadataBandGroup class_RIA_bands;
    182    private final MetadataBandGroup field_RVA_bands;
    183    private final MetadataBandGroup field_RIA_bands;
    184    private final MetadataBandGroup method_RVA_bands;
    185    private final MetadataBandGroup method_RIA_bands;
    186    private final MetadataBandGroup method_RVPA_bands;
    187
    188    private final MetadataBandGroup method_RIPA_bands;
    189    private final MetadataBandGroup method_AD_bands;
    190    private final List<NewAttributeBands> classAttributeBands = new ArrayList<>();
    191    private final List<NewAttributeBands> methodAttributeBands = new ArrayList<>();
    192
    193    private final List<NewAttributeBands> fieldAttributeBands = new ArrayList<>();
    194    private final List<NewAttributeBands> codeAttributeBands = new ArrayList<>();
    195    private final List<Long> tempFieldFlags = new ArrayList<>();
    196    private final List<CPNameAndType> tempFieldDesc = new ArrayList<>();
    197    private final List<Long> tempMethodFlags = new ArrayList<>();
    198    private final List<CPNameAndType> tempMethodDesc = new ArrayList<>();
    199
    200    private TempParamAnnotation tempMethodRVPA;
    201    private TempParamAnnotation tempMethodRIPA;
    202    private boolean anySyntheticClasses;
    203    private boolean anySyntheticFields;
    204
    205    private boolean anySyntheticMethods;
    206    private final Segment segment;
    207
    208    private final Map<CPClass, Set<CPClass>> classReferencesInnerClass = new HashMap<>();
    209
    210    private final boolean stripDebug;
    211    private int index;
    212    private int numMethodArgs;
    213    private int[] class_InnerClasses_N;
    214    private CPClass[] class_InnerClasses_RC;
    215    private int[] class_InnerClasses_F;
    216
    217    private List<CPClass> classInnerClassesOuterRCN;
    218
    219    private List<CPUTF8> classInnerClassesNameRUN;
    220
    221    public ClassBands(final Segment segment, final int numClasses, final int effort, final boolean stripDebug) throws IOException {
    222        super(effort, segment.getSegmentHeader());
    223        this.stripDebug = stripDebug;
    224        this.segment = segment;
    225        this.cpBands = segment.getCpBands();
    226        this.attrBands = segment.getAttrBands();
    227        class_this = new CPClass[numClasses];
    228        class_super = new CPClass[numClasses];
    229        class_interface_count = new int[numClasses];
    230        class_interface = new CPClass[numClasses][];
    231        class_field_count = new int[numClasses];
    232        class_method_count = new int[numClasses];
    233        field_descr = new CPNameAndType[numClasses][];
    234        field_flags = new long[numClasses][];
    235        method_descr = new CPNameAndType[numClasses][];
    236        method_flags = new long[numClasses][];
    237        for (int i = 0; i < numClasses; i++) {
    238            field_flags[i] = EMPTY_LONG_ARRAY;
    239            method_flags[i] = EMPTY_LONG_ARRAY;
    240        }
    241        // minor_versions = new int[numClasses];
    242        major_versions = new int[numClasses];
    243        class_flags = new long[numClasses];
    244
    245        class_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_CLASS, cpBands, segmentHeader, effort);
    246        class_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_CLASS, cpBands, segmentHeader, effort);
    247        field_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_FIELD, cpBands, segmentHeader, effort);
    248        field_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_FIELD, cpBands, segmentHeader, effort);
    249        method_RVA_bands = new MetadataBandGroup("RVA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    250        method_RIA_bands = new MetadataBandGroup("RIA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    251        method_RVPA_bands = new MetadataBandGroup("RVPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    252        method_RIPA_bands = new MetadataBandGroup("RIPA", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    253        method_AD_bands = new MetadataBandGroup("AD", MetadataBandGroup.CONTEXT_METHOD, cpBands, segmentHeader, effort);
    254
    255        createNewAttributeBands();
    256    }
    257
    258    public void addAnnotation(final int context, final String desc, final boolean visible, final List<String> nameRU, final List<String> tags,
    259            final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
    260            final List<Integer> nestPairN) {
    261        switch (context) {
    262        case MetadataBandGroup.CONTEXT_CLASS:
    263            if (visible) {
    264                class_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    265                if ((class_flags[index] & 1 << 21) != 0) {
    266                    class_RVA_bands.incrementAnnoN();
    267                } else {
    268                    class_RVA_bands.newEntryInAnnoN();
    269                    class_flags[index] = class_flags[index] | 1 << 21;
    270                }
    271            } else {
    272                class_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    273                if ((class_flags[index] & 1 << 22) != 0) {
    274                    class_RIA_bands.incrementAnnoN();
    275                } else {
    276                    class_RIA_bands.newEntryInAnnoN();
    277                    class_flags[index] = class_flags[index] | 1 << 22;
    278                }
    279            }
    280            break;
    281        case MetadataBandGroup.CONTEXT_FIELD:
    282            if (visible) {
    283                field_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    284                final Long flag = tempFieldFlags.remove(tempFieldFlags.size() - 1);
    285                if ((flag.intValue() & 1 << 21) != 0) {
    286                    field_RVA_bands.incrementAnnoN();
    287                } else {
    288                    field_RVA_bands.newEntryInAnnoN();
    289                }
    290                tempFieldFlags.add(Long.valueOf(flag.intValue() | 1 << 21));
    291            } else {
    292                field_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    293                final Long flag = tempFieldFlags.remove(tempFieldFlags.size() - 1);
    294                if ((flag.intValue() & 1 << 22) != 0) {
    295                    field_RIA_bands.incrementAnnoN();
    296                } else {
    297                    field_RIA_bands.newEntryInAnnoN();
    298                }
    299                tempFieldFlags.add(Long.valueOf(flag.intValue() | 1 << 22));
    300            }
    301            break;
    302        case MetadataBandGroup.CONTEXT_METHOD:
    303            if (visible) {
    304                method_RVA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    305                final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    306                if ((flag.intValue() & 1 << 21) != 0) {
    307                    method_RVA_bands.incrementAnnoN();
    308                } else {
    309                    method_RVA_bands.newEntryInAnnoN();
    310                }
    311                tempMethodFlags.add(Long.valueOf(flag.intValue() | 1 << 21));
    312            } else {
    313                method_RIA_bands.addAnnotation(desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    314                final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    315                if ((flag.intValue() & 1 << 22) != 0) {
    316                    method_RIA_bands.incrementAnnoN();
    317                } else {
    318                    method_RIA_bands.newEntryInAnnoN();
    319                }
    320                tempMethodFlags.add(Long.valueOf(flag.intValue() | 1 << 22));
    321            }
    322            break;
    323        }
    324    }
    325
    326    public void addAnnotationDefault(final List<String> nameRU, final List<String> tags, final List<Object> values, final List<Integer> caseArrayN,
    327            final List<String> nestTypeRS, final List<String> nestNameRU, final List<Integer> nestPairN) {
    328        method_AD_bands.addAnnotation(null, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    329        final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    330        tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 25));
    331    }
    332
    333    public void addClass(final int major, final int flags, final String className, final String signature, final String superName, final String[] interfaces) {
    334        class_this[index] = cpBands.getCPClass(className);
    335        class_super[index] = cpBands.getCPClass(superName);
    336        class_interface_count[index] = interfaces.length;
    337        class_interface[index] = new CPClass[interfaces.length];
    338        Arrays.setAll(class_interface[index], i -> cpBands.getCPClass(interfaces[i]));
    339        major_versions[index] = major;
    340        class_flags[index] = flags;
    341        if (!anySyntheticClasses && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
    342            cpBands.addCPUtf8("Synthetic");
    343            anySyntheticClasses = true;
    344        }
    345//        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
    346//            flags &= ~Opcodes.ACC_DEPRECATED;
    347//            flags |= (1 << 20);
    348//        }
    349        if (signature != null) {
    350            class_flags[index] |= 1 << 19;
    351            classSignature.add(cpBands.getCPSignature(signature));
    352        }
    353    }
    354
    355    /**
    356     * Adds a new class attribute.
    357     *
    358     * @param attribute the new class attribute.
    359     */
    360    public void addClassAttribute(final NewAttribute attribute) {
    361        // TODO: backwards calls
    362        final String attributeName = attribute.type;
    363        for (final NewAttributeBands bands : classAttributeBands) {
    364            if (bands.getAttributeName().equals(attributeName)) {
    365                bands.addAttribute(attribute);
    366                final int flagIndex = bands.getFlagIndex();
    367                class_flags[index] |= 1 << flagIndex;
    368                return;
    369            }
    370        }
    371        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    372    }
    373
    374    public void addCode() {
    375        codeHandlerCount.add(0);
    376        if (!stripDebug) {
    377            codeFlags.add(Long.valueOf(1 << 2));
    378            codeLocalVariableTableN.add(0);
    379        }
    380    }
    381
    382    /**
    383     * Adds a new code attribute.
    384     *
    385     * @param attribute the new code attribute.
    386     */
    387    public void addCodeAttribute(final NewAttribute attribute) {
    388        final String attributeName = attribute.type;
    389        for (final NewAttributeBands bands : codeAttributeBands) {
    390            if (bands.getAttributeName().equals(attributeName)) {
    391                bands.addAttribute(attribute);
    392                final int flagIndex = bands.getFlagIndex();
    393                final Long flags = codeFlags.remove(codeFlags.size() - 1);
    394                codeFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
    395                return;
    396            }
    397        }
    398        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    399    }
    400
    401    /**
    402     * Adds an enclosing method.
    403     *
    404     * @param ownerClassName a fully-qualifed class name.
    405     * @param name a method name.
    406     * @param signature a signature in the constant pool.
    407     */
    408    public void addEnclosingMethod(final String ownerClassName, final String name, final String signature) {
    409        class_flags[index] |= 1 << 18;
    410        classEnclosingMethodClass.add(cpBands.getCPClass(ownerClassName));
    411        classEnclosingMethodDesc.add(name == null ? null : cpBands.getCPNameAndType(name, signature));
    412    }
    413
    414    public void addField(int flags, final String name, final String desc, final String signature, final Object value) {
    415        flags &= 0xFFFF;
    416        tempFieldDesc.add(cpBands.getCPNameAndType(name, desc));
    417        if (signature != null) {
    418            fieldSignature.add(cpBands.getCPSignature(signature));
    419            flags |= 1 << 19;
    420        }
    421        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
    422            flags &= ~Opcodes.ACC_DEPRECATED;
    423            flags |= 1 << 20;
    424        }
    425        if (value != null) {
    426            fieldConstantValueKQ.add(cpBands.getConstant(value));
    427            flags |= 1 << 17;
    428        }
    429        if (!anySyntheticFields && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
    430            cpBands.addCPUtf8("Synthetic");
    431            anySyntheticFields = true;
    432        }
    433        tempFieldFlags.add(Long.valueOf(flags));
    434    }
    435
    436    /**
    437     * Adds a new field attribute.
    438     *
    439     * @param attribute the new field attribute.
    440     */
    441    public void addFieldAttribute(final NewAttribute attribute) {
    442        final String attributeName = attribute.type;
    443        for (final NewAttributeBands bands : fieldAttributeBands) {
    444            if (bands.getAttributeName().equals(attributeName)) {
    445                bands.addAttribute(attribute);
    446                final int flagIndex = bands.getFlagIndex();
    447                final Long flags = tempFieldFlags.remove(tempFieldFlags.size() - 1);
    448                tempFieldFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
    449                return;
    450            }
    451        }
    452        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    453    }
    454
    455    public void addHandler(final Label start, final Label end, final Label handler, final String type) {
    456        final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
    457        codeHandlerCount.add(handlers + 1);
    458        codeHandlerStartP.add(start);
    459        codeHandlerEndPO.add(end);
    460        codeHandlerCatchPO.add(handler);
    461        codeHandlerClass.add(type == null ? null : cpBands.getCPClass(type));
    462    }
    463
    464    public void addLineNumber(final int line, final Label start) {
    465        final Long latestCodeFlag = codeFlags.get(codeFlags.size() - 1);
    466        if ((latestCodeFlag.intValue() & 1 << 1) == 0) {
    467            codeFlags.remove(codeFlags.size() - 1);
    468            codeFlags.add(Long.valueOf(latestCodeFlag.intValue() | 1 << 1));
    469            codeLineNumberTableN.add(1);
    470        } else {
    471            codeLineNumberTableN.increment(codeLineNumberTableN.size() - 1);
    472        }
    473        codeLineNumberTableLine.add(line);
    474        codeLineNumberTableBciP.add(start);
    475    }
    476
    477    public void addLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int indx) {
    478        if (signature != null) { // LocalVariableTypeTable attribute
    479            final Long latestCodeFlag = codeFlags.get(codeFlags.size() - 1);
    480            if ((latestCodeFlag.intValue() & 1 << 3) == 0) {
    481                codeFlags.remove(codeFlags.size() - 1);
    482                codeFlags.add(Long.valueOf(latestCodeFlag.intValue() | 1 << 3));
    483                codeLocalVariableTypeTableN.add(1);
    484            } else {
    485                codeLocalVariableTypeTableN.increment(codeLocalVariableTypeTableN.size() - 1);
    486            }
    487            codeLocalVariableTypeTableBciP.add(start);
    488            codeLocalVariableTypeTableSpanO.add(end);
    489            codeLocalVariableTypeTableNameRU.add(cpBands.getCPUtf8(name));
    490            codeLocalVariableTypeTableTypeRS.add(cpBands.getCPSignature(signature));
    491            codeLocalVariableTypeTableSlot.add(indx);
    492        }
    493        // LocalVariableTable attribute
    494        codeLocalVariableTableN.increment(codeLocalVariableTableN.size() - 1);
    495        codeLocalVariableTableBciP.add(start);
    496        codeLocalVariableTableSpanO.add(end);
    497        codeLocalVariableTableNameRU.add(cpBands.getCPUtf8(name));
    498        codeLocalVariableTableTypeRS.add(cpBands.getCPSignature(desc));
    499        codeLocalVariableTableSlot.add(indx);
    500    }
    501
    502    public void addMaxStack(final int maxStack, int maxLocals) {
    503        final Long latestFlag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    504        final Long newFlag = Long.valueOf(latestFlag.intValue() | 1 << 17);
    505        tempMethodFlags.add(newFlag);
    506        codeMaxStack.add(maxStack);
    507        if ((newFlag.longValue() & 1 << 3) == 0) { // not static
    508            maxLocals--; // minus 'this' local
    509        }
    510        maxLocals -= numMethodArgs;
    511        codeMaxLocals.add(maxLocals);
    512    }
    513
    514    public void addMethod(int flags, final String name, final String desc, final String signature, final String[] exceptions) {
    515        final CPNameAndType nt = cpBands.getCPNameAndType(name, desc);
    516        tempMethodDesc.add(nt);
    517        if (signature != null) {
    518            methodSignature.add(cpBands.getCPSignature(signature));
    519            flags |= 1 << 19;
    520        }
    521        if (exceptions != null) {
    522            methodExceptionNumber.add(exceptions.length);
    523            for (final String exception : exceptions) {
    524                methodExceptionClasses.add(cpBands.getCPClass(exception));
    525            }
    526            flags |= 1 << 18;
    527        }
    528        if ((flags & Opcodes.ACC_DEPRECATED) != 0) { // ASM uses (1<<17) flag for deprecated
    529            flags &= ~Opcodes.ACC_DEPRECATED;
    530            flags |= 1 << 20;
    531        }
    532        tempMethodFlags.add(Long.valueOf(flags));
    533        numMethodArgs = countArgs(desc);
    534        if (!anySyntheticMethods && (flags & 1 << 12) != 0 && segment.getCurrentClassReader().hasSyntheticAttributes()) {
    535            cpBands.addCPUtf8("Synthetic");
    536            anySyntheticMethods = true;
    537        }
    538    }
    539
    540    /**
    541     * Adds a new method attribute.
    542     *
    543     * @param attribute the new method attribute.
    544     */
    545    public void addMethodAttribute(final NewAttribute attribute) {
    546        final String attributeName = attribute.type;
    547        for (final NewAttributeBands bands : methodAttributeBands) {
    548            if (bands.getAttributeName().equals(attributeName)) {
    549                bands.addAttribute(attribute);
    550                final int flagIndex = bands.getFlagIndex();
    551                final Long flags = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    552                tempMethodFlags.add(Long.valueOf(flags.longValue() | 1 << flagIndex));
    553                return;
    554            }
    555        }
    556        throw new IllegalArgumentException("No suitable definition for " + attributeName);
    557    }
    558
    559    public void addParameterAnnotation(final int parameter, final String desc, final boolean visible, final List<String> nameRU, final List<String> tags,
    560            final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU,
    561            final List<Integer> nestPairN) {
    562        if (visible) {
    563            if (tempMethodRVPA == null) {
    564                tempMethodRVPA = new TempParamAnnotation(numMethodArgs);
    565                tempMethodRVPA.addParameterAnnotation(parameter, desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    566            }
    567            final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    568            tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 23));
    569        } else {
    570            if (tempMethodRIPA == null) {
    571                tempMethodRIPA = new TempParamAnnotation(numMethodArgs);
    572                tempMethodRIPA.addParameterAnnotation(parameter, desc, nameRU, tags, values, caseArrayN, nestTypeRS, nestNameRU, nestPairN);
    573            }
    574            final Long flag = tempMethodFlags.remove(tempMethodFlags.size() - 1);
    575            tempMethodFlags.add(Long.valueOf(flag.longValue() | 1 << 24));
    576        }
    577    }
    578
    579    /**
    580     * Adds a source file path.
    581     *
    582     * @param source a source file path.
    583     */
    584    public void addSourceFile(final String source) {
    585        String implicitSourceFileName = class_this[index].toString();
    586        if (implicitSourceFileName.indexOf('$') != -1) {
    587            implicitSourceFileName = implicitSourceFileName.substring(0, implicitSourceFileName.indexOf('$'));
    588        }
    589        implicitSourceFileName = implicitSourceFileName.substring(implicitSourceFileName.lastIndexOf('/') + 1) + ".java";
    590        if (source.equals(implicitSourceFileName)) {
    591            classSourceFile.add(null);
    592        } else {
    593            classSourceFile.add(cpBands.getCPUtf8(source));
    594        }
    595        class_flags[index] |= 1 << 17;
    596    }
    597
    598    private void createNewAttributeBands() throws IOException {
    599        for (final AttributeDefinition def : attrBands.getClassAttributeLayouts()) {
    600            classAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    601        }
    602        for (final AttributeDefinition def : attrBands.getMethodAttributeLayouts()) {
    603            methodAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    604        }
    605        for (final AttributeDefinition def : attrBands.getFieldAttributeLayouts()) {
    606            fieldAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    607        }
    608        for (final AttributeDefinition def : attrBands.getCodeAttributeLayouts()) {
    609            codeAttributeBands.add(new NewAttributeBands(effort, cpBands, segment.getSegmentHeader(), def));
    610        }
    611    }
    612
    613    public void currentClassReferencesInnerClass(final CPClass inner) {
    614        if (!(index >= class_this.length)) {
    615            final CPClass currentClass = class_this[index];
    616            if (currentClass != null && !currentClass.equals(inner) && !isInnerClassOf(currentClass.toString(), inner)) {
    617                classReferencesInnerClass.computeIfAbsent(currentClass, c -> new HashSet<>()).add(inner);
    618            }
    619        }
    620    }
    621
    622    public void doBciRenumbering(final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
    623        renumberBci(codeLineNumberTableBciP, bciRenumbering, labelsToOffsets);
    624        renumberBci(codeLocalVariableTableBciP, bciRenumbering, labelsToOffsets);
    625        renumberOffsetBci(codeLocalVariableTableBciP, codeLocalVariableTableSpanO, bciRenumbering, labelsToOffsets);
    626        renumberBci(codeLocalVariableTypeTableBciP, bciRenumbering, labelsToOffsets);
    627        renumberOffsetBci(codeLocalVariableTypeTableBciP, codeLocalVariableTypeTableSpanO, bciRenumbering, labelsToOffsets);
    628        renumberBci(codeHandlerStartP, bciRenumbering, labelsToOffsets);
    629        renumberOffsetBci(codeHandlerStartP, codeHandlerEndPO, bciRenumbering, labelsToOffsets);
    630        renumberDoubleOffsetBci(codeHandlerStartP, codeHandlerEndPO, codeHandlerCatchPO, bciRenumbering, labelsToOffsets);
    631
    632        for (final NewAttributeBands newAttributeBandSet : classAttributeBands) {
    633            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    634        }
    635        for (final NewAttributeBands newAttributeBandSet : methodAttributeBands) {
    636            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    637        }
    638        for (final NewAttributeBands newAttributeBandSet : fieldAttributeBands) {
    639            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    640        }
    641        for (final NewAttributeBands newAttributeBandSet : codeAttributeBands) {
    642            newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    643        }
    644    }
    645
    646    /**
    647     * Called when all the data for the current class has been.
    648     *
    649     * @see Segment#visitEnd()
    650     */
    651    public void endOfClass() {
    652        final int numFields = tempFieldDesc.size();
    653        class_field_count[index] = numFields;
    654        field_descr[index] = new CPNameAndType[numFields];
    655        field_flags[index] = new long[numFields];
    656        for (int i = 0; i < numFields; i++) {
    657            field_descr[index][i] = tempFieldDesc.get(i);
    658            field_flags[index][i] = tempFieldFlags.get(i).longValue();
    659        }
    660        final int numMethods = tempMethodDesc.size();
    661        class_method_count[index] = numMethods;
    662        method_descr[index] = new CPNameAndType[numMethods];
    663        method_flags[index] = new long[numMethods];
    664        for (int i = 0; i < numMethods; i++) {
    665            method_descr[index][i] = tempMethodDesc.get(i);
    666            method_flags[index][i] = tempMethodFlags.get(i).longValue();
    667        }
    668        tempFieldDesc.clear();
    669        tempFieldFlags.clear();
    670        tempMethodDesc.clear();
    671        tempMethodFlags.clear();
    672        index++;
    673    }
    674
    675    /**
    676     * Called when all the data for the current method has been.
    677     *
    678     * @see SegmentMethodVisitor#visitEnd()
    679     */
    680    public void endOfMethod() {
    681        if (tempMethodRVPA != null) {
    682            method_RVPA_bands.addParameterAnnotation(tempMethodRVPA.numParams, tempMethodRVPA.annoN, tempMethodRVPA.pairN, tempMethodRVPA.typeRS,
    683                    tempMethodRVPA.nameRU, tempMethodRVPA.tags, tempMethodRVPA.values, tempMethodRVPA.caseArrayN, tempMethodRVPA.nestTypeRS,
    684                    tempMethodRVPA.nestNameRU, tempMethodRVPA.nestPairN);
    685            tempMethodRVPA = null;
    686        }
    687        if (tempMethodRIPA != null) {
    688            method_RIPA_bands.addParameterAnnotation(tempMethodRIPA.numParams, tempMethodRIPA.annoN, tempMethodRIPA.pairN, tempMethodRIPA.typeRS,
    689                    tempMethodRIPA.nameRU, tempMethodRIPA.tags, tempMethodRIPA.values, tempMethodRIPA.caseArrayN, tempMethodRIPA.nestTypeRS,
    690                    tempMethodRIPA.nestNameRU, tempMethodRIPA.nestPairN);
    691            tempMethodRIPA = null;
    692        }
    693        if (codeFlags.size() > 0) {
    694            final long latestCodeFlag = codeFlags.get(codeFlags.size() - 1).longValue();
    695            final int latestLocalVariableTableN = codeLocalVariableTableN.get(codeLocalVariableTableN.size() - 1);
    696            if (latestCodeFlag == 1 << 2 && latestLocalVariableTableN == 0) {
    697                codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
    698                codeFlags.remove(codeFlags.size() - 1);
    699                codeFlags.add(Long.valueOf(0));
    700            }
    701        }
    702    }
    703
    704    /**
    705     * 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
    706     * while classes were being read.
    707     */
    708    public void finaliseBands() {
    709        final int defaultMajorVersion = segmentHeader.getDefaultMajorVersion();
    710        for (int i = 0; i < class_flags.length; i++) {
    711            final int major = major_versions[i];
    712            if (major != defaultMajorVersion) {
    713                class_flags[i] |= 1 << 24;
    714                classFileVersionMajor.add(major);
    715                classFileVersionMinor.add(0);
    716            }
    717        }
    718        // Calculate code headers
    719        codeHeaders = new int[codeHandlerCount.size()];
    720        int removed = 0;
    721        for (int i = 0; i < codeHeaders.length; i++) {
    722            final int numHandlers = codeHandlerCount.get(i - removed);
    723            final int maxLocals = codeMaxLocals.get(i - removed);
    724            final int maxStack = codeMaxStack.get(i - removed);
    725            switch (numHandlers) {
    726            case 0: {
    727                final int header = maxLocals * 12 + maxStack + 1;
    728                if (header < 145 && maxStack < 12) {
    729                    codeHeaders[i] = header;
    730                }
    731                break;
    732            }
    733            case 1: {
    734                final int header = maxLocals * 8 + maxStack + 145;
    735                if (header < 209 && maxStack < 8) {
    736                    codeHeaders[i] = header;
    737                }
    738                break;
    739            }
    740            case 2: {
    741                final int header = maxLocals * 7 + maxStack + 209;
    742                if (header < 256 && maxStack < 7) {
    743                    codeHeaders[i] = header;
    744                }
    745                break;
    746            }
    747            default:
    748                break;
    749            }
    750            if (codeHeaders[i] != 0) { // Remove the redundant values from
    751                                       // codeHandlerCount, codeMaxLocals and
    752                                       // codeMaxStack
    753                codeHandlerCount.remove(i - removed);
    754                codeMaxLocals.remove(i - removed);
    755                codeMaxStack.remove(i - removed);
    756                removed++;
    757            } else if (!segment.getSegmentHeader().have_all_code_flags()) {
    758                codeFlags.add(Long.valueOf(0));
    759            }
    760        }
    761
    762        // Compute any required IcLocals
    763        final IntList innerClassesN = new IntList();
    764        final List<IcTuple> icLocal = new ArrayList<>();
    765        for (int i = 0; i < class_this.length; i++) {
    766            final CPClass cpClass = class_this[i];
    767            final Set<CPClass> referencedInnerClasses = classReferencesInnerClass.get(cpClass);
    768            if (referencedInnerClasses != null) {
    769                int innerN = 0;
    770                final List<IcTuple> innerClasses = segment.getIcBands().getInnerClassesForOuter(cpClass.toString());
    771                if (innerClasses != null) {
    772                    for (final IcTuple element : innerClasses) {
    773                        referencedInnerClasses.remove(element.C);
    774                    }
    775                }
    776                for (final CPClass inner : referencedInnerClasses) {
    777                    final IcTuple icTuple = segment.getIcBands().getIcTuple(inner);
    778                    if (icTuple != null && !icTuple.isAnonymous()) {
    779                        // should transmit an icLocal entry
    780                        icLocal.add(icTuple);
    781                        innerN++;
    782                    }
    783                }
    784                if (innerN != 0) {
    785                    innerClassesN.add(innerN);
    786                    class_flags[i] |= 1 << 23;
    787                }
    788            }
    789        }
    790        class_InnerClasses_N = innerClassesN.toArray();
    791        class_InnerClasses_RC = new CPClass[icLocal.size()];
    792        class_InnerClasses_F = new int[icLocal.size()];
    793        classInnerClassesOuterRCN = new ArrayList<>();
    794        classInnerClassesNameRUN = new ArrayList<>();
    795        for (int i = 0; i < class_InnerClasses_RC.length; i++) {
    796            final IcTuple icTuple = icLocal.get(i);
    797            class_InnerClasses_RC[i] = icTuple.C;
    798            if (icTuple.C2 == null && icTuple.N == null) {
    799                class_InnerClasses_F[i] = 0;
    800            } else {
    801                if (icTuple.F == 0) {
    802                    class_InnerClasses_F[i] = 0x00010000;
    803                } else {
    804                    class_InnerClasses_F[i] = icTuple.F;
    805                }
    806                classInnerClassesOuterRCN.add(icTuple.C2);
    807                classInnerClassesNameRUN.add(icTuple.N);
    808            }
    809        }
    810        // Calculate any backwards calls from metadata bands
    811        final IntList classAttrCalls = new IntList();
    812        final IntList fieldAttrCalls = new IntList();
    813        final IntList methodAttrCalls = new IntList();
    814        final IntList codeAttrCalls = new IntList();
    815
    816        if (class_RVA_bands.hasContent()) {
    817            classAttrCalls.add(class_RVA_bands.numBackwardsCalls());
    818        }
    819        if (class_RIA_bands.hasContent()) {
    820            classAttrCalls.add(class_RIA_bands.numBackwardsCalls());
    821        }
    822        if (field_RVA_bands.hasContent()) {
    823            fieldAttrCalls.add(field_RVA_bands.numBackwardsCalls());
    824        }
    825        if (field_RIA_bands.hasContent()) {
    826            fieldAttrCalls.add(field_RIA_bands.numBackwardsCalls());
    827        }
    828        if (method_RVA_bands.hasContent()) {
    829            methodAttrCalls.add(method_RVA_bands.numBackwardsCalls());
    830        }
    831        if (method_RIA_bands.hasContent()) {
    832            methodAttrCalls.add(method_RIA_bands.numBackwardsCalls());
    833        }
    834        if (method_RVPA_bands.hasContent()) {
    835            methodAttrCalls.add(method_RVPA_bands.numBackwardsCalls());
    836        }
    837        if (method_RIPA_bands.hasContent()) {
    838            methodAttrCalls.add(method_RIPA_bands.numBackwardsCalls());
    839        }
    840        if (method_AD_bands.hasContent()) {
    841            methodAttrCalls.add(method_AD_bands.numBackwardsCalls());
    842        }
    843
    844        // Sort non-predefined attribute bands
    845        final Comparator<NewAttributeBands> comparator = (arg0, arg1) -> arg0.getFlagIndex() - arg1.getFlagIndex();
    846        classAttributeBands.sort(comparator);
    847        methodAttributeBands.sort(comparator);
    848        fieldAttributeBands.sort(comparator);
    849        codeAttributeBands.sort(comparator);
    850
    851        for (final NewAttributeBands bands : classAttributeBands) {
    852            if (bands.isUsedAtLeastOnce()) {
    853                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    854                    classAttrCalls.add(backwardsCallCount);
    855                }
    856            }
    857        }
    858        for (final NewAttributeBands bands : methodAttributeBands) {
    859            if (bands.isUsedAtLeastOnce()) {
    860                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    861                    methodAttrCalls.add(backwardsCallCount);
    862                }
    863            }
    864        }
    865        for (final NewAttributeBands bands : fieldAttributeBands) {
    866            if (bands.isUsedAtLeastOnce()) {
    867                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    868                    fieldAttrCalls.add(backwardsCallCount);
    869                }
    870            }
    871        }
    872        for (final NewAttributeBands bands : codeAttributeBands) {
    873            if (bands.isUsedAtLeastOnce()) {
    874                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    875                    codeAttrCalls.add(backwardsCallCount);
    876                }
    877            }
    878        }
    879
    880        class_attr_calls = classAttrCalls.toArray();
    881        field_attr_calls = fieldAttrCalls.toArray();
    882        method_attr_calls = methodAttrCalls.toArray();
    883        code_attr_calls = codeAttrCalls.toArray();
    884    }
    885
    886    private int[] getInts(final CPClass[] cpClasses) {
    887        final int[] ints = new int[cpClasses.length];
    888        for (int i = 0; i < ints.length; i++) {
    889            if (cpClasses[i] != null) {
    890                ints[i] = cpClasses[i].getIndex();
    891            }
    892        }
    893        return ints;
    894    }
    895
    896    /**
    897     * Tests whether there are any synthetic classes.
    898     *
    899     * @return whether there are any synthetic classes.
    900     */
    901    public boolean isAnySyntheticClasses() {
    902        return anySyntheticClasses;
    903    }
    904
    905    /**
    906     * Tests whether there are any synthetic fields.
    907     *
    908     * @return whether there are any synthetic fields.
    909     */
    910    public boolean isAnySyntheticFields() {
    911        return anySyntheticFields;
    912    }
    913
    914    /**
    915     * Tests whether there are any synthetic methods.
    916     *
    917     * @return whether there are any synthetic methods.
    918     */
    919    public boolean isAnySyntheticMethods() {
    920        return anySyntheticMethods;
    921    }
    922
    923    private boolean isInnerClass(final String possibleInner) {
    924        return possibleInner.indexOf('$') != -1;
    925    }
    926
    927    private boolean isInnerClassOf(final String possibleInner, final CPClass possibleOuter) {
    928        if (isInnerClass(possibleInner)) {
    929            final String superClassName = possibleInner.substring(0, possibleInner.lastIndexOf('$'));
    930            if (superClassName.equals(possibleOuter.toString())) {
    931                return true;
    932            }
    933            return isInnerClassOf(superClassName, possibleOuter);
    934        }
    935        return false;
    936    }
    937
    938    /**
    939     * Gets the number of classes processed.
    940     *
    941     * @return the number of classes processed.
    942     */
    943    public int numClassesProcessed() {
    944        return index;
    945    }
    946
    947    @Override
    948    public void pack(final OutputStream out) throws IOException, Pack200Exception {
    949        PackingUtils.log("Writing class bands...");
    950
    951        byte[] encodedBand = encodeBandInt("class_this", getInts(class_this), Codec.DELTA5);
    952        out.write(encodedBand);
    953        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_this[" + class_this.length + "]");
    954
    955        encodedBand = encodeBandInt("class_super", getInts(class_super), Codec.DELTA5);
    956        out.write(encodedBand);
    957        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_super[" + class_super.length + "]");
    958
    959        encodedBand = encodeBandInt("class_interface_count", class_interface_count, Codec.DELTA5);
    960        out.write(encodedBand);
    961        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface_count[" + class_interface_count.length + "]");
    962
    963        final int totalInterfaces = sum(class_interface_count);
    964        final int[] classInterface = new int[totalInterfaces];
    965        int k = 0;
    966        for (final CPClass[] element : class_interface) {
    967            if (element != null) {
    968                for (final CPClass cpClass : element) {
    969                    classInterface[k] = cpClass.getIndex();
    970                    k++;
    971                }
    972            }
    973        }
    974
    975        encodedBand = encodeBandInt("class_interface", classInterface, Codec.DELTA5);
    976        out.write(encodedBand);
    977        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface[" + classInterface.length + "]");
    978
    979        encodedBand = encodeBandInt("class_field_count", class_field_count, Codec.DELTA5);
    980        out.write(encodedBand);
    981        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_field_count[" + class_field_count.length + "]");
    982
    983        encodedBand = encodeBandInt("class_method_count", class_method_count, Codec.DELTA5);
    984        out.write(encodedBand);
    985        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_method_count[" + class_method_count.length + "]");
    986
    987        final int totalFields = sum(class_field_count);
    988        final int[] fieldDescr = new int[totalFields];
    989        k = 0;
    990        for (int i = 0; i < index; i++) {
    991            for (int j = 0; j < field_descr[i].length; j++) {
    992                final CPNameAndType descr = field_descr[i][j];
    993                fieldDescr[k] = descr.getIndex();
    994                k++;
    995            }
    996        }
    997
    998        encodedBand = encodeBandInt("field_descr", fieldDescr, Codec.DELTA5);
    999        out.write(encodedBand);
    1000        PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_descr[" + fieldDescr.length + "]");
    1001
    1002        writeFieldAttributeBands(out);
    1003
    1004        final int totalMethods = sum(class_method_count);
    1005        final int[] methodDescr = new int[totalMethods];
    1006        k = 0;
    1007        for (int i = 0; i < index; i++) {
    1008            for (int j = 0; j < method_descr[i].length; j++) {
    1009                final CPNameAndType descr = method_descr[i][j];
    1010                methodDescr[k] = descr.getIndex();
    1011                k++;
    1012            }
    1013        }
    1014
    1015        encodedBand = encodeBandInt("method_descr", methodDescr, Codec.MDELTA5);
    1016        out.write(encodedBand);
    1017        PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_descr[" + methodDescr.length + "]");
    1018
    1019        writeMethodAttributeBands(out);
    1020        writeClassAttributeBands(out);
    1021        writeCodeBands(out);
    1022    }
    1023
    1024    /**
    1025     * Remove all entries for the current class
    1026     */
    1027    public void removeCurrentClass() {
    1028        // Note - this doesn't remove any entries added to the constant pool but
    1029        // that shouldn't be a problem
    1030        if ((class_flags[index] & 1 << 17) != 0) {
    1031            classSourceFile.remove(classSourceFile.size() - 1);
    1032        }
    1033        if ((class_flags[index] & 1 << 18) != 0) {
    1034            classEnclosingMethodClass.remove(classEnclosingMethodClass.size() - 1);
    1035            classEnclosingMethodDesc.remove(classEnclosingMethodDesc.size() - 1);
    1036        }
    1037        if ((class_flags[index] & 1 << 19) != 0) {
    1038            classSignature.remove(classSignature.size() - 1);
    1039        }
    1040        if ((class_flags[index] & 1 << 21) != 0) {
    1041            class_RVA_bands.removeLatest();
    1042        }
    1043        if ((class_flags[index] & 1 << 22) != 0) {
    1044            class_RIA_bands.removeLatest();
    1045        }
    1046        for (final Long flagsL : tempFieldFlags) {
    1047            final long flags = flagsL.longValue();
    1048            if ((flags & 1 << 19) != 0) {
    1049                fieldSignature.remove(fieldSignature.size() - 1);
    1050            }
    1051            if ((flags & 1 << 17) != 0) {
    1052                fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1);
    1053            }
    1054            if ((flags & 1 << 21) != 0) {
    1055                field_RVA_bands.removeLatest();
    1056            }
    1057            if ((flags & 1 << 22) != 0) {
    1058                field_RIA_bands.removeLatest();
    1059            }
    1060        }
    1061        for (final Long flagsL : tempMethodFlags) {
    1062            final long flags = flagsL.longValue();
    1063            if ((flags & 1 << 19) != 0) {
    1064                methodSignature.remove(methodSignature.size() - 1);
    1065            }
    1066            if ((flags & 1 << 18) != 0) {
    1067                final int exceptions = methodExceptionNumber.remove(methodExceptionNumber.size() - 1);
    1068                for (int i = 0; i < exceptions; i++) {
    1069                    methodExceptionClasses.remove(methodExceptionClasses.size() - 1);
    1070                }
    1071            }
    1072            if ((flags & 1 << 17) != 0) { // has code attribute
    1073                codeMaxLocals.remove(codeMaxLocals.size() - 1);
    1074                codeMaxStack.remove(codeMaxStack.size() - 1);
    1075                final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
    1076                for (int i = 0; i < handlers; i++) {
    1077                    final int index = codeHandlerStartP.size() - 1;
    1078                    codeHandlerStartP.remove(index);
    1079                    codeHandlerEndPO.remove(index);
    1080                    codeHandlerCatchPO.remove(index);
    1081                    codeHandlerClass.remove(index);
    1082                }
    1083                if (!stripDebug) {
    1084                    final long cdeFlags = codeFlags.remove(codeFlags.size() - 1).longValue();
    1085                    final int numLocalVariables = codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
    1086                    for (int i = 0; i < numLocalVariables; i++) {
    1087                        final int location = codeLocalVariableTableBciP.size() - 1;
    1088                        codeLocalVariableTableBciP.remove(location);
    1089                        codeLocalVariableTableSpanO.remove(location);
    1090                        codeLocalVariableTableNameRU.remove(location);
    1091                        codeLocalVariableTableTypeRS.remove(location);
    1092                        codeLocalVariableTableSlot.remove(location);
    1093                    }
    1094                    if ((cdeFlags & 1 << 3) != 0) {
    1095                        final int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN.remove(codeLocalVariableTypeTableN.size() - 1);
    1096                        for (int i = 0; i < numLocalVariablesInTypeTable; i++) {
    1097                            final int location = codeLocalVariableTypeTableBciP.size() - 1;
    1098                            codeLocalVariableTypeTableBciP.remove(location);
    1099                            codeLocalVariableTypeTableSpanO.remove(location);
    1100                            codeLocalVariableTypeTableNameRU.remove(location);
    1101                            codeLocalVariableTypeTableTypeRS.remove(location);
    1102                            codeLocalVariableTypeTableSlot.remove(location);
    1103                        }
    1104                    }
    1105                    if ((cdeFlags & 1 << 1) != 0) {
    1106                        final int numLineNumbers = codeLineNumberTableN.remove(codeLineNumberTableN.size() - 1);
    1107                        for (int i = 0; i < numLineNumbers; i++) {
    1108                            final int location = codeLineNumberTableBciP.size() - 1;
    1109                            codeLineNumberTableBciP.remove(location);
    1110                            codeLineNumberTableLine.remove(location);
    1111                        }
    1112                    }
    1113                }
    1114            }
    1115            if ((flags & 1 << 21) != 0) {
    1116                method_RVA_bands.removeLatest();
    1117            }
    1118            if ((flags & 1 << 22) != 0) {
    1119                method_RIA_bands.removeLatest();
    1120            }
    1121            if ((flags & 1 << 23) != 0) {
    1122                method_RVPA_bands.removeLatest();
    1123            }
    1124            if ((flags & 1 << 24) != 0) {
    1125                method_RIPA_bands.removeLatest();
    1126            }
    1127            if ((flags & 1 << 25) != 0) {
    1128                method_AD_bands.removeLatest();
    1129            }
    1130        }
    1131        class_this[index] = null;
    1132        class_super[index] = null;
    1133        class_interface_count[index] = 0;
    1134        class_interface[index] = null;
    1135        major_versions[index] = 0;
    1136        class_flags[index] = 0;
    1137        tempFieldDesc.clear();
    1138        tempFieldFlags.clear();
    1139        tempMethodDesc.clear();
    1140        tempMethodFlags.clear();
    1141        if (index > 0) {
    1142            index--;
    1143        }
    1144    }
    1145
    1146    private void renumberBci(final List<Integer> list, final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
    1147        for (int i = list.size() - 1; i >= 0; i--) {
    1148            final Object label = list.get(i);
    1149            if (label instanceof Integer) {
    1150                break;
    1151            }
    1152            if (label instanceof Label) {
    1153                list.remove(i);
    1154                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1155                list.add(i, Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue())));
    1156            }
    1157        }
    1158    }
    1159
    1160    private void renumberDoubleOffsetBci(final List<Integer> relative, final List<Integer> firstOffset, final List<Object> list, final IntList bciRenumbering,
    1161            final Map<Label, Integer> labelsToOffsets) {
    1162        // TODO: There's probably a nicer way of doing this...
    1163        for (int i = list.size() - 1; i >= 0; i--) {
    1164            final Object label = list.get(i);
    1165            if (label instanceof Integer) {
    1166                break;
    1167            }
    1168            if (label instanceof Label) {
    1169                list.remove(i);
    1170                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1171                final Integer renumberedOffset = Integer
    1172                        .valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue() - firstOffset.get(i).intValue());
    1173                list.add(i, renumberedOffset);
    1174            }
    1175        }
    1176    }
    1177
    1178    private void renumberOffsetBci(final List<Integer> relative, final List<Integer> list, final IntList bciRenumbering,
    1179            final Map<Label, Integer> labelsToOffsets) {
    1180        for (int i = list.size() - 1; i >= 0; i--) {
    1181            final Object label = list.get(i);
    1182            if (label instanceof Integer) {
    1183                break;
    1184            }
    1185            if (label instanceof Label) {
    1186                list.remove(i);
    1187                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1188                final Integer renumberedOffset = Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue());
    1189                list.add(i, renumberedOffset);
    1190            }
    1191        }
    1192    }
    1193
    1194    private int sum(final int[] ints) {
    1195        int sum = 0;
    1196        for (final int j : ints) {
    1197            sum += j;
    1198        }
    1199        return sum;
    1200    }
    1201
    1202    private void writeClassAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1203        byte[] encodedBand = encodeFlags("class_flags", class_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_class_flags_hi());
    1204        out.write(encodedBand);
    1205        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_flags[" + class_flags.length + "]");
    1206
    1207        // These bands are not needed, but could be used to reduce the size of
    1208        // the archive if there are enough different non-standard attributes
    1209        // defined that segmentHeader.have_class_flags_hi() is true. The same
    1210        // applies to method_attr_count, field_attr_count, code_attr_count etc.
    1211
    1212        // *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1213        // *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]
    1214
    1215        encodedBand = encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5);
    1216        out.write(encodedBand);
    1217        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_attr_calls[" + class_attr_calls.length + "]");
    1218
    1219        encodedBand = encodeBandInt("classSourceFile", cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5);
    1220        out.write(encodedBand);
    1221        PackingUtils.log("Wrote " + encodedBand.length + " bytes from classSourceFile[" + classSourceFile.size() + "]");
    1222
    1223        encodedBand = encodeBandInt("class_enclosing_method_RC", cpEntryListToArray(classEnclosingMethodClass), Codec.UNSIGNED5);
    1224        out.write(encodedBand);
    1225        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_enclosing_method_RC[" + classEnclosingMethodClass.size() + "]");
    1226
    1227        encodedBand = encodeBandInt("class_EnclosingMethod_RDN", cpEntryOrNullListToArray(classEnclosingMethodDesc), Codec.UNSIGNED5);
    1228        out.write(encodedBand);
    1229        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_EnclosingMethod_RDN[" + classEnclosingMethodDesc.size() + "]");
    1230
    1231        encodedBand = encodeBandInt("class_Signature_RS", cpEntryListToArray(classSignature), Codec.UNSIGNED5);
    1232        out.write(encodedBand);
    1233        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_Signature_RS[" + classSignature.size() + "]");
    1234
    1235        class_RVA_bands.pack(out);
    1236        class_RIA_bands.pack(out);
    1237
    1238        encodedBand = encodeBandInt("class_InnerClasses_N", class_InnerClasses_N, Codec.UNSIGNED5);
    1239        out.write(encodedBand);
    1240        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_N[" + class_InnerClasses_N.length + "]");
    1241
    1242        encodedBand = encodeBandInt("class_InnerClasses_RC", getInts(class_InnerClasses_RC), Codec.UNSIGNED5);
    1243        out.write(encodedBand);
    1244        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_RC[" + class_InnerClasses_RC.length + "]");
    1245
    1246        encodedBand = encodeBandInt("class_InnerClasses_F", class_InnerClasses_F, Codec.UNSIGNED5);
    1247        out.write(encodedBand);
    1248        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_F[" + class_InnerClasses_F.length + "]");
    1249
    1250        encodedBand = encodeBandInt("class_InnerClasses_outer_RCN", cpEntryOrNullListToArray(classInnerClassesOuterRCN), Codec.UNSIGNED5);
    1251        out.write(encodedBand);
    1252        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_outer_RCN[" + classInnerClassesOuterRCN.size() + "]");
    1253
    1254        encodedBand = encodeBandInt("class_InnerClasses_name_RUN", cpEntryOrNullListToArray(classInnerClassesNameRUN), Codec.UNSIGNED5);
    1255        out.write(encodedBand);
    1256        PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_name_RUN[" + classInnerClassesNameRUN.size() + "]");
    1257
    1258        encodedBand = encodeBandInt("classFileVersionMinor", classFileVersionMinor.toArray(), Codec.UNSIGNED5);
    1259        out.write(encodedBand);
    1260        PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMinor[" + classFileVersionMinor.size() + "]");
    1261
    1262        encodedBand = encodeBandInt("classFileVersionMajor", classFileVersionMajor.toArray(), Codec.UNSIGNED5);
    1263        out.write(encodedBand);
    1264        PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMajor[" + classFileVersionMajor.size() + "]");
    1265
    1266        for (final NewAttributeBands classAttributeBand : classAttributeBands) {
    1267            classAttributeBand.pack(out);
    1268        }
    1269    }
    1270
    1271    private void writeCodeAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1272        byte[] encodedBand = encodeFlags("codeFlags", longListToArray(codeFlags), Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_code_flags_hi());
    1273        out.write(encodedBand);
    1274        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeFlags[" + codeFlags.size() + "]");
    1275
    1276        // *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1277        // *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
    1278        encodedBand = encodeBandInt("code_attr_calls", code_attr_calls, Codec.UNSIGNED5);
    1279        out.write(encodedBand);
    1280        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_attr_calls[" + code_attr_calls.length + "]");
    1281
    1282        encodedBand = encodeBandInt("code_LineNumberTable_N", codeLineNumberTableN.toArray(), Codec.UNSIGNED5);
    1283        out.write(encodedBand);
    1284        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_N[" + codeLineNumberTableN.size() + "]");
    1285
    1286        encodedBand = encodeBandInt("code_LineNumberTable_bci_P", integerListToArray(codeLineNumberTableBciP), Codec.BCI5);
    1287        out.write(encodedBand);
    1288        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_bci_P[" + codeLineNumberTableBciP.size() + "]");
    1289
    1290        encodedBand = encodeBandInt("code_LineNumberTable_line", codeLineNumberTableLine.toArray(), Codec.UNSIGNED5);
    1291        out.write(encodedBand);
    1292        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_line[" + codeLineNumberTableLine.size() + "]");
    1293
    1294        encodedBand = encodeBandInt("code_LocalVariableTable_N", codeLocalVariableTableN.toArray(), Codec.UNSIGNED5);
    1295        out.write(encodedBand);
    1296        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_N[" + codeLocalVariableTableN.size() + "]");
    1297
    1298        encodedBand = encodeBandInt("code_LocalVariableTable_bci_P", integerListToArray(codeLocalVariableTableBciP), Codec.BCI5);
    1299        out.write(encodedBand);
    1300        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_bci_P[" + codeLocalVariableTableBciP.size() + "]");
    1301
    1302        encodedBand = encodeBandInt("code_LocalVariableTable_span_O", integerListToArray(codeLocalVariableTableSpanO), Codec.BRANCH5);
    1303        out.write(encodedBand);
    1304        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_span_O[" + codeLocalVariableTableSpanO.size() + "]");
    1305
    1306        encodedBand = encodeBandInt("code_LocalVariableTable_name_RU", cpEntryListToArray(codeLocalVariableTableNameRU), Codec.UNSIGNED5);
    1307        out.write(encodedBand);
    1308        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_name_RU[" + codeLocalVariableTableNameRU.size() + "]");
    1309
    1310        encodedBand = encodeBandInt("code_LocalVariableTable_type_RS", cpEntryListToArray(codeLocalVariableTableTypeRS), Codec.UNSIGNED5);
    1311        out.write(encodedBand);
    1312        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_type_RS[" + codeLocalVariableTableTypeRS.size() + "]");
    1313
    1314        encodedBand = encodeBandInt("code_LocalVariableTable_slot", codeLocalVariableTableSlot.toArray(), Codec.UNSIGNED5);
    1315        out.write(encodedBand);
    1316        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_slot[" + codeLocalVariableTableSlot.size() + "]");
    1317
    1318        encodedBand = encodeBandInt("code_LocalVariableTypeTable_N", codeLocalVariableTypeTableN.toArray(), Codec.UNSIGNED5);
    1319        out.write(encodedBand);
    1320        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_N[" + codeLocalVariableTypeTableN.size() + "]");
    1321
    1322        encodedBand = encodeBandInt("code_LocalVariableTypeTable_bci_P", integerListToArray(codeLocalVariableTypeTableBciP), Codec.BCI5);
    1323        out.write(encodedBand);
    1324        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_bci_P[" + codeLocalVariableTypeTableBciP.size() + "]");
    1325
    1326        encodedBand = encodeBandInt("code_LocalVariableTypeTable_span_O", integerListToArray(codeLocalVariableTypeTableSpanO), Codec.BRANCH5);
    1327        out.write(encodedBand);
    1328        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_span_O[" + codeLocalVariableTypeTableSpanO.size() + "]");
    1329
    1330        encodedBand = encodeBandInt("code_LocalVariableTypeTable_name_RU", cpEntryListToArray(codeLocalVariableTypeTableNameRU), Codec.UNSIGNED5);
    1331        out.write(encodedBand);
    1332        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_name_RU[" + codeLocalVariableTypeTableNameRU.size() + "]");
    1333
    1334        encodedBand = encodeBandInt("code_LocalVariableTypeTable_type_RS", cpEntryListToArray(codeLocalVariableTypeTableTypeRS), Codec.UNSIGNED5);
    1335        out.write(encodedBand);
    1336        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_type_RS[" + codeLocalVariableTypeTableTypeRS.size() + "]");
    1337
    1338        encodedBand = encodeBandInt("code_LocalVariableTypeTable_slot", codeLocalVariableTypeTableSlot.toArray(), Codec.UNSIGNED5);
    1339        out.write(encodedBand);
    1340        PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_slot[" + codeLocalVariableTypeTableSlot.size() + "]");
    1341
    1342        for (final NewAttributeBands bands : codeAttributeBands) {
    1343            bands.pack(out);
    1344        }
    1345    }
    1346
    1347    private void writeCodeBands(final OutputStream out) throws IOException, Pack200Exception {
    1348        byte[] encodedBand = encodeBandInt("codeHeaders", codeHeaders, Codec.BYTE1);
    1349        out.write(encodedBand);
    1350        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHeaders[" + codeHeaders.length + "]");
    1351
    1352        encodedBand = encodeBandInt("codeMaxStack", codeMaxStack.toArray(), Codec.UNSIGNED5);
    1353        out.write(encodedBand);
    1354        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxStack[" + codeMaxStack.size() + "]");
    1355
    1356        encodedBand = encodeBandInt("codeMaxLocals", codeMaxLocals.toArray(), Codec.UNSIGNED5);
    1357        out.write(encodedBand);
    1358        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxLocals[" + codeMaxLocals.size() + "]");
    1359
    1360        encodedBand = encodeBandInt("codeHandlerCount", codeHandlerCount.toArray(), Codec.UNSIGNED5);
    1361        out.write(encodedBand);
    1362        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerCount[" + codeHandlerCount.size() + "]");
    1363
    1364        encodedBand = encodeBandInt("codeHandlerStartP", integerListToArray(codeHandlerStartP), Codec.BCI5);
    1365        out.write(encodedBand);
    1366        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerStartP[" + codeHandlerStartP.size() + "]");
    1367
    1368        encodedBand = encodeBandInt("codeHandlerEndPO", integerListToArray(codeHandlerEndPO), Codec.BRANCH5);
    1369        out.write(encodedBand);
    1370        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerEndPO[" + codeHandlerEndPO.size() + "]");
    1371
    1372        encodedBand = encodeBandInt("codeHandlerCatchPO", integerListToArray(codeHandlerCatchPO), Codec.BRANCH5);
    1373        out.write(encodedBand);
    1374        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerCatchPO[" + codeHandlerCatchPO.size() + "]");
    1375
    1376        encodedBand = encodeBandInt("codeHandlerClass", cpEntryOrNullListToArray(codeHandlerClass), Codec.UNSIGNED5);
    1377        out.write(encodedBand);
    1378        PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHandlerClass[" + codeHandlerClass.size() + "]");
    1379
    1380        writeCodeAttributeBands(out);
    1381    }
    1382
    1383    private void writeFieldAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1384        byte[] encodedBand = encodeFlags("field_flags", field_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_field_flags_hi());
    1385        out.write(encodedBand);
    1386        PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_flags[" + field_flags.length + "]");
    1387
    1388        // *field_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1389        // *field_attr_indexes :UNSIGNED5 [SUM(*field_attr_count)]
    1390        encodedBand = encodeBandInt("field_attr_calls", field_attr_calls, Codec.UNSIGNED5);
    1391        out.write(encodedBand);
    1392        PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_attr_calls[" + field_attr_calls.length + "]");
    1393
    1394        encodedBand = encodeBandInt("fieldConstantValueKQ", cpEntryListToArray(fieldConstantValueKQ), Codec.UNSIGNED5);
    1395        out.write(encodedBand);
    1396        PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldConstantValueKQ[" + fieldConstantValueKQ.size() + "]");
    1397
    1398        encodedBand = encodeBandInt("fieldSignature", cpEntryListToArray(fieldSignature), Codec.UNSIGNED5);
    1399        out.write(encodedBand);
    1400        PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldSignature[" + fieldSignature.size() + "]");
    1401
    1402        field_RVA_bands.pack(out);
    1403        field_RIA_bands.pack(out);
    1404        for (final NewAttributeBands bands : fieldAttributeBands) {
    1405            bands.pack(out);
    1406        }
    1407    }
    1408
    1409    private void writeMethodAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1410        byte[] encodedBand = encodeFlags("method_flags", method_flags, Codec.UNSIGNED5, Codec.UNSIGNED5, segmentHeader.have_method_flags_hi());
    1411        out.write(encodedBand);
    1412        PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_flags[" + method_flags.length + "]");
    1413
    1414        // *method_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1415        // *method_attr_indexes :UNSIGNED5 [SUM(*method_attr_count)]
    1416        encodedBand = encodeBandInt("method_attr_calls", method_attr_calls, Codec.UNSIGNED5);
    1417        out.write(encodedBand);
    1418        PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_attr_calls[" + method_attr_calls.length + "]");
    1419
    1420        encodedBand = encodeBandInt("methodExceptionNumber", methodExceptionNumber.toArray(), Codec.UNSIGNED5);
    1421        out.write(encodedBand);
    1422        PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionNumber[" + methodExceptionNumber.size() + "]");
    1423
    1424        encodedBand = encodeBandInt("methodExceptionClasses", cpEntryListToArray(methodExceptionClasses), Codec.UNSIGNED5);
    1425        out.write(encodedBand);
    1426        PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionClasses[" + methodExceptionClasses.size() + "]");
    1427
    1428        encodedBand = encodeBandInt("methodSignature", cpEntryListToArray(methodSignature), Codec.UNSIGNED5);
    1429        out.write(encodedBand);
    1430        PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodSignature[" + methodSignature.size() + "]");
    1431
    1432        method_RVA_bands.pack(out);
    1433        method_RIA_bands.pack(out);
    1434        method_RVPA_bands.pack(out);
    1435        method_RIPA_bands.pack(out);
    1436        method_AD_bands.pack(out);
    1437        for (final NewAttributeBands bands : methodAttributeBands) {
    1438            bands.pack(out);
    1439        }
    1440    }
    1441}