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.unpack200;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.util.ArrayList;
022import java.util.List;
023
024import org.apache.commons.compress.harmony.pack200.Codec;
025import org.apache.commons.compress.harmony.pack200.Pack200Exception;
026import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
027import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
028import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
029import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
030import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
031import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantValueAttribute;
032import org.apache.commons.compress.harmony.unpack200.bytecode.DeprecatedAttribute;
033import org.apache.commons.compress.harmony.unpack200.bytecode.EnclosingMethodAttribute;
034import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionsAttribute;
035import org.apache.commons.compress.harmony.unpack200.bytecode.LineNumberTableAttribute;
036import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTableAttribute;
037import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute;
038import org.apache.commons.compress.harmony.unpack200.bytecode.SignatureAttribute;
039import org.apache.commons.compress.harmony.unpack200.bytecode.SourceFileAttribute;
040
041/**
042 * Class Bands
043 */
044public class ClassBands extends BandSet {
045
046    private int[] classFieldCount;
047
048    private long[] classFlags;
049
050    private long[] classAccessFlags; // Access flags for writing to the class
051    // file
052
053    private int[][] classInterfacesInts;
054
055    private int[] classMethodCount;
056
057    private int[] classSuperInts;
058
059    private String[] classThis;
060
061    private int[] classThisInts;
062
063    private ArrayList[] classAttributes;
064
065    private int[] classVersionMajor;
066
067    private int[] classVersionMinor;
068
069    private IcTuple[][] icLocal;
070
071    private List[] codeAttributes;
072
073    private int[] codeHandlerCount;
074
075    private int[] codeMaxNALocals;
076
077    private int[] codeMaxStack;
078
079    private ArrayList[][] fieldAttributes;
080
081    private String[][] fieldDescr;
082
083    private int[][] fieldDescrInts;
084
085    private long[][] fieldFlags;
086
087    private long[][] fieldAccessFlags;
088
089    private ArrayList[][] methodAttributes;
090
091    private String[][] methodDescr;
092
093    private int[][] methodDescrInts;
094
095    private long[][] methodFlags;
096
097    private long[][] methodAccessFlags;
098
099    private final AttributeLayoutMap attrMap;
100
101    private final CpBands cpBands;
102
103    private final SegmentOptions options;
104
105    private final int classCount;
106
107    private int[] methodAttrCalls;
108
109    private int[][] codeHandlerStartP;
110
111    private int[][] codeHandlerEndPO;
112
113    private int[][] codeHandlerCatchPO;
114
115    private int[][] codeHandlerClassRCN;
116
117    private boolean[] codeHasAttributes;
118
119    /**
120     * @param segment TODO
121     */
122    public ClassBands(final Segment segment) {
123        super(segment);
124        this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
125        this.cpBands = segment.getCpBands();
126        this.classCount = header.getClassCount();
127        this.options = header.getOptions();
128
129    }
130
131    /*
132     * (non-Javadoc)
133     *
134     * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream)
135     */
136    @Override
137    public void read(final InputStream in) throws IOException, Pack200Exception {
138        final int classCount = header.getClassCount();
139        classThisInts = decodeBandInt("class_this", in, Codec.DELTA5, classCount);
140        classThis = getReferences(classThisInts, cpBands.getCpClass());
141        classSuperInts = decodeBandInt("class_super", in, Codec.DELTA5, classCount);
142        final int[] classInterfaceLengths = decodeBandInt("class_interface_count", in, Codec.DELTA5, classCount);
143        classInterfacesInts = decodeBandInt("class_interface", in, Codec.DELTA5, classInterfaceLengths);
144        classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount);
145        classMethodCount = decodeBandInt("class_method_count", in, Codec.DELTA5, classCount);
146        parseFieldBands(in);
147        parseMethodBands(in);
148        parseClassAttrBands(in);
149        parseCodeBands(in);
150
151    }
152
153    @Override
154    public void unpack() {
155
156    }
157
158    private void parseFieldBands(final InputStream in) throws IOException, Pack200Exception {
159        fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5, classFieldCount);
160        fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor());
161        parseFieldAttrBands(in);
162    }
163
164    private void parseFieldAttrBands(final InputStream in) throws IOException, Pack200Exception {
165        fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi());
166        final int fieldAttrCount = SegmentUtils.countBit16(fieldFlags);
167        final int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount);
168        final int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts);
169        final int callCount = getCallCount(fieldAttrIndexes, fieldFlags, AttributeLayout.CONTEXT_FIELD);
170        final int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in, Codec.UNSIGNED5, callCount);
171
172        // Assign empty field attributes
173        fieldAttributes = new ArrayList[classCount][];
174        for (int i = 0; i < classCount; i++) {
175            fieldAttributes[i] = new ArrayList[fieldFlags[i].length];
176            for (int j = 0; j < fieldFlags[i].length; j++) {
177                fieldAttributes[i][j] = new ArrayList();
178            }
179        }
180
181        final AttributeLayout constantValueLayout = attrMap.getAttributeLayout("ConstantValue",
182            AttributeLayout.CONTEXT_FIELD);
183        final int constantCount = SegmentUtils.countMatches(fieldFlags, constantValueLayout);
184        final int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5,
185            constantCount);
186        int constantValueIndex = 0;
187
188        final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE,
189            AttributeLayout.CONTEXT_FIELD);
190        final int signatureCount = SegmentUtils.countMatches(fieldFlags, signatureLayout);
191        final int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
192        int signatureIndex = 0;
193
194        final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED,
195            AttributeLayout.CONTEXT_FIELD);
196
197        for (int i = 0; i < classCount; i++) {
198            for (int j = 0; j < fieldFlags[i].length; j++) {
199                final long flag = fieldFlags[i][j];
200                if (deprecatedLayout.matches(flag)) {
201                    fieldAttributes[i][j].add(new DeprecatedAttribute());
202                }
203                if (constantValueLayout.matches(flag)) {
204                    // we've got a value to read
205                    final long result = field_constantValue_KQ[constantValueIndex];
206                    final String desc = fieldDescr[i][j];
207                    final int colon = desc.indexOf(':');
208                    String type = desc.substring(colon + 1);
209                    if (type.equals("B") || type.equals("S") || type.equals("C") || type.equals("Z")) {
210                        type = "I";
211                    }
212                    final ClassFileEntry value = constantValueLayout.getValue(result, type, cpBands.getConstantPool());
213                    fieldAttributes[i][j].add(new ConstantValueAttribute(value));
214                    constantValueIndex++;
215                }
216                if (signatureLayout.matches(flag)) {
217                    // we've got a signature attribute
218                    final long result = fieldSignatureRS[signatureIndex];
219                    final String desc = fieldDescr[i][j];
220                    final int colon = desc.indexOf(':');
221                    final String type = desc.substring(colon + 1);
222                    final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, type, cpBands.getConstantPool());
223                    fieldAttributes[i][j].add(new SignatureAttribute(value));
224                    signatureIndex++;
225                }
226            }
227        }
228
229        final int backwardsCallsUsed = parseFieldMetadataBands(in, fieldAttrCalls);
230
231        // Parse non-predefined attribute bands
232        int backwardsCallIndex = backwardsCallsUsed;
233        final int limit = options.hasFieldFlagsHi() ? 62 : 31;
234        final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
235        final int[] counts = new int[limit + 1];
236        final List[] otherAttributes = new List[limit + 1];
237        for (int i = 0; i < limit; i++) {
238            final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
239            if (layout != null && !(layout.isDefaultLayout())) {
240                otherLayouts[i] = layout;
241                counts[i] = SegmentUtils.countMatches(fieldFlags, layout);
242            }
243        }
244        for (int i = 0; i < counts.length; i++) {
245            if (counts[i] > 0) {
246                final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
247                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
248                final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
249                if (numBackwardsCallables > 0) {
250                    final int[] backwardsCalls = new int[numBackwardsCallables];
251                    System.arraycopy(fieldAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
252                    bands.setBackwardsCalls(backwardsCalls);
253                    backwardsCallIndex += numBackwardsCallables;
254                }
255            }
256        }
257
258        // Non-predefined attributes
259        for (int i = 0; i < classCount; i++) {
260            for (int j = 0; j < fieldFlags[i].length; j++) {
261                final long flag = fieldFlags[i][j];
262                int othersAddedAtStart = 0;
263                for (int k = 0; k < otherLayouts.length; k++) {
264                    if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
265                        // Add the next attribute
266                        if (otherLayouts[k].getIndex() < 15) {
267                            fieldAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
268                        } else {
269                            fieldAttributes[i][j].add(otherAttributes[k].get(0));
270                        }
271                        otherAttributes[k].remove(0);
272                    }
273                }
274            }
275        }
276    }
277
278    private void parseMethodBands(final InputStream in) throws IOException, Pack200Exception {
279        methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5, classMethodCount);
280        methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor());
281        parseMethodAttrBands(in);
282    }
283
284    private void parseMethodAttrBands(final InputStream in) throws IOException, Pack200Exception {
285        methodFlags = parseFlags("method_flags", in, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi());
286        final int methodAttrCount = SegmentUtils.countBit16(methodFlags);
287        final int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount);
288        final int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts);
289        final int callCount = getCallCount(methodAttrIndexes, methodFlags, AttributeLayout.CONTEXT_METHOD);
290        methodAttrCalls = decodeBandInt("method_attr_calls", in, Codec.UNSIGNED5, callCount);
291
292        // assign empty method attributes
293        methodAttributes = new ArrayList[classCount][];
294        for (int i = 0; i < classCount; i++) {
295            methodAttributes[i] = new ArrayList[methodFlags[i].length];
296            for (int j = 0; j < methodFlags[i].length; j++) {
297                methodAttributes[i][j] = new ArrayList();
298            }
299        }
300
301        // Parse method exceptions attributes
302        final AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS,
303            AttributeLayout.CONTEXT_METHOD);
304        final int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout);
305        final int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count);
306        final int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions);
307
308        // Parse method signature attributes
309        final AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE,
310            AttributeLayout.CONTEXT_METHOD);
311        final int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout);
312        final int[] methodSignatureRS = decodeBandInt("method_signature_RS", in, Codec.UNSIGNED5, count1);
313
314        final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED,
315            AttributeLayout.CONTEXT_METHOD);
316
317        // Add attributes to the attribute arrays
318        int methodExceptionsIndex = 0;
319        int methodSignatureIndex = 0;
320        for (int i = 0; i < methodAttributes.length; i++) {
321            for (int j = 0; j < methodAttributes[i].length; j++) {
322                final long flag = methodFlags[i][j];
323                if (methodExceptionsLayout.matches(flag)) {
324                    final int n = numExceptions[methodExceptionsIndex];
325                    final int[] exceptions = methodExceptionsRS[methodExceptionsIndex];
326                    final CPClass[] exceptionClasses = new CPClass[n];
327                    for (int k = 0; k < n; k++) {
328                        exceptionClasses[k] = cpBands.cpClassValue(exceptions[k]);
329                    }
330                    methodAttributes[i][j].add(new ExceptionsAttribute(exceptionClasses));
331                    methodExceptionsIndex++;
332                }
333                if (methodSignatureLayout.matches(flag)) {
334                    // We've got a signature attribute
335                    final long result = methodSignatureRS[methodSignatureIndex];
336                    final String desc = methodDescr[i][j];
337                    final int colon = desc.indexOf(':');
338                    String type = desc.substring(colon + 1);
339                    // TODO Got to get better at this ... in any case, it should
340                    // be e.g. KIB or KIH
341                    if (type.equals("B") || type.equals("H")) {
342                        type = "I";
343                    }
344                    final CPUTF8 value = (CPUTF8) methodSignatureLayout.getValue(result, type,
345                        cpBands.getConstantPool());
346                    methodAttributes[i][j].add(new SignatureAttribute(value));
347                    methodSignatureIndex++;
348                }
349                if (deprecatedLayout.matches(flag)) {
350                    methodAttributes[i][j].add(new DeprecatedAttribute());
351                }
352            }
353        }
354
355        // Parse method metadata bands
356        final int backwardsCallsUsed = parseMethodMetadataBands(in, methodAttrCalls);
357
358        // Parse non-predefined attribute bands
359        int backwardsCallIndex = backwardsCallsUsed;
360        final int limit = options.hasMethodFlagsHi() ? 62 : 31;
361        final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
362        final int[] counts = new int[limit + 1];
363        final List[] otherAttributes = new List[limit + 1];
364        for (int i = 0; i < limit; i++) {
365            final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
366            if (layout != null && !(layout.isDefaultLayout())) {
367                otherLayouts[i] = layout;
368                counts[i] = SegmentUtils.countMatches(methodFlags, layout);
369            }
370        }
371        for (int i = 0; i < counts.length; i++) {
372            if (counts[i] > 0) {
373                final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
374                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
375                final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
376                if (numBackwardsCallables > 0) {
377                    final int[] backwardsCalls = new int[numBackwardsCallables];
378                    System.arraycopy(methodAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
379                    bands.setBackwardsCalls(backwardsCalls);
380                    backwardsCallIndex += numBackwardsCallables;
381                }
382            }
383        }
384
385        // Non-predefined attributes
386        for (int i = 0; i < methodAttributes.length; i++) {
387            for (int j = 0; j < methodAttributes[i].length; j++) {
388                final long flag = methodFlags[i][j];
389                int othersAddedAtStart = 0;
390                for (int k = 0; k < otherLayouts.length; k++) {
391                    if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) {
392                        // Add the next attribute
393                        if (otherLayouts[k].getIndex() < 15) {
394                            methodAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0));
395                        } else {
396                            methodAttributes[i][j].add(otherAttributes[k].get(0));
397                        }
398                        otherAttributes[k].remove(0);
399                    }
400                }
401            }
402        }
403    }
404
405    private int getCallCount(final int[][] methodAttrIndexes, final long[][] flags, final int context)
406        throws Pack200Exception {
407        int callCount = 0;
408        for (int i = 0; i < methodAttrIndexes.length; i++) {
409            for (int j = 0; j < methodAttrIndexes[i].length; j++) {
410                final int index = methodAttrIndexes[i][j];
411                final AttributeLayout layout = attrMap.getAttributeLayout(index, context);
412                callCount += layout.numBackwardsCallables();
413            }
414        }
415        int layoutsUsed = 0;
416        for (int i = 0; i < flags.length; i++) {
417            for (int j = 0; j < flags[i].length; j++) {
418                layoutsUsed |= flags[i][j];
419            }
420        }
421        for (int i = 0; i < 26; i++) {
422            if ((layoutsUsed & 1 << i) != 0) {
423                final AttributeLayout layout = attrMap.getAttributeLayout(i, context);
424                callCount += layout.numBackwardsCallables();
425            }
426        }
427        return callCount;
428    }
429
430    private void parseClassAttrBands(final InputStream in) throws IOException, Pack200Exception {
431        final String[] cpUTF8 = cpBands.getCpUTF8();
432        final String[] cpClass = cpBands.getCpClass();
433
434        // Prepare empty attribute lists
435        classAttributes = new ArrayList[classCount];
436        for (int i = 0; i < classCount; i++) {
437            classAttributes[i] = new ArrayList();
438        }
439
440        classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5, options.hasClassFlagsHi());
441        final int classAttrCount = SegmentUtils.countBit16(classFlags);
442        final int[] classAttrCounts = decodeBandInt("class_attr_count", in, Codec.UNSIGNED5, classAttrCount);
443        final int[][] classAttrIndexes = decodeBandInt("class_attr_indexes", in, Codec.UNSIGNED5, classAttrCounts);
444        final int callCount = getCallCount(classAttrIndexes, new long[][] {classFlags}, AttributeLayout.CONTEXT_CLASS);
445        final int[] classAttrCalls = decodeBandInt("class_attr_calls", in, Codec.UNSIGNED5, callCount);
446
447        final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED,
448            AttributeLayout.CONTEXT_CLASS);
449
450        final AttributeLayout sourceFileLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE,
451            AttributeLayout.CONTEXT_CLASS);
452        final int sourceFileCount = SegmentUtils.countMatches(classFlags, sourceFileLayout);
453        final int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, Codec.UNSIGNED5, sourceFileCount);
454
455        final AttributeLayout enclosingMethodLayout = attrMap
456            .getAttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS);
457        final int enclosingMethodCount = SegmentUtils.countMatches(classFlags, enclosingMethodLayout);
458        final int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, Codec.UNSIGNED5,
459            enclosingMethodCount);
460        final int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, Codec.UNSIGNED5,
461            enclosingMethodCount);
462
463        final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE,
464            AttributeLayout.CONTEXT_CLASS);
465        final int signatureCount = SegmentUtils.countMatches(classFlags, signatureLayout);
466        final int[] classSignature = decodeBandInt("class_Signature_RS", in, Codec.UNSIGNED5, signatureCount);
467
468        final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls);
469
470        final AttributeLayout innerClassLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES,
471            AttributeLayout.CONTEXT_CLASS);
472        final int innerClassCount = SegmentUtils.countMatches(classFlags, innerClassLayout);
473        final int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, Codec.UNSIGNED5, innerClassCount);
474        final int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5,
475            classInnerClassesN);
476        final int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5,
477            classInnerClassesN);
478        int flagsCount = 0;
479        for (int i = 0; i < classInnerClassesF.length; i++) {
480            for (int j = 0; j < classInnerClassesF[i].length; j++) {
481                if (classInnerClassesF[i][j] != 0) {
482                    flagsCount++;
483                }
484            }
485        }
486        final int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5,
487            flagsCount);
488        final int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5,
489            flagsCount);
490
491        final AttributeLayout versionLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION,
492            AttributeLayout.CONTEXT_CLASS);
493        final int versionCount = SegmentUtils.countMatches(classFlags, versionLayout);
494        final int[] classFileVersionMinorH = decodeBandInt("class_file_version_minor_H", in, Codec.UNSIGNED5,
495            versionCount);
496        final int[] classFileVersionMajorH = decodeBandInt("class_file_version_major_H", in, Codec.UNSIGNED5,
497            versionCount);
498        if (versionCount > 0) {
499            classVersionMajor = new int[classCount];
500            classVersionMinor = new int[classCount];
501        }
502        final int defaultVersionMajor = header.getDefaultClassMajorVersion();
503        final int defaultVersionMinor = header.getDefaultClassMinorVersion();
504
505        // Parse non-predefined attribute bands
506        int backwardsCallIndex = backwardsCallsUsed;
507        final int limit = options.hasClassFlagsHi() ? 62 : 31;
508        final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
509        final int[] counts = new int[limit + 1];
510        final List[] otherAttributes = new List[limit + 1];
511        for (int i = 0; i < limit; i++) {
512            final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
513            if (layout != null && !(layout.isDefaultLayout())) {
514                otherLayouts[i] = layout;
515                counts[i] = SegmentUtils.countMatches(classFlags, layout);
516            }
517        }
518        for (int i = 0; i < counts.length; i++) {
519            if (counts[i] > 0) {
520                final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
521                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
522                final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
523                if (numBackwardsCallables > 0) {
524                    final int[] backwardsCalls = new int[numBackwardsCallables];
525                    System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
526                    bands.setBackwardsCalls(backwardsCalls);
527                    backwardsCallIndex += numBackwardsCallables;
528                }
529            }
530        }
531
532        // Now process the attribute bands we have parsed
533        int sourceFileIndex = 0;
534        int enclosingMethodIndex = 0;
535        int signatureIndex = 0;
536        int innerClassIndex = 0;
537        int innerClassC2NIndex = 0;
538        int versionIndex = 0;
539        icLocal = new IcTuple[classCount][];
540        for (int i = 0; i < classCount; i++) {
541            final long flag = classFlags[i];
542            if (deprecatedLayout.matches(classFlags[i])) {
543                classAttributes[i].add(new DeprecatedAttribute());
544            }
545            if (sourceFileLayout.matches(flag)) {
546                final long result = classSourceFile[sourceFileIndex];
547                ClassFileEntry value = sourceFileLayout.getValue(result, cpBands.getConstantPool());
548                if (value == null) {
549                    // Remove package prefix
550                    String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1);
551                    className = className.substring(className.lastIndexOf('.') + 1);
552
553                    // Remove mangled nested class names
554                    final char[] chars = className.toCharArray();
555                    int index = -1;
556                    for (int j = 0; j < chars.length; j++) {
557                        if (chars[j] <= 0x2D) {
558                            index = j;
559                            break;
560                        }
561                    }
562                    if (index > -1) {
563                        className = className.substring(0, index);
564                    }
565                    // Add .java to the end
566                    value = cpBands.cpUTF8Value(className + ".java", true);
567                }
568                classAttributes[i].add(new SourceFileAttribute((CPUTF8) value));
569                sourceFileIndex++;
570            }
571            if (enclosingMethodLayout.matches(flag)) {
572                final CPClass theClass = cpBands.cpClassValue(enclosingMethodRC[enclosingMethodIndex]);
573                CPNameAndType theMethod = null;
574                if (enclosingMethodRDN[enclosingMethodIndex] != 0) {
575                    theMethod = cpBands.cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1);
576                }
577                classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod));
578                enclosingMethodIndex++;
579            }
580            if (signatureLayout.matches(flag)) {
581                final long result = classSignature[signatureIndex];
582                final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands.getConstantPool());
583                classAttributes[i].add(new SignatureAttribute(value));
584                signatureIndex++;
585            }
586            if (innerClassLayout.matches(flag)) {
587                // Just create the tuples for now because the attributes are
588                // decided at the end when creating class constant pools
589                icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]];
590                for (int j = 0; j < icLocal[i].length; j++) {
591                    final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j];
592                    int icTupleC2Index = -1;
593                    int icTupleNIndex = -1;
594
595                    final String icTupleC = cpClass[icTupleCIndex];
596                    int icTupleF = classInnerClassesF[innerClassIndex][j];
597                    String icTupleC2 = null;
598                    String icTupleN = null;
599
600                    if (icTupleF != 0) {
601                        icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex];
602                        icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex];
603                        icTupleC2 = cpClass[icTupleC2Index];
604                        icTupleN = cpUTF8[icTupleNIndex];
605                        innerClassC2NIndex++;
606                    } else {
607                        // Get from icBands
608                        final IcBands icBands = segment.getIcBands();
609                        final IcTuple[] icAll = icBands.getIcTuples();
610                        for (int k = 0; k < icAll.length; k++) {
611                            if (icAll[k].getC().equals(icTupleC)) {
612                                icTupleF = icAll[k].getF();
613                                icTupleC2 = icAll[k].getC2();
614                                icTupleN = icAll[k].getN();
615                                break;
616                            }
617                        }
618                    }
619
620                    final IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, icTupleCIndex,
621                        icTupleC2Index, icTupleNIndex, j);
622                    icLocal[i][j] = icTuple;
623                }
624                innerClassIndex++;
625            }
626            if (versionLayout.matches(flag)) {
627                classVersionMajor[i] = classFileVersionMajorH[versionIndex];
628                classVersionMinor[i] = classFileVersionMinorH[versionIndex];
629                versionIndex++;
630            } else if (classVersionMajor != null) {
631                // Fill in with defaults
632                classVersionMajor[i] = defaultVersionMajor;
633                classVersionMinor[i] = defaultVersionMinor;
634            }
635            // Non-predefined attributes
636            for (int j = 0; j < otherLayouts.length; j++) {
637                if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) {
638                    // Add the next attribute
639                    classAttributes[i].add(otherAttributes[j].get(0));
640                    otherAttributes[j].remove(0);
641                }
642            }
643        }
644    }
645
646    private void parseCodeBands(final InputStream in) throws Pack200Exception, IOException {
647        final AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CODE,
648            AttributeLayout.CONTEXT_METHOD);
649
650        final int codeCount = SegmentUtils.countMatches(methodFlags, layout);
651        final int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, codeCount);
652
653        final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags();
654        if (!allCodeHasFlags) {
655            codeHasAttributes = new boolean[codeCount];
656        }
657        int codeSpecialHeader = 0;
658        for (int i = 0; i < codeCount; i++) {
659            if (codeHeaders[i] == 0) {
660                codeSpecialHeader++;
661                if (!allCodeHasFlags) {
662                    codeHasAttributes[i] = true;
663                }
664            }
665        }
666        final int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, Codec.UNSIGNED5, codeSpecialHeader);
667        final int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, Codec.UNSIGNED5,
668            codeSpecialHeader);
669        final int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", in, Codec.UNSIGNED5,
670            codeSpecialHeader);
671
672        codeMaxStack = new int[codeCount];
673        codeMaxNALocals = new int[codeCount];
674        codeHandlerCount = new int[codeCount];
675        int special = 0;
676        for (int i = 0; i < codeCount; i++) {
677            final int header = 0xff & codeHeaders[i];
678            if (header < 0) {
679                throw new IllegalStateException("Shouldn't get here");
680            }
681            if (header == 0) {
682                codeMaxStack[i] = codeMaxStackSpecials[special];
683                codeMaxNALocals[i] = codeMaxNALocalsSpecials[special];
684                codeHandlerCount[i] = codeHandlerCountSpecials[special];
685                special++;
686            } else if (header <= 144) {
687                codeMaxStack[i] = (header - 1) % 12;
688                codeMaxNALocals[i] = (header - 1) / 12;
689                codeHandlerCount[i] = 0;
690            } else if (header <= 208) {
691                codeMaxStack[i] = (header - 145) % 8;
692                codeMaxNALocals[i] = (header - 145) / 8;
693                codeHandlerCount[i] = 1;
694            } else if (header <= 255) {
695                codeMaxStack[i] = (header - 209) % 7;
696                codeMaxNALocals[i] = (header - 209) / 7;
697                codeHandlerCount[i] = 2;
698            } else {
699                throw new IllegalStateException("Shouldn't get here either");
700            }
701        }
702        codeHandlerStartP = decodeBandInt("code_handler_start_P", in, Codec.BCI5, codeHandlerCount);
703        codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in, Codec.BRANCH5, codeHandlerCount);
704        codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in, Codec.BRANCH5, codeHandlerCount);
705        codeHandlerClassRCN = decodeBandInt("code_handler_class_RCN", in, Codec.UNSIGNED5, codeHandlerCount);
706
707        final int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader;
708
709        codeAttributes = new List[codeFlagsCount];
710        for (int i = 0; i < codeAttributes.length; i++) {
711            codeAttributes[i] = new ArrayList();
712        }
713        parseCodeAttrBands(in, codeFlagsCount);
714    }
715
716    private void parseCodeAttrBands(final InputStream in, final int codeFlagsCount)
717        throws IOException, Pack200Exception {
718        final long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5,
719            segment.getSegmentHeader().getOptions().hasCodeFlagsHi());
720        final int codeAttrCount = SegmentUtils.countBit16(codeFlags);
721        final int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount);
722        final int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts);
723        int callCount = 0;
724        for (int i = 0; i < codeAttrIndexes.length; i++) {
725            for (int j = 0; j < codeAttrIndexes[i].length; j++) {
726                final int index = codeAttrIndexes[i][j];
727                final AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE);
728                callCount += layout.numBackwardsCallables();
729            }
730        }
731        final int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount);
732
733        final AttributeLayout lineNumberTableLayout = attrMap
734            .getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE);
735        final int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, lineNumberTableLayout);
736        final int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5,
737            lineNumberTableCount);
738        final int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5,
739            lineNumberTableN);
740        final int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5,
741            lineNumberTableN);
742
743        final AttributeLayout localVariableTableLayout = attrMap
744            .getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE, AttributeLayout.CONTEXT_CODE);
745        final AttributeLayout localVariableTypeTableLayout = attrMap
746            .getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE, AttributeLayout.CONTEXT_CODE);
747
748        final int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags, localVariableTableLayout);
749        final int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N", in, Codec.UNSIGNED5,
750            lengthLocalVariableNBand);
751        final int[][] localVariableTableBciP = decodeBandInt("code_LocalVariableTable_bci_P", in, Codec.BCI5,
752            localVariableTableN);
753        final int[][] localVariableTableSpanO = decodeBandInt("code_LocalVariableTable_span_O", in, Codec.BRANCH5,
754            localVariableTableN);
755        final CPUTF8[][] localVariableTableNameRU = parseCPUTF8References("code_LocalVariableTable_name_RU", in,
756            Codec.UNSIGNED5, localVariableTableN);
757        final CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences("code_LocalVariableTable_type_RS", in,
758            Codec.UNSIGNED5, localVariableTableN);
759        final int[][] localVariableTableSlot = decodeBandInt("code_LocalVariableTable_slot", in, Codec.UNSIGNED5,
760            localVariableTableN);
761
762        final int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(codeFlags,
763            localVariableTypeTableLayout);
764        final int[] localVariableTypeTableN = decodeBandInt("code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5,
765            lengthLocalVariableTypeTableNBand);
766        final int[][] localVariableTypeTableBciP = decodeBandInt("code_LocalVariableTypeTable_bci_P", in, Codec.BCI5,
767            localVariableTypeTableN);
768        final int[][] localVariableTypeTableSpanO = decodeBandInt("code_LocalVariableTypeTable_span_O", in,
769            Codec.BRANCH5, localVariableTypeTableN);
770        final CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References("code_LocalVariableTypeTable_name_RU", in,
771            Codec.UNSIGNED5, localVariableTypeTableN);
772        final CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences(
773            "code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5, localVariableTypeTableN);
774        final int[][] localVariableTypeTableSlot = decodeBandInt("code_LocalVariableTypeTable_slot", in,
775            Codec.UNSIGNED5, localVariableTypeTableN);
776
777        // Parse non-predefined attribute bands
778        int backwardsCallIndex = 0;
779        final int limit = options.hasCodeFlagsHi() ? 62 : 31;
780        final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1];
781        final int[] counts = new int[limit + 1];
782        final List[] otherAttributes = new List[limit + 1];
783        for (int i = 0; i < limit; i++) {
784            final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CODE);
785            if (layout != null && !(layout.isDefaultLayout())) {
786                otherLayouts[i] = layout;
787                counts[i] = SegmentUtils.countMatches(codeFlags, layout);
788            }
789        }
790        for (int i = 0; i < counts.length; i++) {
791            if (counts[i] > 0) {
792                final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]);
793                otherAttributes[i] = bands.parseAttributes(in, counts[i]);
794                final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables();
795                if (numBackwardsCallables > 0) {
796                    final int[] backwardsCalls = new int[numBackwardsCallables];
797                    System.arraycopy(codeAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables);
798                    bands.setBackwardsCalls(backwardsCalls);
799                    backwardsCallIndex += numBackwardsCallables;
800                }
801            }
802        }
803
804        int lineNumberIndex = 0;
805        int lvtIndex = 0;
806        int lvttIndex = 0;
807        for (int i = 0; i < codeFlagsCount; i++) {
808            if (lineNumberTableLayout.matches(codeFlags[i])) {
809                final LineNumberTableAttribute lnta = new LineNumberTableAttribute(lineNumberTableN[lineNumberIndex],
810                    lineNumberTableBciP[lineNumberIndex], lineNumberTableLine[lineNumberIndex]);
811                lineNumberIndex++;
812                codeAttributes[i].add(lnta);
813            }
814            if (localVariableTableLayout.matches(codeFlags[i])) {
815                final LocalVariableTableAttribute lvta = new LocalVariableTableAttribute(localVariableTableN[lvtIndex],
816                    localVariableTableBciP[lvtIndex], localVariableTableSpanO[lvtIndex],
817                    localVariableTableNameRU[lvtIndex], localVariableTableTypeRS[lvtIndex],
818                    localVariableTableSlot[lvtIndex]);
819                lvtIndex++;
820                codeAttributes[i].add(lvta);
821            }
822            if (localVariableTypeTableLayout.matches(codeFlags[i])) {
823                final LocalVariableTypeTableAttribute lvtta = new LocalVariableTypeTableAttribute(
824                    localVariableTypeTableN[lvttIndex], localVariableTypeTableBciP[lvttIndex],
825                    localVariableTypeTableSpanO[lvttIndex], localVariableTypeTableNameRU[lvttIndex],
826                    localVariableTypeTableTypeRS[lvttIndex], localVariableTypeTableSlot[lvttIndex]);
827                lvttIndex++;
828                codeAttributes[i].add(lvtta);
829            }
830            // Non-predefined attributes
831            for (int j = 0; j < otherLayouts.length; j++) {
832                if (otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) {
833                    // Add the next attribute
834                    codeAttributes[i].add(otherAttributes[j].get(0));
835                    otherAttributes[j].remove(0);
836                }
837            }
838        }
839
840    }
841
842    private int parseFieldMetadataBands(final InputStream in, final int[] fieldAttrCalls)
843        throws Pack200Exception, IOException {
844        int backwardsCallsUsed = 0;
845        final String[] RxA = {"RVA", "RIA"};
846
847        final AttributeLayout rvaLayout = attrMap
848            .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
849        final AttributeLayout riaLayout = attrMap
850            .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD);
851
852        final int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout);
853        final int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout);
854        final int[] RxACount = {rvaCount, riaCount};
855        final int[] backwardsCalls = {0, 0};
856        if (rvaCount > 0) {
857            backwardsCalls[0] = fieldAttrCalls[0];
858            backwardsCallsUsed++;
859            if (riaCount > 0) {
860                backwardsCalls[1] = fieldAttrCalls[1];
861                backwardsCallsUsed++;
862            }
863        } else if (riaCount > 0) {
864            backwardsCalls[1] = fieldAttrCalls[0];
865            backwardsCallsUsed++;
866        }
867        final MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field");
868        final List rvaAttributes = mb[0].getAttributes();
869        final List riaAttributes = mb[1].getAttributes();
870        int rvaAttributesIndex = 0;
871        int riaAttributesIndex = 0;
872        for (int i = 0; i < fieldFlags.length; i++) {
873            for (int j = 0; j < fieldFlags[i].length; j++) {
874                if (rvaLayout.matches(fieldFlags[i][j])) {
875                    fieldAttributes[i][j].add(rvaAttributes.get(rvaAttributesIndex++));
876                }
877                if (riaLayout.matches(fieldFlags[i][j])) {
878                    fieldAttributes[i][j].add(riaAttributes.get(riaAttributesIndex++));
879                }
880            }
881        }
882        return backwardsCallsUsed;
883    }
884
885    private MetadataBandGroup[] parseMetadata(final InputStream in, final String[] RxA, final int[] RxACount,
886        final int[] backwardsCallCounts, final String contextName) throws IOException, Pack200Exception {
887        final MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length];
888        for (int i = 0; i < RxA.length; i++) {
889            mbg[i] = new MetadataBandGroup(RxA[i], cpBands);
890            final String rxa = RxA[i];
891            if (rxa.indexOf('P') >= 0) {
892                mbg[i].param_NB = decodeBandInt(contextName + "_" + rxa + "_param_NB", in, Codec.BYTE1, RxACount[i]);
893            }
894            int pairCount = 0;
895            if (!rxa.equals("AD")) {
896                mbg[i].anno_N = decodeBandInt(contextName + "_" + rxa + "_anno_N", in, Codec.UNSIGNED5, RxACount[i]);
897                mbg[i].type_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_type_RS", in, Codec.UNSIGNED5,
898                    mbg[i].anno_N);
899                mbg[i].pair_N = decodeBandInt(contextName + "_" + rxa + "_pair_N", in, Codec.UNSIGNED5, mbg[i].anno_N);
900                for (int j = 0; j < mbg[i].pair_N.length; j++) {
901                    for (int k = 0; k < mbg[i].pair_N[j].length; k++) {
902                        pairCount += mbg[i].pair_N[j][k];
903                    }
904                }
905
906                mbg[i].name_RU = parseCPUTF8References(contextName + "_" + rxa + "_name_RU", in, Codec.UNSIGNED5,
907                    pairCount);
908            } else {
909                pairCount = RxACount[i];
910            }
911            mbg[i].T = decodeBandInt(contextName + "_" + rxa + "_T", in, Codec.BYTE1,
912                pairCount + backwardsCallCounts[i]);
913            int ICount = 0, DCount = 0, FCount = 0, JCount = 0, cCount = 0, eCount = 0, sCount = 0, arrayCount = 0,
914                atCount = 0;
915            for (int j = 0; j < mbg[i].T.length; j++) {
916                final char c = (char) mbg[i].T[j];
917                switch (c) {
918                case 'B':
919                case 'C':
920                case 'I':
921                case 'S':
922                case 'Z':
923                    ICount++;
924                    break;
925                case 'D':
926                    DCount++;
927                    break;
928                case 'F':
929                    FCount++;
930                    break;
931                case 'J':
932                    JCount++;
933                    break;
934                case 'c':
935                    cCount++;
936                    break;
937                case 'e':
938                    eCount++;
939                    break;
940                case 's':
941                    sCount++;
942                    break;
943                case '[':
944                    arrayCount++;
945                    break;
946                case '@':
947                    atCount++;
948                    break;
949                }
950            }
951            mbg[i].caseI_KI = parseCPIntReferences(contextName + "_" + rxa + "_caseI_KI", in, Codec.UNSIGNED5, ICount);
952            mbg[i].caseD_KD = parseCPDoubleReferences(contextName + "_" + rxa + "_caseD_KD", in, Codec.UNSIGNED5,
953                DCount);
954            mbg[i].caseF_KF = parseCPFloatReferences(contextName + "_" + rxa + "_caseF_KF", in, Codec.UNSIGNED5,
955                FCount);
956            mbg[i].caseJ_KJ = parseCPLongReferences(contextName + "_" + rxa + "_caseJ_KJ", in, Codec.UNSIGNED5, JCount);
957            mbg[i].casec_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_casec_RS", in, Codec.UNSIGNED5,
958                cCount);
959            mbg[i].caseet_RS = parseReferences(contextName + "_" + rxa + "_caseet_RS", in, Codec.UNSIGNED5, eCount,
960                cpBands.getCpSignature());
961            mbg[i].caseec_RU = parseReferences(contextName + "_" + rxa + "_caseec_RU", in, Codec.UNSIGNED5, eCount,
962                cpBands.getCpUTF8());
963            mbg[i].cases_RU = parseCPUTF8References(contextName + "_" + rxa + "_cases_RU", in, Codec.UNSIGNED5, sCount);
964            mbg[i].casearray_N = decodeBandInt(contextName + "_" + rxa + "_casearray_N", in, Codec.UNSIGNED5,
965                arrayCount);
966            mbg[i].nesttype_RS = parseCPUTF8References(contextName + "_" + rxa + "_nesttype_RS", in, Codec.UNSIGNED5,
967                atCount);
968            mbg[i].nestpair_N = decodeBandInt(contextName + "_" + rxa + "_nestpair_N", in, Codec.UNSIGNED5, atCount);
969            int nestPairCount = 0;
970            for (int j = 0; j < mbg[i].nestpair_N.length; j++) {
971                nestPairCount += mbg[i].nestpair_N[j];
972            }
973            mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa + "_nestname_RU", in, Codec.UNSIGNED5,
974                nestPairCount);
975        }
976        return mbg;
977    }
978
979    private int parseMethodMetadataBands(final InputStream in, final int[] methodAttrCalls)
980        throws Pack200Exception, IOException {
981        int backwardsCallsUsed = 0;
982        final String[] RxA = {"RVA", "RIA", "RVPA", "RIPA", "AD"};
983        final int[] rxaCounts = {0, 0, 0, 0, 0};
984
985        final AttributeLayout rvaLayout = attrMap
986            .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
987        final AttributeLayout riaLayout = attrMap.getAttributeLayout(
988            AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
989        final AttributeLayout rvpaLayout = attrMap.getAttributeLayout(
990            AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
991        final AttributeLayout ripaLayout = attrMap.getAttributeLayout(
992            AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD);
993        final AttributeLayout adLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT,
994            AttributeLayout.CONTEXT_METHOD);
995        final AttributeLayout[] rxaLayouts = {rvaLayout, riaLayout, rvpaLayout, ripaLayout, adLayout};
996
997        for (int i = 0; i < rxaLayouts.length; i++) {
998            rxaCounts[i] = SegmentUtils.countMatches(methodFlags, rxaLayouts[i]);
999        }
1000        final int[] backwardsCalls = new int[5];
1001        int methodAttrIndex = 0;
1002        for (int i = 0; i < backwardsCalls.length; i++) {
1003            if (rxaCounts[i] > 0) {
1004                backwardsCallsUsed++;
1005                backwardsCalls[i] = methodAttrCalls[methodAttrIndex];
1006                methodAttrIndex++;
1007            } else {
1008                backwardsCalls[i] = 0;
1009            }
1010        }
1011        final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts, backwardsCalls, "method");
1012        final List[] attributeLists = new List[RxA.length];
1013        final int[] attributeListIndexes = new int[RxA.length];
1014        for (int i = 0; i < mbgs.length; i++) {
1015            attributeLists[i] = mbgs[i].getAttributes();
1016            attributeListIndexes[i] = 0;
1017        }
1018        for (int i = 0; i < methodFlags.length; i++) {
1019            for (int j = 0; j < methodFlags[i].length; j++) {
1020                for (int k = 0; k < rxaLayouts.length; k++) {
1021                    if (rxaLayouts[k].matches(methodFlags[i][j])) {
1022                        methodAttributes[i][j].add(attributeLists[k].get(attributeListIndexes[k]++));
1023                    }
1024                }
1025            }
1026        }
1027        return backwardsCallsUsed;
1028    }
1029
1030    /**
1031     * Parse the class metadata bands and return the number of backwards callables.
1032     *
1033     * @param in TODO
1034     * @param classAttrCalls TODO
1035     * @return the number of backwards callables.
1036     * @throws Pack200Exception TODO
1037     * @throws IOException If an I/O error occurs.
1038     */
1039    private int parseClassMetadataBands(final InputStream in, final int[] classAttrCalls)
1040        throws Pack200Exception, IOException {
1041        int numBackwardsCalls = 0;
1042        final String[] RxA = {"RVA", "RIA"};
1043
1044        final AttributeLayout rvaLayout = attrMap
1045            .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
1046        final AttributeLayout riaLayout = attrMap
1047            .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS);
1048        final int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout);
1049        final int riaCount = SegmentUtils.countMatches(classFlags, riaLayout);
1050        final int[] RxACount = {rvaCount, riaCount};
1051        final int[] backwardsCalls = {0, 0};
1052        if (rvaCount > 0) {
1053            numBackwardsCalls++;
1054            backwardsCalls[0] = classAttrCalls[0];
1055            if (riaCount > 0) {
1056                numBackwardsCalls++;
1057                backwardsCalls[1] = classAttrCalls[1];
1058            }
1059        } else if (riaCount > 0) {
1060            numBackwardsCalls++;
1061            backwardsCalls[1] = classAttrCalls[0];
1062        }
1063        final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class");
1064        final List rvaAttributes = mbgs[0].getAttributes();
1065        final List riaAttributes = mbgs[1].getAttributes();
1066        int rvaAttributesIndex = 0;
1067        int riaAttributesIndex = 0;
1068        for (int i = 0; i < classFlags.length; i++) {
1069            if (rvaLayout.matches(classFlags[i])) {
1070                classAttributes[i].add(rvaAttributes.get(rvaAttributesIndex++));
1071            }
1072            if (riaLayout.matches(classFlags[i])) {
1073                classAttributes[i].add(riaAttributes.get(riaAttributesIndex++));
1074            }
1075        }
1076        return numBackwardsCalls;
1077    }
1078
1079    public ArrayList[] getClassAttributes() {
1080        return classAttributes;
1081    }
1082
1083    public int[] getClassFieldCount() {
1084        return classFieldCount;
1085    }
1086
1087    public long[] getRawClassFlags() {
1088        return classFlags;
1089    }
1090
1091    public long[] getClassFlags() throws Pack200Exception {
1092        if (classAccessFlags == null) {
1093            long mask = 0x7FFF;
1094            for (int i = 0; i < 16; i++) {
1095                final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS);
1096                if (layout != null && !layout.isDefaultLayout()) {
1097                    mask &= ~(1 << i);
1098                }
1099            }
1100            classAccessFlags = new long[classFlags.length];
1101            for (int i = 0; i < classFlags.length; i++) {
1102                classAccessFlags[i] = classFlags[i] & mask;
1103            }
1104        }
1105        return classAccessFlags;
1106    }
1107
1108    public int[][] getClassInterfacesInts() {
1109        return classInterfacesInts;
1110    }
1111
1112    public int[] getClassMethodCount() {
1113        return classMethodCount;
1114    }
1115
1116    public int[] getClassSuperInts() {
1117        return classSuperInts;
1118    }
1119
1120    public int[] getClassThisInts() {
1121        return classThisInts;
1122    }
1123
1124    public int[] getCodeMaxNALocals() {
1125        return codeMaxNALocals;
1126    }
1127
1128    public int[] getCodeMaxStack() {
1129        return codeMaxStack;
1130    }
1131
1132    public ArrayList[][] getFieldAttributes() {
1133        return fieldAttributes;
1134    }
1135
1136    public int[][] getFieldDescrInts() {
1137        return fieldDescrInts;
1138    }
1139
1140    public int[][] getMethodDescrInts() {
1141        return methodDescrInts;
1142    }
1143
1144    public long[][] getFieldFlags() throws Pack200Exception {
1145        if (fieldAccessFlags == null) {
1146            long mask = 0x7FFF;
1147            for (int i = 0; i < 16; i++) {
1148                final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD);
1149                if (layout != null && !layout.isDefaultLayout()) {
1150                    mask &= ~(1 << i);
1151                }
1152            }
1153            fieldAccessFlags = new long[fieldFlags.length][];
1154            for (int i = 0; i < fieldFlags.length; i++) {
1155                fieldAccessFlags[i] = new long[fieldFlags[i].length];
1156                for (int j = 0; j < fieldFlags[i].length; j++) {
1157                    fieldAccessFlags[i][j] = fieldFlags[i][j] & mask;
1158                }
1159            }
1160        }
1161        return fieldAccessFlags;
1162    }
1163
1164    /**
1165     * Answer an ArrayList of ArrayLists which hold the code attributes corresponding to all classes in order.
1166     *
1167     * If a class doesn't have any attributes, the corresponding element in this list will be an empty ArrayList.
1168     *
1169     * @return ArrayList
1170     */
1171    public ArrayList getOrderedCodeAttributes() {
1172        final ArrayList orderedAttributeList = new ArrayList(codeAttributes.length);
1173        for (int classIndex = 0; classIndex < codeAttributes.length; classIndex++) {
1174            final ArrayList currentAttributes = new ArrayList(codeAttributes[classIndex].size());
1175            for (int attributeIndex = 0; attributeIndex < codeAttributes[classIndex].size(); attributeIndex++) {
1176                final Attribute attribute = (Attribute) codeAttributes[classIndex].get(attributeIndex);
1177                currentAttributes.add(attribute);
1178            }
1179            orderedAttributeList.add(currentAttributes);
1180        }
1181        return orderedAttributeList;
1182    }
1183
1184    public ArrayList[][] getMethodAttributes() {
1185        return methodAttributes;
1186    }
1187
1188    public String[][] getMethodDescr() {
1189        return methodDescr;
1190    }
1191
1192    public long[][] getMethodFlags() throws Pack200Exception {
1193        if (methodAccessFlags == null) {
1194            long mask = 0x7FFF;
1195            for (int i = 0; i < 16; i++) {
1196                final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD);
1197                if (layout != null && !layout.isDefaultLayout()) {
1198                    mask &= ~(1 << i);
1199                }
1200            }
1201            methodAccessFlags = new long[methodFlags.length][];
1202            for (int i = 0; i < methodFlags.length; i++) {
1203                methodAccessFlags[i] = new long[methodFlags[i].length];
1204                for (int j = 0; j < methodFlags[i].length; j++) {
1205                    methodAccessFlags[i][j] = methodFlags[i][j] & mask;
1206                }
1207            }
1208        }
1209        return methodAccessFlags;
1210    }
1211
1212    /**
1213     * Returns null if all classes should use the default major and minor version or an array of integers containing the
1214     * major version numberss to use for each class in the segment
1215     *
1216     * @return Class file major version numbers, or null if none specified
1217     */
1218    public int[] getClassVersionMajor() {
1219        return classVersionMajor;
1220    }
1221
1222    /**
1223     * Returns null if all classes should use the default major and minor version or an array of integers containing the
1224     * minor version numberss to use for each class in the segment
1225     *
1226     * @return Class file minor version numbers, or null if none specified
1227     */
1228    public int[] getClassVersionMinor() {
1229        return classVersionMinor;
1230    }
1231
1232    public int[] getCodeHandlerCount() {
1233        return codeHandlerCount;
1234    }
1235
1236    public int[][] getCodeHandlerCatchPO() {
1237        return codeHandlerCatchPO;
1238    }
1239
1240    public int[][] getCodeHandlerClassRCN() {
1241        return codeHandlerClassRCN;
1242    }
1243
1244    public int[][] getCodeHandlerEndPO() {
1245        return codeHandlerEndPO;
1246    }
1247
1248    public int[][] getCodeHandlerStartP() {
1249        return codeHandlerStartP;
1250    }
1251
1252    public IcTuple[][] getIcLocal() {
1253        return icLocal;
1254    }
1255
1256    public boolean[] getCodeHasAttributes() {
1257        return codeHasAttributes;
1258    }
1259
1260}