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