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