    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.HashMap;
    023import java.util.Map;
    024
    025import org.apache.commons.compress.harmony.pack200.Codec;
    026import org.apache.commons.compress.harmony.pack200.Pack200Exception;
    027import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
    028import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
    029import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
    030import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
    031import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
    032import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
    033import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
    034import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
    035import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
    036import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
    037import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
    038
    039/**
    040 * Constant Pool bands
    041 */
    042public class CpBands extends BandSet {
    043
    044    public SegmentConstantPool getConstantPool() {
    045        return pool;
    046    }
    047
    048    private final SegmentConstantPool pool = new SegmentConstantPool(this);
    049
    050    private String[] cpClass;
    051    private int[] cpClassInts;
    052    private int[] cpDescriptorNameInts;
    053    private int[] cpDescriptorTypeInts;
    054    private String[] cpDescriptor;
    055    private double[] cpDouble;
    056    private String[] cpFieldClass;
    057    private String[] cpFieldDescriptor;
    058    private int[] cpFieldClassInts;
    059    private int[] cpFieldDescriptorInts;
    060    private float[] cpFloat;
    061    private String[] cpIMethodClass;
    062    private String[] cpIMethodDescriptor;
    063    private int[] cpIMethodClassInts;
    064    private int[] cpIMethodDescriptorInts;
    065    private int[] cpInt;
    066    private long[] cpLong;
    067    private String[] cpMethodClass;
    068    private String[] cpMethodDescriptor;
    069    private int[] cpMethodClassInts;
    070    private int[] cpMethodDescriptorInts;
    071    private String[] cpSignature;
    072    private int[] cpSignatureInts;
    073    private String[] cpString;
    074    private int[] cpStringInts;
    075    private String[] cpUTF8;
    076
    077    private final Map stringsToCPUTF8 = new HashMap();
    078    private final Map stringsToCPStrings = new HashMap();
    079    private final Map longsToCPLongs = new HashMap();
    080    private final Map integersToCPIntegers = new HashMap();
    081    private final Map floatsToCPFloats = new HashMap();
    082    private final Map stringsToCPClass = new HashMap();
    083    private final Map doublesToCPDoubles = new HashMap();
    084    private final Map descriptorsToCPNameAndTypes = new HashMap();
    085
    086    private Map mapClass;
    087    private Map mapDescriptor;
    088    private Map mapUTF8;
    089
    090// TODO: Not used
    091    private Map mapSignature;
    092
    093    private int intOffset;
    094    private int floatOffset;
    095    private int longOffset;
    096    private int doubleOffset;
    097    private int stringOffset;
    098    private int classOffset;
    099    private int signatureOffset;
    100    private int descrOffset;
    101    private int fieldOffset;
    102    private int methodOffset;
    103    private int imethodOffset;
    104
    105    public CpBands(final Segment segment) {
    106        super(segment);
    107    }
    108
    109    @Override
    110    public void read(final InputStream in) throws IOException, Pack200Exception {
    111        parseCpUtf8(in);
    112        parseCpInt(in);
    113        parseCpFloat(in);
    114        parseCpLong(in);
    115        parseCpDouble(in);
    116        parseCpString(in);
    117        parseCpClass(in);
    118        parseCpSignature(in);
    119        parseCpDescriptor(in);
    120        parseCpField(in);
    121        parseCpMethod(in);
    122        parseCpIMethod(in);
    123
    124        intOffset = cpUTF8.length;
    125        floatOffset = intOffset + cpInt.length;
    126        longOffset = floatOffset + cpFloat.length;
    127        doubleOffset = longOffset + cpLong.length;
    128        stringOffset = doubleOffset + cpDouble.length;
    129        classOffset = stringOffset + cpString.length;
    130        signatureOffset = classOffset + cpClass.length;
    131        descrOffset = signatureOffset + cpSignature.length;
    132        fieldOffset = descrOffset + cpDescriptor.length;
    133        methodOffset = fieldOffset + cpFieldClass.length;
    134        imethodOffset = methodOffset + cpMethodClass.length;
    135    }
    136
    137    @Override
    138    public void unpack() {
    139
    140    }
    141
    142    /**
    143     * Parses the constant pool class names, using {@link #cpClassCount} to populate {@link #cpClass} from
    144     * {@link #cpUTF8}.
    145     *
    146     * @param in the input stream to read from
    147     * @throws IOException if a problem occurs during reading from the underlying stream
    148     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    149     */
    150    private void parseCpClass(final InputStream in) throws IOException, Pack200Exception {
    151        final int cpClassCount = header.getCpClassCount();
    152        cpClassInts = decodeBandInt("cp_Class", in, Codec.UDELTA5, cpClassCount);
    153        cpClass = new String[cpClassCount];
    154        mapClass = new HashMap(cpClassCount);
    155        for (int i = 0; i < cpClassCount; i++) {
    156            cpClass[i] = cpUTF8[cpClassInts[i]];
    157            mapClass.put(cpClass[i], Integer.valueOf(i));
    158        }
    159    }
    160
    161    /**
    162     * Parses the constant pool descriptor definitions, using {@link #cpDescriptorCount} to populate
    163     * {@link #cpDescriptor}. For ease of use, the cpDescriptor is stored as a string of the form <i>name:type</i>,
    164     * largely to make it easier for representing field and method descriptors (e.g.
    165     * <code>out:java.lang.PrintStream</code>) in a way that is compatible with passing String arrays.
    166     *
    167     * @param in the input stream to read from
    168     * @throws IOException if a problem occurs during reading from the underlying stream
    169     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    170     */
    171    private void parseCpDescriptor(final InputStream in) throws IOException, Pack200Exception {
    172        final int cpDescriptorCount = header.getCpDescriptorCount();
    173        cpDescriptorNameInts = decodeBandInt("cp_Descr_name", in, Codec.DELTA5, cpDescriptorCount);
    174        cpDescriptorTypeInts = decodeBandInt("cp_Descr_type", in, Codec.UDELTA5, cpDescriptorCount);
    175        final String[] cpDescriptorNames = getReferences(cpDescriptorNameInts, cpUTF8);
    176        final String[] cpDescriptorTypes = getReferences(cpDescriptorTypeInts, cpSignature);
    177        cpDescriptor = new String[cpDescriptorCount];
    178        mapDescriptor = new HashMap(cpDescriptorCount);
    179        for (int i = 0; i < cpDescriptorCount; i++) {
    180            cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i]; //$NON-NLS-1$
    181            mapDescriptor.put(cpDescriptor[i], Integer.valueOf(i));
    182        }
    183    }
    184
    185    private void parseCpDouble(final InputStream in) throws IOException, Pack200Exception {
    186        final int cpDoubleCount = header.getCpDoubleCount();
    187        final long[] band = parseFlags("cp_Double", in, cpDoubleCount, Codec.UDELTA5, Codec.DELTA5);
    188        cpDouble = new double[band.length];
    189        for (int i = 0; i < band.length; i++) {
    190            cpDouble[i] = Double.longBitsToDouble(band[i]);
    191        }
    192    }
    193
    194    /**
    195     * Parses the constant pool field definitions, using {@link #cpFieldCount} to populate {@link #cpFieldClass} and
    196     * {@link #cpFieldDescriptor}.
    197     *
    198     * @param in the input stream to read from
    199     * @throws IOException if a problem occurs during reading from the underlying stream
    200     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    201     */
    202    private void parseCpField(final InputStream in) throws IOException, Pack200Exception {
    203        final int cpFieldCount = header.getCpFieldCount();
    204        cpFieldClassInts = decodeBandInt("cp_Field_class", in, Codec.DELTA5, cpFieldCount);
    205        cpFieldDescriptorInts = decodeBandInt("cp_Field_desc", in, Codec.UDELTA5, cpFieldCount);
    206        cpFieldClass = new String[cpFieldCount];
    207        cpFieldDescriptor = new String[cpFieldCount];
    208        for (int i = 0; i < cpFieldCount; i++) {
    209            cpFieldClass[i] = cpClass[cpFieldClassInts[i]];
    210            cpFieldDescriptor[i] = cpDescriptor[cpFieldDescriptorInts[i]];
    211        }
    212    }
    213
    214    private void parseCpFloat(final InputStream in) throws IOException, Pack200Exception {
    215        final int cpFloatCount = header.getCpFloatCount();
    216        cpFloat = new float[cpFloatCount];
    217        final int floatBits[] = decodeBandInt("cp_Float", in, Codec.UDELTA5, cpFloatCount);
    218        for (int i = 0; i < cpFloatCount; i++) {
    219            cpFloat[i] = Float.intBitsToFloat(floatBits[i]);
    220        }
    221    }
    222
    223    /**
    224     * Parses the constant pool interface method definitions, using {@link #cpIMethodCount} to populate
    225     * {@link #cpIMethodClass} and {@link #cpIMethodDescriptor}.
    226     *
    227     * @param in the input stream to read from
    228     * @throws IOException if a problem occurs during reading from the underlying stream
    229     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    230     */
    231    private void parseCpIMethod(final InputStream in) throws IOException, Pack200Exception {
    232        final int cpIMethodCount = header.getCpIMethodCount();
    233        cpIMethodClassInts = decodeBandInt("cp_Imethod_class", in, Codec.DELTA5, cpIMethodCount);
    234        cpIMethodDescriptorInts = decodeBandInt("cp_Imethod_desc", in, Codec.UDELTA5, cpIMethodCount);
    235        cpIMethodClass = new String[cpIMethodCount];
    236        cpIMethodDescriptor = new String[cpIMethodCount];
    237        for (int i = 0; i < cpIMethodCount; i++) {
    238            cpIMethodClass[i] = cpClass[cpIMethodClassInts[i]];
    239            cpIMethodDescriptor[i] = cpDescriptor[cpIMethodDescriptorInts[i]];
    240        }
    241    }
    242
    243    private void parseCpInt(final InputStream in) throws IOException, Pack200Exception {
    244        final int cpIntCount = header.getCpIntCount();
    245        cpInt = decodeBandInt("cpInt", in, Codec.UDELTA5, cpIntCount);
    246    }
    247
    248    private void parseCpLong(final InputStream in) throws IOException, Pack200Exception {
    249        final int cpLongCount = header.getCpLongCount();
    250        cpLong = parseFlags("cp_Long", in, cpLongCount, Codec.UDELTA5, Codec.DELTA5);
    251    }
    252
    253    /**
    254     * Parses the constant pool method definitions, using {@link #cpMethodCount} to populate {@link #cpMethodClass} and
    255     * {@link #cpMethodDescriptor}.
    256     *
    257     * @param in the input stream to read from
    258     * @throws IOException if a problem occurs during reading from the underlying stream
    259     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    260     */
    261    private void parseCpMethod(final InputStream in) throws IOException, Pack200Exception {
    262        final int cpMethodCount = header.getCpMethodCount();
    263        cpMethodClassInts = decodeBandInt("cp_Method_class", in, Codec.DELTA5, cpMethodCount);
    264        cpMethodDescriptorInts = decodeBandInt("cp_Method_desc", in, Codec.UDELTA5, cpMethodCount);
    265        cpMethodClass = new String[cpMethodCount];
    266        cpMethodDescriptor = new String[cpMethodCount];
    267        for (int i = 0; i < cpMethodCount; i++) {
    268            cpMethodClass[i] = cpClass[cpMethodClassInts[i]];
    269            cpMethodDescriptor[i] = cpDescriptor[cpMethodDescriptorInts[i]];
    270        }
    271    }
    272
    273    /**
    274     * Parses the constant pool signature classes, using {@link #cpSignatureCount} to populate {@link #cpSignature}. A
    275     * signature form is akin to the bytecode representation of a class; Z for boolean, I for int, [ for array etc.
    276     * However, although classes are started with L, the classname does not follow the form; instead, there is a
    277     * separate array of classes. So an array corresponding to <code>public static void main(String args[])</code> has a
    278     * form of <code>[L(V)</code> and a classes array of <code>[java.lang.String]</code>. The {@link #cpSignature} is a
    279     * string representation identical to the bytecode equivalent <code>[Ljava/lang/String;(V)</code> TODO Check that
    280     * the form is as above and update other types e.g. J
    281     *
    282     * @param in the input stream to read from
    283     * @throws IOException if a problem occurs during reading from the underlying stream
    284     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    285     */
    286    private void parseCpSignature(final InputStream in) throws IOException, Pack200Exception {
    287        final int cpSignatureCount = header.getCpSignatureCount();
    288        cpSignatureInts = decodeBandInt("cp_Signature_form", in, Codec.DELTA5, cpSignatureCount);
    289        final String[] cpSignatureForm = getReferences(cpSignatureInts, cpUTF8);
    290        cpSignature = new String[cpSignatureCount];
    291        mapSignature = new HashMap();
    292        int lCount = 0;
    293        for (int i = 0; i < cpSignatureCount; i++) {
    294            final String form = cpSignatureForm[i];
    295            final char[] chars = form.toCharArray();
    296            for (int j = 0; j < chars.length; j++) {
    297                if (chars[j] == 'L') {
    298                    cpSignatureInts[i] = -1;
    299                    lCount++;
    300                }
    301            }
    302        }
    303        final String[] cpSignatureClasses = parseReferences("cp_Signature_classes", in, Codec.UDELTA5, lCount, cpClass);
    304        int index = 0;
    305        for (int i = 0; i < cpSignatureCount; i++) {
    306            final String form = cpSignatureForm[i];
    307            final int len = form.length();
    308            final StringBuffer signature = new StringBuffer(64);
    309            final ArrayList list = new ArrayList();
    310            for (int j = 0; j < len; j++) {
    311                final char c = form.charAt(j);
    312                signature.append(c);
    313                if (c == 'L') {
    314                    final String className = cpSignatureClasses[index];
    315                    list.add(className);
    316                    signature.append(className);
    317                    index++;
    318                }
    319            }
    320            cpSignature[i] = signature.toString();
    321            mapSignature.put(signature.toString(), Integer.valueOf(i));
    322        }
    323//        for (int i = 0; i < cpSignatureInts.length; i++) {
    324//            if(cpSignatureInts[i] == -1) {
    325//                cpSignatureInts[i] = search(cpUTF8, cpSignature[i]);
    326//            }
    327//        }
    328    }
    329
    330    /**
    331     * Parses the constant pool strings, using {@link #cpStringCount} to populate {@link #cpString} from indexes into
    332     * {@link #cpUTF8}.
    333     *
    334     * @param in the input stream to read from
    335     * @throws IOException if a problem occurs during reading from the underlying stream
    336     * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec
    337     */
    338    private void parseCpString(final InputStream in) throws IOException, Pack200Exception {
    339        final int cpStringCount = header.getCpStringCount();
    340        cpStringInts = decodeBandInt("cp_String", in, Codec.UDELTA5, cpStringCount);
    341        cpString = new String[cpStringCount];
    342        for (int i = 0; i < cpStringCount; i++) {
    343            cpString[i] = cpUTF8[cpStringInts[i]];
    344        }
    345    }
    346
    347    private void parseCpUtf8(final InputStream in) throws IOException, Pack200Exception {
    348        final int cpUTF8Count = header.getCpUTF8Count();
    349        cpUTF8 = new String[cpUTF8Count];
    350        mapUTF8 = new HashMap(cpUTF8Count + 1);
    351        cpUTF8[0] = ""; //$NON-NLS-1$
    352        mapUTF8.put("", Integer.valueOf(0));
    353        final int[] prefix = decodeBandInt("cpUTF8Prefix", in, Codec.DELTA5, cpUTF8Count - 2);
    354        int charCount = 0;
    355        int bigSuffixCount = 0;
    356        final int[] suffix = decodeBandInt("cpUTF8Suffix", in, Codec.UNSIGNED5, cpUTF8Count - 1);
    357
    358        for (int i = 0; i < suffix.length; i++) {
    359            if (suffix[i] == 0) {
    360                bigSuffixCount++;
    361            } else {
    362                charCount += suffix[i];
    363            }
    364        }
    365        final char[] data = new char[charCount];
    366        final int[] dataBand = decodeBandInt("cp_Utf8_chars", in, Codec.CHAR3, charCount);
    367        for (int i = 0; i < data.length; i++) {
    368            data[i] = (char) dataBand[i];
    369        }
    370
    371        // Read in the big suffix data
    372        final int[] bigSuffixCounts = decodeBandInt("cp_Utf8_big_suffix", in, Codec.DELTA5, bigSuffixCount);
    373        final int[][] bigSuffixDataBand = new int[bigSuffixCount][];
    374        for (int i = 0; i < bigSuffixDataBand.length; i++) {
    375            bigSuffixDataBand[i] = decodeBandInt("cp_Utf8_big_chars " + i, in, Codec.DELTA5, bigSuffixCounts[i]);
    376        }
    377
    378        // Convert big suffix data to characters
    379        final char bigSuffixData[][] = new char[bigSuffixCount][];
    380        for (int i = 0; i < bigSuffixDataBand.length; i++) {
    381            bigSuffixData[i] = new char[bigSuffixDataBand[i].length];
    382            for (int j = 0; j < bigSuffixDataBand[i].length; j++) {
    383                bigSuffixData[i][j] = (char) bigSuffixDataBand[i][j];
    384            }
    385        }
    386        // Go through the strings
    387        charCount = 0;
    388        bigSuffixCount = 0;
    389        for (int i = 1; i < cpUTF8Count; i++) {
    390            final String lastString = cpUTF8[i - 1];
    391            if (suffix[i - 1] == 0) {
    392                // The big suffix stuff hasn't been tested, and I'll be
    393                // surprised if it works first time w/o errors ...
    394                cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0)
    395                    + new String(bigSuffixData[bigSuffixCount++]);
    396                mapUTF8.put(cpUTF8[i], Integer.valueOf(i));
    397            } else {
    398                cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0)
    399                    + new String(data, charCount, suffix[i - 1]);
    400                charCount += suffix[i - 1];
    401                mapUTF8.put(cpUTF8[i], Integer.valueOf(i));
    402            }
    403        }
    404    }
    405
    406    public String[] getCpClass() {
    407        return cpClass;
    408    }
    409
    410    public String[] getCpDescriptor() {
    411        return cpDescriptor;
    412    }
    413
    414    public String[] getCpFieldClass() {
    415        return cpFieldClass;
    416    }
    417
    418    public String[] getCpIMethodClass() {
    419        return cpIMethodClass;
    420    }
    421
    422    public int[] getCpInt() {
    423        return cpInt;
    424    }
    425
    426    public long[] getCpLong() {
    427        return cpLong;
    428    }
    429
    430    public String[] getCpMethodClass() {
    431        return cpMethodClass;
    432    }
    433
    434    public String[] getCpMethodDescriptor() {
    435        return cpMethodDescriptor;
    436    }
    437
    438    public String[] getCpSignature() {
    439        return cpSignature;
    440    }
    441
    442    public String[] getCpUTF8() {
    443        return cpUTF8;
    444    }
    445
    446    public CPUTF8 cpUTF8Value(final int index) {
    447        final String string = cpUTF8[index];
    448        CPUTF8 cputf8 = (CPUTF8) stringsToCPUTF8.get(string);
    449        if (cputf8 == null) {
    450            cputf8 = new CPUTF8(string, index);
    451            stringsToCPUTF8.put(string, cputf8);
    452        } else if (cputf8.getGlobalIndex() > index) {
    453            cputf8.setGlobalIndex(index);
    454        }
    455        return cputf8;
    456    }
    457
    458    public CPUTF8 cpUTF8Value(final String string) {
    459        return cpUTF8Value(string, true);
    460    }
    461
    462    public CPUTF8 cpUTF8Value(final String string, final boolean searchForIndex) {
    463        CPUTF8 cputf8 = (CPUTF8) stringsToCPUTF8.get(string);
    464        if (cputf8 == null) {
    465            Integer index = null;
    466            if (searchForIndex) {
    467                index = (Integer) mapUTF8.get(string);
    468            }
    469            if (index != null) {
    470                return cpUTF8Value(index.intValue());
    471            }
    472            if (searchForIndex) {
    473                index = (Integer) mapSignature.get(string);
    474            }
    475            if (index != null) {
    476                return cpSignatureValue(index.intValue());
    477            }
    478            cputf8 = new CPUTF8(string, -1);
    479            stringsToCPUTF8.put(string, cputf8);
    480        }
    481        return cputf8;
    482    }
    483
    484    public CPString cpStringValue(final int index) {
    485        final String string = cpString[index];
    486        final int utf8Index = cpStringInts[index];
    487        final int globalIndex = stringOffset + index;
    488        CPString cpString = (CPString) stringsToCPStrings.get(string);
    489        if (cpString == null) {
    490            cpString = new CPString(cpUTF8Value(utf8Index), globalIndex);
    491            stringsToCPStrings.put(string, cpString);
    492        }
    493        return cpString;
    494    }
    495
    496    public CPLong cpLongValue(final int index) {
    497        final Long l = Long.valueOf(cpLong[index]);
    498        CPLong cpLong = (CPLong) longsToCPLongs.get(l);
    499        if (cpLong == null) {
    500            cpLong = new CPLong(l, index + longOffset);
    501            longsToCPLongs.put(l, cpLong);
    502        }
    503        return cpLong;
    504    }
    505
    506    public CPInteger cpIntegerValue(final int index) {
    507        final Integer i = Integer.valueOf(cpInt[index]);
    508        CPInteger cpInteger = (CPInteger) integersToCPIntegers.get(i);
    509        if (cpInteger == null) {
    510            cpInteger = new CPInteger(i, index + intOffset);
    511            integersToCPIntegers.put(i, cpInteger);
    512        }
    513        return cpInteger;
    514    }
    515
    516    public CPFloat cpFloatValue(final int index) {
    517        final Float f = Float.valueOf(cpFloat[index]);
    518        CPFloat cpFloat = (CPFloat) floatsToCPFloats.get(f);
    519        if (cpFloat == null) {
    520            cpFloat = new CPFloat(f, index + floatOffset);
    521            floatsToCPFloats.put(f, cpFloat);
    522        }
    523        return cpFloat;
    524    }
    525
    526    public CPClass cpClassValue(final int index) {
    527        final String string = cpClass[index];
    528        final int utf8Index = cpClassInts[index];
    529        final int globalIndex = classOffset + index;
    530        CPClass cpString = (CPClass) stringsToCPClass.get(string);
    531        if (cpString == null) {
    532            cpString = new CPClass(cpUTF8Value(utf8Index), globalIndex);
    533            stringsToCPClass.put(string, cpString);
    534        }
    535        return cpString;
    536    }
    537
    538    public CPClass cpClassValue(final String string) {
    539        CPClass cpString = (CPClass) stringsToCPClass.get(string);
    540        if (cpString == null) {
    541            final Integer index = (Integer) mapClass.get(string);
    542            if (index != null) {
    543                return cpClassValue(index.intValue());
    544            }
    545            cpString = new CPClass(cpUTF8Value(string, false), -1);
    546            stringsToCPClass.put(string, cpString);
    547        }
    548        return cpString;
    549    }
    550
    551    public CPDouble cpDoubleValue(final int index) {
    552        final Double dbl = Double.valueOf(cpDouble[index]);
    553        CPDouble cpDouble = (CPDouble) doublesToCPDoubles.get(dbl);
    554        if (cpDouble == null) {
    555            cpDouble = new CPDouble(dbl, index + doubleOffset);
    556            doublesToCPDoubles.put(dbl, cpDouble);
    557        }
    558        return cpDouble;
    559    }
    560
    561    public CPNameAndType cpNameAndTypeValue(final int index) {
    562        final String descriptor = cpDescriptor[index];
    563        CPNameAndType cpNameAndType = (CPNameAndType) descriptorsToCPNameAndTypes.get(descriptor);
    564        if (cpNameAndType == null) {
    565            final int nameIndex = cpDescriptorNameInts[index];
    566            final int descriptorIndex = cpDescriptorTypeInts[index];
    567
    568            final CPUTF8 name = cpUTF8Value(nameIndex);
    569            final CPUTF8 descriptorU = cpSignatureValue(descriptorIndex);
    570            cpNameAndType = new CPNameAndType(name, descriptorU, index + descrOffset);
    571            descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType);
    572        }
    573        return cpNameAndType;
    574    }
    575
    576    public CPInterfaceMethodRef cpIMethodValue(final int index) {
    577        return new CPInterfaceMethodRef(cpClassValue(cpIMethodClassInts[index]),
    578            cpNameAndTypeValue(cpIMethodDescriptorInts[index]), index + imethodOffset);
    579    }
    580
    581    public CPMethodRef cpMethodValue(final int index) {
    582        return new CPMethodRef(cpClassValue(cpMethodClassInts[index]),
    583            cpNameAndTypeValue(cpMethodDescriptorInts[index]), index + methodOffset);
    584    }
    585
    586    public CPFieldRef cpFieldValue(final int index) {
    587        return new CPFieldRef(cpClassValue(cpFieldClassInts[index]), cpNameAndTypeValue(cpFieldDescriptorInts[index]),
    588            index + fieldOffset);
    589    }
    590
    591    public CPUTF8 cpSignatureValue(final int index) {
    592        int globalIndex;
    593        if (cpSignatureInts[index] != -1) {
    594            globalIndex = cpSignatureInts[index];
    595        } else {
    596            globalIndex = index + signatureOffset;
    597        }
    598        final String string = cpSignature[index];
    599        CPUTF8 cpUTF8 = (CPUTF8) stringsToCPUTF8.get(string);
    600        if (cpUTF8 == null) {
    601            cpUTF8 = new CPUTF8(string, globalIndex);
    602            stringsToCPUTF8.put(string, cpUTF8);
    603        }
    604        return cpUTF8;
    605    }
    606
    607    public CPNameAndType cpNameAndTypeValue(final String descriptor) {
    608        CPNameAndType cpNameAndType = (CPNameAndType) descriptorsToCPNameAndTypes.get(descriptor);
    609        if (cpNameAndType == null) {
    610            final Integer index = (Integer) mapDescriptor.get(descriptor);
    611            if (index != null) {
    612                return cpNameAndTypeValue(index.intValue());
    613            }
    614            final int colon = descriptor.indexOf(':');
    615            final String nameString = descriptor.substring(0, colon);
    616            final String descriptorString = descriptor.substring(colon + 1);
    617
    618            final CPUTF8 name = cpUTF8Value(nameString, true);
    619            final CPUTF8 descriptorU = cpUTF8Value(descriptorString, true);
    620            cpNameAndType = new CPNameAndType(name, descriptorU, -1 + descrOffset);
    621            descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType);
    622        }
    623        return cpNameAndType;
    624    }
    625
    626    public int[] getCpDescriptorNameInts() {
    627        return cpDescriptorNameInts;
    628    }
    629
    630    public int[] getCpDescriptorTypeInts() {
    631        return cpDescriptorTypeInts;
    632    }
    633
    634}