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}