    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) && !isInnerClassOf(currentClass.toString(), inner)) {
    596                classReferencesInnerClass.computeIfAbsent(currentClass, c -> new HashSet<>()).add(inner);
    597            }
    598        }
    599    }
    600
    601        public void doBciRenumbering(final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
    602                renumberBci(codeLineNumberTableBciP, bciRenumbering, labelsToOffsets);
    603                renumberBci(codeLocalVariableTableBciP, bciRenumbering, labelsToOffsets);
    604                renumberOffsetBci(codeLocalVariableTableBciP, codeLocalVariableTableSpanO, bciRenumbering, labelsToOffsets);
    605                renumberBci(codeLocalVariableTypeTableBciP, bciRenumbering, labelsToOffsets);
    606                renumberOffsetBci(codeLocalVariableTypeTableBciP, codeLocalVariableTypeTableSpanO, bciRenumbering,
    607                                labelsToOffsets);
    608                renumberBci(codeHandlerStartP, bciRenumbering, labelsToOffsets);
    609                renumberOffsetBci(codeHandlerStartP, codeHandlerEndPO, bciRenumbering, labelsToOffsets);
    610                renumberDoubleOffsetBci(codeHandlerStartP, codeHandlerEndPO, codeHandlerCatchPO, bciRenumbering,
    611                                labelsToOffsets);
    612
    613                for (final NewAttributeBands newAttributeBandSet : classAttributeBands) {
    614                        newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    615                }
    616                for (final NewAttributeBands newAttributeBandSet : methodAttributeBands) {
    617                        newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    618                }
    619                for (final NewAttributeBands newAttributeBandSet : fieldAttributeBands) {
    620                        newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    621                }
    622                for (final NewAttributeBands newAttributeBandSet : codeAttributeBands) {
    623                        newAttributeBandSet.renumberBci(bciRenumbering, labelsToOffsets);
    624                }
    625        }
    626
    627        public void endOfClass() { // All the data for the current class has been
    628                                                                // read
    629                final int numFields = tempFieldDesc.size();
    630                class_field_count[index] = numFields;
    631                field_descr[index] = new CPNameAndType[numFields];
    632                field_flags[index] = new long[numFields];
    633                for (int i = 0; i < numFields; i++) {
    634                        field_descr[index][i] = tempFieldDesc.get(i);
    635                        field_flags[index][i] = tempFieldFlags.get(i).longValue();
    636                }
    637                final int numMethods = tempMethodDesc.size();
    638                class_method_count[index] = numMethods;
    639                method_descr[index] = new CPNameAndType[numMethods];
    640                method_flags[index] = new long[numMethods];
    641                for (int i = 0; i < numMethods; i++) {
    642                        method_descr[index][i] = tempMethodDesc.get(i);
    643                        method_flags[index][i] = tempMethodFlags.get(i).longValue();
    644                }
    645                tempFieldDesc.clear();
    646                tempFieldFlags.clear();
    647                tempMethodDesc.clear();
    648                tempMethodFlags.clear();
    649                index++;
    650        }
    651
    652        public void endOfMethod() {
    653                if (tempMethodRVPA != null) {
    654                        method_RVPA_bands.addParameterAnnotation(tempMethodRVPA.numParams, tempMethodRVPA.annoN,
    655                                        tempMethodRVPA.pairN, tempMethodRVPA.typeRS, tempMethodRVPA.nameRU, tempMethodRVPA.tags,
    656                                        tempMethodRVPA.values, tempMethodRVPA.caseArrayN, tempMethodRVPA.nestTypeRS,
    657                                        tempMethodRVPA.nestNameRU, tempMethodRVPA.nestPairN);
    658                        tempMethodRVPA = null;
    659                }
    660                if (tempMethodRIPA != null) {
    661                        method_RIPA_bands.addParameterAnnotation(tempMethodRIPA.numParams, tempMethodRIPA.annoN,
    662                                        tempMethodRIPA.pairN, tempMethodRIPA.typeRS, tempMethodRIPA.nameRU, tempMethodRIPA.tags,
    663                                        tempMethodRIPA.values, tempMethodRIPA.caseArrayN, tempMethodRIPA.nestTypeRS,
    664                                        tempMethodRIPA.nestNameRU, tempMethodRIPA.nestPairN);
    665                        tempMethodRIPA = null;
    666                }
    667                if (codeFlags.size() > 0) {
    668                        final long latestCodeFlag = codeFlags.get(codeFlags.size() - 1).longValue();
    669                        final int latestLocalVariableTableN = codeLocalVariableTableN.get(codeLocalVariableTableN.size() - 1);
    670                        if (latestCodeFlag == (1 << 2) && latestLocalVariableTableN == 0) {
    671                                codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
    672                                codeFlags.remove(codeFlags.size() - 1);
    673                                codeFlags.add(Long.valueOf(0));
    674                        }
    675                }
    676        }
    677
    678        /**
    679         * All input classes for the segment have now been read in, so this method is
    680         * called so that this class can calculate/complete anything it could not do
    681         * while classes were being read.
    682         */
    683        public void finaliseBands() {
    684                final int defaultMajorVersion = segmentHeader.getDefaultMajorVersion();
    685                for (int i = 0; i < class_flags.length; i++) {
    686                        final int major = major_versions[i];
    687                        if (major != defaultMajorVersion) {
    688                                class_flags[i] |= 1 << 24;
    689                                classFileVersionMajor.add(major);
    690                                classFileVersionMinor.add(0);
    691                        }
    692                }
    693                // Calculate code headers
    694                codeHeaders = new int[codeHandlerCount.size()];
    695                int removed = 0;
    696                for (int i = 0; i < codeHeaders.length; i++) {
    697                        final int numHandlers = codeHandlerCount.get(i - removed);
    698                        final int maxLocals = codeMaxLocals.get(i - removed);
    699                        final int maxStack = codeMaxStack.get(i - removed);
    700                        switch (numHandlers) {
    701            case 0: {
    702                final int header = maxLocals * 12 + maxStack + 1;
    703                if (header < 145 && maxStack < 12) {
    704                                        codeHeaders[i] = header;
    705                                }
    706                break;
    707            }
    708            case 1: {
    709                final int header = maxLocals * 8 + maxStack + 145;
    710                if (header < 209 && maxStack < 8) {
    711                                        codeHeaders[i] = header;
    712                                }
    713                break;
    714            }
    715            case 2: {
    716                final int header = maxLocals * 7 + maxStack + 209;
    717                if (header < 256 && maxStack < 7) {
    718                                        codeHeaders[i] = header;
    719                                }
    720                break;
    721            }
    722            default:
    723                break;
    724            }
    725                        if (codeHeaders[i] != 0) { // Remove the redundant values from
    726                                                                                // codeHandlerCount, codeMaxLocals and
    727                                                                                // codeMaxStack
    728                                codeHandlerCount.remove(i - removed);
    729                                codeMaxLocals.remove(i - removed);
    730                                codeMaxStack.remove(i - removed);
    731                                removed++;
    732                        } else if (!segment.getSegmentHeader().have_all_code_flags()) {
    733                                codeFlags.add(Long.valueOf(0));
    734                        }
    735                }
    736
    737                // Compute any required IcLocals
    738                final IntList innerClassesN = new IntList();
    739                final List<IcTuple> icLocal = new ArrayList<>();
    740                for (int i = 0; i < class_this.length; i++) {
    741                        final CPClass cpClass = class_this[i];
    742                        final Set<CPClass> referencedInnerClasses = classReferencesInnerClass.get(cpClass);
    743                        if (referencedInnerClasses != null) {
    744                                int innerN = 0;
    745                                final List<IcTuple> innerClasses = segment.getIcBands().getInnerClassesForOuter(cpClass.toString());
    746                                if (innerClasses != null) {
    747                                        for (final IcTuple element : innerClasses) {
    748                                                referencedInnerClasses.remove(element.C);
    749                                        }
    750                                }
    751                                for (final CPClass inner : referencedInnerClasses) {
    752                                        final IcTuple icTuple = segment.getIcBands().getIcTuple(inner);
    753                                        if (icTuple != null && !icTuple.isAnonymous()) {
    754                                                // should transmit an icLocal entry
    755                                                icLocal.add(icTuple);
    756                                                innerN++;
    757                                        }
    758                                }
    759                                if (innerN != 0) {
    760                                        innerClassesN.add(innerN);
    761                                        class_flags[i] |= (1 << 23);
    762                                }
    763                        }
    764                }
    765                class_InnerClasses_N = innerClassesN.toArray();
    766                class_InnerClasses_RC = new CPClass[icLocal.size()];
    767                class_InnerClasses_F = new int[icLocal.size()];
    768                classInnerClassesOuterRCN = new ArrayList<>();
    769                classInnerClassesNameRUN = new ArrayList<>();
    770                for (int i = 0; i < class_InnerClasses_RC.length; i++) {
    771                        final IcTuple icTuple = icLocal.get(i);
    772                        class_InnerClasses_RC[i] = (icTuple.C);
    773                        if (icTuple.C2 == null && icTuple.N == null) {
    774                                class_InnerClasses_F[i] = 0;
    775                        } else {
    776                                if (icTuple.F == 0) {
    777                                        class_InnerClasses_F[i] = 0x00010000;
    778                                } else {
    779                                        class_InnerClasses_F[i] = icTuple.F;
    780                                }
    781                                classInnerClassesOuterRCN.add(icTuple.C2);
    782                                classInnerClassesNameRUN.add(icTuple.N);
    783                        }
    784                }
    785                // Calculate any backwards calls from metadata bands
    786                final IntList classAttrCalls = new IntList();
    787                final IntList fieldAttrCalls = new IntList();
    788                final IntList methodAttrCalls = new IntList();
    789                final IntList codeAttrCalls = new IntList();
    790
    791                if (class_RVA_bands.hasContent()) {
    792                        classAttrCalls.add(class_RVA_bands.numBackwardsCalls());
    793                }
    794                if (class_RIA_bands.hasContent()) {
    795                        classAttrCalls.add(class_RIA_bands.numBackwardsCalls());
    796                }
    797                if (field_RVA_bands.hasContent()) {
    798                        fieldAttrCalls.add(field_RVA_bands.numBackwardsCalls());
    799                }
    800                if (field_RIA_bands.hasContent()) {
    801                        fieldAttrCalls.add(field_RIA_bands.numBackwardsCalls());
    802                }
    803                if (method_RVA_bands.hasContent()) {
    804                        methodAttrCalls.add(method_RVA_bands.numBackwardsCalls());
    805                }
    806                if (method_RIA_bands.hasContent()) {
    807                        methodAttrCalls.add(method_RIA_bands.numBackwardsCalls());
    808                }
    809                if (method_RVPA_bands.hasContent()) {
    810                        methodAttrCalls.add(method_RVPA_bands.numBackwardsCalls());
    811                }
    812                if (method_RIPA_bands.hasContent()) {
    813                        methodAttrCalls.add(method_RIPA_bands.numBackwardsCalls());
    814                }
    815                if (method_AD_bands.hasContent()) {
    816                        methodAttrCalls.add(method_AD_bands.numBackwardsCalls());
    817                }
    818
    819                // Sort non-predefined attribute bands
    820                final Comparator<NewAttributeBands> comparator = (arg0, arg1) -> arg0.getFlagIndex() - arg1.getFlagIndex();
    821                classAttributeBands.sort(comparator);
    822                methodAttributeBands.sort(comparator);
    823                fieldAttributeBands.sort(comparator);
    824                codeAttributeBands.sort(comparator);
    825
    826                for (final NewAttributeBands bands : classAttributeBands) {
    827                        if (bands.isUsedAtLeastOnce()) {
    828                                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    829                                        classAttrCalls.add(backwardsCallCount);
    830                                }
    831                        }
    832                }
    833                for (final NewAttributeBands bands : methodAttributeBands) {
    834                        if (bands.isUsedAtLeastOnce()) {
    835                                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    836                                        methodAttrCalls.add(backwardsCallCount);
    837                                }
    838                        }
    839                }
    840                for (final NewAttributeBands bands : fieldAttributeBands) {
    841                        if (bands.isUsedAtLeastOnce()) {
    842                                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    843                                        fieldAttrCalls.add(backwardsCallCount);
    844                                }
    845                        }
    846                }
    847                for (final NewAttributeBands bands : codeAttributeBands) {
    848                        if (bands.isUsedAtLeastOnce()) {
    849                                for (final int backwardsCallCount : bands.numBackwardsCalls()) {
    850                                        codeAttrCalls.add(backwardsCallCount);
    851                                }
    852                        }
    853                }
    854
    855                class_attr_calls = classAttrCalls.toArray();
    856                field_attr_calls = fieldAttrCalls.toArray();
    857                method_attr_calls = methodAttrCalls.toArray();
    858                code_attr_calls = codeAttrCalls.toArray();
    859        }
    860
    861        private int[] getInts(final CPClass[] cpClasses) {
    862                final int[] ints = new int[cpClasses.length];
    863                for (int i = 0; i < ints.length; i++) {
    864                        if (cpClasses[i] != null) {
    865                                ints[i] = cpClasses[i].getIndex();
    866                        }
    867                }
    868                return ints;
    869        }
    870
    871        public boolean isAnySyntheticClasses() {
    872                return anySyntheticClasses;
    873        }
    874
    875        public boolean isAnySyntheticFields() {
    876                return anySyntheticFields;
    877        }
    878
    879        public boolean isAnySyntheticMethods() {
    880                return anySyntheticMethods;
    881        }
    882
    883        private boolean isInnerClass(final String possibleInner) {
    884                return possibleInner.indexOf('$') != -1;
    885        }
    886
    887        private boolean isInnerClassOf(final String possibleInner, final CPClass possibleOuter) {
    888                if (isInnerClass(possibleInner)) {
    889                        final String superClassName = possibleInner.substring(0, possibleInner.lastIndexOf('$'));
    890                        if (superClassName.equals(possibleOuter.toString())) {
    891                                return true;
    892                        }
    893                        return isInnerClassOf(superClassName, possibleOuter);
    894                }
    895                return false;
    896        }
    897
    898        public int numClassesProcessed() {
    899                return index;
    900        }
    901
    902        @Override
    903        public void pack(final OutputStream out) throws IOException, Pack200Exception {
    904                PackingUtils.log("Writing class bands...");
    905
    906                byte[] encodedBand = encodeBandInt("class_this", getInts(class_this), Codec.DELTA5);
    907                out.write(encodedBand);
    908                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_this[" + class_this.length + "]");
    909
    910                encodedBand = encodeBandInt("class_super", getInts(class_super), Codec.DELTA5);
    911                out.write(encodedBand);
    912                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_super[" + class_super.length + "]");
    913
    914                encodedBand = encodeBandInt("class_interface_count", class_interface_count, Codec.DELTA5);
    915                out.write(encodedBand);
    916                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface_count["
    917                                + class_interface_count.length + "]");
    918
    919                final int totalInterfaces = sum(class_interface_count);
    920                final int[] classInterface = new int[totalInterfaces];
    921                int k = 0;
    922                for (final CPClass[] element : class_interface) {
    923                        if (element != null) {
    924                                for (final CPClass cpClass : element) {
    925                                        classInterface[k] = cpClass.getIndex();
    926                                        k++;
    927                                }
    928                        }
    929                }
    930
    931                encodedBand = encodeBandInt("class_interface", classInterface, Codec.DELTA5);
    932                out.write(encodedBand);
    933                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_interface[" + classInterface.length + "]");
    934
    935                encodedBand = encodeBandInt("class_field_count", class_field_count, Codec.DELTA5);
    936                out.write(encodedBand);
    937                PackingUtils
    938                                .log("Wrote " + encodedBand.length + " bytes from class_field_count[" + class_field_count.length + "]");
    939
    940                encodedBand = encodeBandInt("class_method_count", class_method_count, Codec.DELTA5);
    941                out.write(encodedBand);
    942                PackingUtils.log(
    943                                "Wrote " + encodedBand.length + " bytes from class_method_count[" + class_method_count.length + "]");
    944
    945                final int totalFields = sum(class_field_count);
    946                final int[] fieldDescr = new int[totalFields];
    947                k = 0;
    948                for (int i = 0; i < index; i++) {
    949                        for (int j = 0; j < field_descr[i].length; j++) {
    950                                final CPNameAndType descr = field_descr[i][j];
    951                                fieldDescr[k] = descr.getIndex();
    952                                k++;
    953                        }
    954                }
    955
    956                encodedBand = encodeBandInt("field_descr", fieldDescr, Codec.DELTA5);
    957                out.write(encodedBand);
    958                PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_descr[" + fieldDescr.length + "]");
    959
    960                writeFieldAttributeBands(out);
    961
    962                final int totalMethods = sum(class_method_count);
    963                final int[] methodDescr = new int[totalMethods];
    964                k = 0;
    965                for (int i = 0; i < index; i++) {
    966                        for (int j = 0; j < method_descr[i].length; j++) {
    967                                final CPNameAndType descr = method_descr[i][j];
    968                                methodDescr[k] = descr.getIndex();
    969                                k++;
    970                        }
    971                }
    972
    973                encodedBand = encodeBandInt("method_descr", methodDescr, Codec.MDELTA5);
    974                out.write(encodedBand);
    975                PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_descr[" + methodDescr.length + "]");
    976
    977                writeMethodAttributeBands(out);
    978                writeClassAttributeBands(out);
    979                writeCodeBands(out);
    980        }
    981
    982        /**
    983         * Remove all entries for the current class
    984         */
    985        public void removeCurrentClass() {
    986                // Note - this doesn't remove any entries added to the constant pool but
    987                // that shouldn't be a problem
    988                if ((class_flags[index] & (1 << 17)) != 0) {
    989                        classSourceFile.remove(classSourceFile.size() - 1);
    990                }
    991                if ((class_flags[index] & (1 << 18)) != 0) {
    992                        classEnclosingMethodClass.remove(classEnclosingMethodClass.size() - 1);
    993                        classEnclosingMethodDesc.remove(classEnclosingMethodDesc.size() - 1);
    994                }
    995                if ((class_flags[index] & (1 << 19)) != 0) {
    996                        classSignature.remove(classSignature.size() - 1);
    997                }
    998                if ((class_flags[index] & (1 << 21)) != 0) {
    999                        class_RVA_bands.removeLatest();
    1000                }
    1001                if ((class_flags[index] & (1 << 22)) != 0) {
    1002                        class_RIA_bands.removeLatest();
    1003                }
    1004                for (final Long flagsL : tempFieldFlags) {
    1005                        final long flags = flagsL.longValue();
    1006                        if ((flags & (1 << 19)) != 0) {
    1007                                fieldSignature.remove(fieldSignature.size() - 1);
    1008                        }
    1009                        if ((flags & (1 << 17)) != 0) {
    1010                                fieldConstantValueKQ.remove(fieldConstantValueKQ.size() - 1);
    1011                        }
    1012                        if ((flags & (1 << 21)) != 0) {
    1013                                field_RVA_bands.removeLatest();
    1014                        }
    1015                        if ((flags & (1 << 22)) != 0) {
    1016                                field_RIA_bands.removeLatest();
    1017                        }
    1018                }
    1019                for (final Long flagsL : tempMethodFlags) {
    1020                        final long flags = flagsL.longValue();
    1021                        if ((flags & (1 << 19)) != 0) {
    1022                                methodSignature.remove(methodSignature.size() - 1);
    1023                        }
    1024                        if ((flags & (1 << 18)) != 0) {
    1025                                final int exceptions = methodExceptionNumber.remove(methodExceptionNumber.size() - 1);
    1026                                for (int i = 0; i < exceptions; i++) {
    1027                                        methodExceptionClasses.remove(methodExceptionClasses.size() - 1);
    1028                                }
    1029                        }
    1030                        if ((flags & (1 << 17)) != 0) { // has code attribute
    1031                                codeMaxLocals.remove(codeMaxLocals.size() - 1);
    1032                                codeMaxStack.remove(codeMaxStack.size() - 1);
    1033                                final int handlers = codeHandlerCount.remove(codeHandlerCount.size() - 1);
    1034                                for (int i = 0; i < handlers; i++) {
    1035                                        final int index = codeHandlerStartP.size() - 1;
    1036                                        codeHandlerStartP.remove(index);
    1037                                        codeHandlerEndPO.remove(index);
    1038                                        codeHandlerCatchPO.remove(index);
    1039                                        codeHandlerClass.remove(index);
    1040                                }
    1041                                if (!stripDebug) {
    1042                                        final long cdeFlags = codeFlags.remove(codeFlags.size() - 1).longValue();
    1043                                        final int numLocalVariables = codeLocalVariableTableN.remove(codeLocalVariableTableN.size() - 1);
    1044                                        for (int i = 0; i < numLocalVariables; i++) {
    1045                                                final int location = codeLocalVariableTableBciP.size() - 1;
    1046                                                codeLocalVariableTableBciP.remove(location);
    1047                                                codeLocalVariableTableSpanO.remove(location);
    1048                                                codeLocalVariableTableNameRU.remove(location);
    1049                                                codeLocalVariableTableTypeRS.remove(location);
    1050                                                codeLocalVariableTableSlot.remove(location);
    1051                                        }
    1052                                        if ((cdeFlags & (1 << 3)) != 0) {
    1053                                                final int numLocalVariablesInTypeTable = codeLocalVariableTypeTableN
    1054                                                                .remove(codeLocalVariableTypeTableN.size() - 1);
    1055                                                for (int i = 0; i < numLocalVariablesInTypeTable; i++) {
    1056                                                        final int location = codeLocalVariableTypeTableBciP.size() - 1;
    1057                                                        codeLocalVariableTypeTableBciP.remove(location);
    1058                                                        codeLocalVariableTypeTableSpanO.remove(location);
    1059                                                        codeLocalVariableTypeTableNameRU.remove(location);
    1060                                                        codeLocalVariableTypeTableTypeRS.remove(location);
    1061                                                        codeLocalVariableTypeTableSlot.remove(location);
    1062                                                }
    1063                                        }
    1064                                        if ((cdeFlags & (1 << 1)) != 0) {
    1065                                                final int numLineNumbers = codeLineNumberTableN.remove(codeLineNumberTableN.size() - 1);
    1066                                                for (int i = 0; i < numLineNumbers; i++) {
    1067                                                        final int location = codeLineNumberTableBciP.size() - 1;
    1068                                                        codeLineNumberTableBciP.remove(location);
    1069                                                        codeLineNumberTableLine.remove(location);
    1070                                                }
    1071                                        }
    1072                                }
    1073                        }
    1074                        if ((flags & (1 << 21)) != 0) {
    1075                                method_RVA_bands.removeLatest();
    1076                        }
    1077                        if ((flags & (1 << 22)) != 0) {
    1078                                method_RIA_bands.removeLatest();
    1079                        }
    1080                        if ((flags & (1 << 23)) != 0) {
    1081                                method_RVPA_bands.removeLatest();
    1082                        }
    1083                        if ((flags & (1 << 24)) != 0) {
    1084                                method_RIPA_bands.removeLatest();
    1085                        }
    1086                        if ((flags & (1 << 25)) != 0) {
    1087                                method_AD_bands.removeLatest();
    1088                        }
    1089                }
    1090                class_this[index] = null;
    1091                class_super[index] = null;
    1092                class_interface_count[index] = 0;
    1093                class_interface[index] = null;
    1094                major_versions[index] = 0;
    1095                class_flags[index] = 0;
    1096                tempFieldDesc.clear();
    1097                tempFieldFlags.clear();
    1098                tempMethodDesc.clear();
    1099                tempMethodFlags.clear();
    1100                if (index > 0) {
    1101                        index--;
    1102                }
    1103        }
    1104
    1105        private void renumberBci(final List<Integer> list, final IntList bciRenumbering,
    1106                        final Map<Label, Integer> labelsToOffsets) {
    1107                for (int i = list.size() - 1; i >= 0; i--) {
    1108                        final Object label = list.get(i);
    1109                        if (label instanceof Integer) {
    1110                                break;
    1111                        }
    1112                        if (label instanceof Label) {
    1113                                list.remove(i);
    1114                                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1115                                list.add(i, Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue())));
    1116                        }
    1117                }
    1118        }
    1119
    1120        private void renumberDoubleOffsetBci(final List<Integer> relative, final List<Integer> firstOffset, final List<Object> list,
    1121                        final IntList bciRenumbering, final Map<Label, Integer> labelsToOffsets) {
    1122                // TODO: There's probably a nicer way of doing this...
    1123                for (int i = list.size() - 1; i >= 0; i--) {
    1124                        final Object label = list.get(i);
    1125                        if (label instanceof Integer) {
    1126                                break;
    1127                        }
    1128                        if (label instanceof Label) {
    1129                                list.remove(i);
    1130                                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1131                                final Integer renumberedOffset = Integer.valueOf(bciRenumbering.get(bytecodeIndex.intValue())
    1132                                                - relative.get(i).intValue() - firstOffset.get(i).intValue());
    1133                                list.add(i, renumberedOffset);
    1134                        }
    1135                }
    1136        }
    1137
    1138        private void renumberOffsetBci(final List<Integer> relative, final List<Integer> list, final IntList bciRenumbering,
    1139                        final Map<Label, Integer> labelsToOffsets) {
    1140                for (int i = list.size() - 1; i >= 0; i--) {
    1141                        final Object label = list.get(i);
    1142                        if (label instanceof Integer) {
    1143                                break;
    1144                        }
    1145                        if (label instanceof Label) {
    1146                                list.remove(i);
    1147                                final Integer bytecodeIndex = labelsToOffsets.get(label);
    1148                                final Integer renumberedOffset = Integer
    1149                                                .valueOf(bciRenumbering.get(bytecodeIndex.intValue()) - relative.get(i).intValue());
    1150                                list.add(i, renumberedOffset);
    1151                        }
    1152                }
    1153        }
    1154
    1155        private int sum(final int[] ints) {
    1156                int sum = 0;
    1157                for (final int j : ints) {
    1158                        sum += j;
    1159                }
    1160                return sum;
    1161        }
    1162
    1163        private void writeClassAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1164                byte[] encodedBand = encodeFlags("class_flags", class_flags, Codec.UNSIGNED5, Codec.UNSIGNED5,
    1165                                segmentHeader.have_class_flags_hi());
    1166                out.write(encodedBand);
    1167                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_flags[" + class_flags.length + "]");
    1168
    1169                // These bands are not needed, but could be used to reduce the size of
    1170                // the archive if there are enough different non-standard attributes
    1171                // defined that segmentHeader.have_class_flags_hi() is true. The same
    1172                // applies to method_attr_count, field_attr_count, code_attr_count etc.
    1173
    1174                // *class_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1175                // *class_attr_indexes :UNSIGNED5 [SUM(*class_attr_count)]
    1176
    1177                encodedBand = encodeBandInt("class_attr_calls", class_attr_calls, Codec.UNSIGNED5);
    1178                out.write(encodedBand);
    1179                PackingUtils
    1180                                .log("Wrote " + encodedBand.length + " bytes from class_attr_calls[" + class_attr_calls.length + "]");
    1181
    1182                encodedBand = encodeBandInt("classSourceFile", cpEntryOrNullListToArray(classSourceFile), Codec.UNSIGNED5);
    1183                out.write(encodedBand);
    1184                PackingUtils.log("Wrote " + encodedBand.length + " bytes from classSourceFile[" + classSourceFile.size() + "]");
    1185
    1186                encodedBand = encodeBandInt("class_enclosing_method_RC", cpEntryListToArray(classEnclosingMethodClass),
    1187                                Codec.UNSIGNED5);
    1188                out.write(encodedBand);
    1189                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_enclosing_method_RC["
    1190                                + classEnclosingMethodClass.size() + "]");
    1191
    1192                encodedBand = encodeBandInt("class_EnclosingMethod_RDN", cpEntryOrNullListToArray(classEnclosingMethodDesc),
    1193                                Codec.UNSIGNED5);
    1194                out.write(encodedBand);
    1195                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_EnclosingMethod_RDN["
    1196                                + classEnclosingMethodDesc.size() + "]");
    1197
    1198                encodedBand = encodeBandInt("class_Signature_RS", cpEntryListToArray(classSignature), Codec.UNSIGNED5);
    1199                out.write(encodedBand);
    1200                PackingUtils
    1201                                .log("Wrote " + encodedBand.length + " bytes from class_Signature_RS[" + classSignature.size() + "]");
    1202
    1203                class_RVA_bands.pack(out);
    1204                class_RIA_bands.pack(out);
    1205
    1206                encodedBand = encodeBandInt("class_InnerClasses_N", class_InnerClasses_N, Codec.UNSIGNED5);
    1207                out.write(encodedBand);
    1208                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_N["
    1209                                + class_InnerClasses_N.length + "]");
    1210
    1211                encodedBand = encodeBandInt("class_InnerClasses_RC", getInts(class_InnerClasses_RC), Codec.UNSIGNED5);
    1212                out.write(encodedBand);
    1213                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_RC["
    1214                                + class_InnerClasses_RC.length + "]");
    1215
    1216                encodedBand = encodeBandInt("class_InnerClasses_F", class_InnerClasses_F, Codec.UNSIGNED5);
    1217                out.write(encodedBand);
    1218                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_F["
    1219                                + class_InnerClasses_F.length + "]");
    1220
    1221                encodedBand = encodeBandInt("class_InnerClasses_outer_RCN", cpEntryOrNullListToArray(classInnerClassesOuterRCN),
    1222                                Codec.UNSIGNED5);
    1223                out.write(encodedBand);
    1224                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_outer_RCN["
    1225                                + classInnerClassesOuterRCN.size() + "]");
    1226
    1227                encodedBand = encodeBandInt("class_InnerClasses_name_RUN", cpEntryOrNullListToArray(classInnerClassesNameRUN),
    1228                                Codec.UNSIGNED5);
    1229                out.write(encodedBand);
    1230                PackingUtils.log("Wrote " + encodedBand.length + " bytes from class_InnerClasses_name_RUN["
    1231                                + classInnerClassesNameRUN.size() + "]");
    1232
    1233                encodedBand = encodeBandInt("classFileVersionMinor", classFileVersionMinor.toArray(), Codec.UNSIGNED5);
    1234                out.write(encodedBand);
    1235                PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMinor["
    1236                                + classFileVersionMinor.size() + "]");
    1237
    1238                encodedBand = encodeBandInt("classFileVersionMajor", classFileVersionMajor.toArray(), Codec.UNSIGNED5);
    1239                out.write(encodedBand);
    1240                PackingUtils.log("Wrote " + encodedBand.length + " bytes from classFileVersionMajor["
    1241                                + classFileVersionMajor.size() + "]");
    1242
    1243                for (final NewAttributeBands classAttributeBand : classAttributeBands) {
    1244                        classAttributeBand.pack(out);
    1245                }
    1246        }
    1247
    1248        private void writeCodeAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1249                byte[] encodedBand = encodeFlags("codeFlags", longListToArray(codeFlags), Codec.UNSIGNED5, Codec.UNSIGNED5,
    1250                                segmentHeader.have_code_flags_hi());
    1251                out.write(encodedBand);
    1252                PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeFlags[" + codeFlags.size() + "]");
    1253
    1254                // *code_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1255                // *code_attr_indexes :UNSIGNED5 [SUM(*code_attr_count)]
    1256                encodedBand = encodeBandInt("code_attr_calls", code_attr_calls, Codec.UNSIGNED5);
    1257                out.write(encodedBand);
    1258                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_attr_calls[" + code_attr_calls.length + "]");
    1259
    1260                encodedBand = encodeBandInt("code_LineNumberTable_N", codeLineNumberTableN.toArray(), Codec.UNSIGNED5);
    1261                out.write(encodedBand);
    1262                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_N["
    1263                                + codeLineNumberTableN.size() + "]");
    1264
    1265                encodedBand = encodeBandInt("code_LineNumberTable_bci_P", integerListToArray(codeLineNumberTableBciP),
    1266                                Codec.BCI5);
    1267                out.write(encodedBand);
    1268                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_bci_P["
    1269                                + codeLineNumberTableBciP.size() + "]");
    1270
    1271                encodedBand = encodeBandInt("code_LineNumberTable_line", codeLineNumberTableLine.toArray(), Codec.UNSIGNED5);
    1272                out.write(encodedBand);
    1273                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LineNumberTable_line["
    1274                                + codeLineNumberTableLine.size() + "]");
    1275
    1276                encodedBand = encodeBandInt("code_LocalVariableTable_N", codeLocalVariableTableN.toArray(), Codec.UNSIGNED5);
    1277                out.write(encodedBand);
    1278                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_N["
    1279                                + codeLocalVariableTableN.size() + "]");
    1280
    1281                encodedBand = encodeBandInt("code_LocalVariableTable_bci_P", integerListToArray(codeLocalVariableTableBciP),
    1282                                Codec.BCI5);
    1283                out.write(encodedBand);
    1284                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_bci_P["
    1285                                + codeLocalVariableTableBciP.size() + "]");
    1286
    1287                encodedBand = encodeBandInt("code_LocalVariableTable_span_O", integerListToArray(codeLocalVariableTableSpanO),
    1288                                Codec.BRANCH5);
    1289                out.write(encodedBand);
    1290                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_span_O["
    1291                                + codeLocalVariableTableSpanO.size() + "]");
    1292
    1293                encodedBand = encodeBandInt("code_LocalVariableTable_name_RU", cpEntryListToArray(codeLocalVariableTableNameRU),
    1294                                Codec.UNSIGNED5);
    1295                out.write(encodedBand);
    1296                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_name_RU["
    1297                                + codeLocalVariableTableNameRU.size() + "]");
    1298
    1299                encodedBand = encodeBandInt("code_LocalVariableTable_type_RS", cpEntryListToArray(codeLocalVariableTableTypeRS),
    1300                                Codec.UNSIGNED5);
    1301                out.write(encodedBand);
    1302                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_type_RS["
    1303                                + codeLocalVariableTableTypeRS.size() + "]");
    1304
    1305                encodedBand = encodeBandInt("code_LocalVariableTable_slot", codeLocalVariableTableSlot.toArray(),
    1306                                Codec.UNSIGNED5);
    1307                out.write(encodedBand);
    1308                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTable_slot["
    1309                                + codeLocalVariableTableSlot.size() + "]");
    1310
    1311                encodedBand = encodeBandInt("code_LocalVariableTypeTable_N", codeLocalVariableTypeTableN.toArray(),
    1312                                Codec.UNSIGNED5);
    1313                out.write(encodedBand);
    1314                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_N["
    1315                                + codeLocalVariableTypeTableN.size() + "]");
    1316
    1317                encodedBand = encodeBandInt("code_LocalVariableTypeTable_bci_P",
    1318                                integerListToArray(codeLocalVariableTypeTableBciP), Codec.BCI5);
    1319                out.write(encodedBand);
    1320                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_bci_P["
    1321                                + codeLocalVariableTypeTableBciP.size() + "]");
    1322
    1323                encodedBand = encodeBandInt("code_LocalVariableTypeTable_span_O",
    1324                                integerListToArray(codeLocalVariableTypeTableSpanO), Codec.BRANCH5);
    1325                out.write(encodedBand);
    1326                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_span_O["
    1327                                + codeLocalVariableTypeTableSpanO.size() + "]");
    1328
    1329                encodedBand = encodeBandInt("code_LocalVariableTypeTable_name_RU",
    1330                                cpEntryListToArray(codeLocalVariableTypeTableNameRU), Codec.UNSIGNED5);
    1331                out.write(encodedBand);
    1332                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_name_RU["
    1333                                + codeLocalVariableTypeTableNameRU.size() + "]");
    1334
    1335                encodedBand = encodeBandInt("code_LocalVariableTypeTable_type_RS",
    1336                                cpEntryListToArray(codeLocalVariableTypeTableTypeRS), Codec.UNSIGNED5);
    1337                out.write(encodedBand);
    1338                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_type_RS["
    1339                                + codeLocalVariableTypeTableTypeRS.size() + "]");
    1340
    1341                encodedBand = encodeBandInt("code_LocalVariableTypeTable_slot", codeLocalVariableTypeTableSlot.toArray(),
    1342                                Codec.UNSIGNED5);
    1343                out.write(encodedBand);
    1344                PackingUtils.log("Wrote " + encodedBand.length + " bytes from code_LocalVariableTypeTable_slot["
    1345                                + codeLocalVariableTypeTableSlot.size() + "]");
    1346
    1347                for (final NewAttributeBands bands : codeAttributeBands) {
    1348                        bands.pack(out);
    1349                }
    1350        }
    1351
    1352        private void writeCodeBands(final OutputStream out) throws IOException, Pack200Exception {
    1353                byte[] encodedBand = encodeBandInt("codeHeaders", codeHeaders, Codec.BYTE1);
    1354                out.write(encodedBand);
    1355                PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeHeaders[" + codeHeaders.length + "]");
    1356
    1357                encodedBand = encodeBandInt("codeMaxStack", codeMaxStack.toArray(), Codec.UNSIGNED5);
    1358                out.write(encodedBand);
    1359                PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxStack[" + codeMaxStack.size() + "]");
    1360
    1361                encodedBand = encodeBandInt("codeMaxLocals", codeMaxLocals.toArray(), Codec.UNSIGNED5);
    1362                out.write(encodedBand);
    1363                PackingUtils.log("Wrote " + encodedBand.length + " bytes from codeMaxLocals[" + codeMaxLocals.size() + "]");
    1364
    1365                encodedBand = encodeBandInt("codeHandlerCount", codeHandlerCount.toArray(), Codec.UNSIGNED5);
    1366                out.write(encodedBand);
    1367                PackingUtils
    1368                                .log("Wrote " + encodedBand.length + " bytes from codeHandlerCount[" + codeHandlerCount.size() + "]");
    1369
    1370                encodedBand = encodeBandInt("codeHandlerStartP", integerListToArray(codeHandlerStartP), Codec.BCI5);
    1371                out.write(encodedBand);
    1372                PackingUtils
    1373                                .log("Wrote " + encodedBand.length + " bytes from codeHandlerStartP[" + codeHandlerStartP.size() + "]");
    1374
    1375                encodedBand = encodeBandInt("codeHandlerEndPO", integerListToArray(codeHandlerEndPO), Codec.BRANCH5);
    1376                out.write(encodedBand);
    1377                PackingUtils
    1378                                .log("Wrote " + encodedBand.length + " bytes from codeHandlerEndPO[" + codeHandlerEndPO.size() + "]");
    1379
    1380                encodedBand = encodeBandInt("codeHandlerCatchPO", integerListToArray(codeHandlerCatchPO), Codec.BRANCH5);
    1381                out.write(encodedBand);
    1382                PackingUtils.log(
    1383                                "Wrote " + encodedBand.length + " bytes from codeHandlerCatchPO[" + codeHandlerCatchPO.size() + "]");
    1384
    1385                encodedBand = encodeBandInt("codeHandlerClass", cpEntryOrNullListToArray(codeHandlerClass), Codec.UNSIGNED5);
    1386                out.write(encodedBand);
    1387                PackingUtils
    1388                                .log("Wrote " + encodedBand.length + " bytes from codeHandlerClass[" + codeHandlerClass.size() + "]");
    1389
    1390                writeCodeAttributeBands(out);
    1391        }
    1392
    1393        private void writeFieldAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1394                byte[] encodedBand = encodeFlags("field_flags", field_flags, Codec.UNSIGNED5, Codec.UNSIGNED5,
    1395                                segmentHeader.have_field_flags_hi());
    1396                out.write(encodedBand);
    1397                PackingUtils.log("Wrote " + encodedBand.length + " bytes from field_flags[" + field_flags.length + "]");
    1398
    1399                // *field_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1400                // *field_attr_indexes :UNSIGNED5 [SUM(*field_attr_count)]
    1401                encodedBand = encodeBandInt("field_attr_calls", field_attr_calls, Codec.UNSIGNED5);
    1402                out.write(encodedBand);
    1403                PackingUtils
    1404                                .log("Wrote " + encodedBand.length + " bytes from field_attr_calls[" + field_attr_calls.length + "]");
    1405
    1406                encodedBand = encodeBandInt("fieldConstantValueKQ", cpEntryListToArray(fieldConstantValueKQ), Codec.UNSIGNED5);
    1407                out.write(encodedBand);
    1408                PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldConstantValueKQ["
    1409                                + fieldConstantValueKQ.size() + "]");
    1410
    1411                encodedBand = encodeBandInt("fieldSignature", cpEntryListToArray(fieldSignature), Codec.UNSIGNED5);
    1412                out.write(encodedBand);
    1413                PackingUtils.log("Wrote " + encodedBand.length + " bytes from fieldSignature[" + fieldSignature.size() + "]");
    1414
    1415                field_RVA_bands.pack(out);
    1416                field_RIA_bands.pack(out);
    1417                for (final NewAttributeBands bands : fieldAttributeBands) {
    1418                        bands.pack(out);
    1419                }
    1420        }
    1421
    1422        private void writeMethodAttributeBands(final OutputStream out) throws IOException, Pack200Exception {
    1423                byte[] encodedBand = encodeFlags("method_flags", method_flags, Codec.UNSIGNED5, Codec.UNSIGNED5,
    1424                                segmentHeader.have_method_flags_hi());
    1425                out.write(encodedBand);
    1426                PackingUtils.log("Wrote " + encodedBand.length + " bytes from method_flags[" + method_flags.length + "]");
    1427
    1428                // *method_attr_count :UNSIGNED5 [COUNT(1<<16,...)]
    1429                // *method_attr_indexes :UNSIGNED5 [SUM(*method_attr_count)]
    1430                encodedBand = encodeBandInt("method_attr_calls", method_attr_calls, Codec.UNSIGNED5);
    1431                out.write(encodedBand);
    1432                PackingUtils
    1433                                .log("Wrote " + encodedBand.length + " bytes from method_attr_calls[" + method_attr_calls.length + "]");
    1434
    1435                encodedBand = encodeBandInt("methodExceptionNumber", methodExceptionNumber.toArray(), Codec.UNSIGNED5);
    1436                out.write(encodedBand);
    1437                PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionNumber["
    1438                                + methodExceptionNumber.size() + "]");
    1439
    1440                encodedBand = encodeBandInt("methodExceptionClasses", cpEntryListToArray(methodExceptionClasses),
    1441                                Codec.UNSIGNED5);
    1442                out.write(encodedBand);
    1443                PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodExceptionClasses["
    1444                                + methodExceptionClasses.size() + "]");
    1445
    1446                encodedBand = encodeBandInt("methodSignature", cpEntryListToArray(methodSignature), Codec.UNSIGNED5);
    1447                out.write(encodedBand);
    1448                PackingUtils.log("Wrote " + encodedBand.length + " bytes from methodSignature[" + methodSignature.size() + "]");
    1449
    1450                method_RVA_bands.pack(out);
    1451                method_RIA_bands.pack(out);
    1452                method_RVPA_bands.pack(out);
    1453                method_RIPA_bands.pack(out);
    1454                method_AD_bands.pack(out);
    1455                for (final NewAttributeBands bands : methodAttributeBands) {
    1456                        bands.pack(out);
    1457                }
    1458        }
    1459}