001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with this
004 * work for additional information regarding copyright ownership. The ASF
005 * licenses this file to You under the Apache License, Version 2.0 (the
006 * "License"); you may not use this file except in compliance with the License.
007 * 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, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 * License for the specific language governing permissions and limitations under
015 * the License.
016 */
017package org.apache.commons.compress.harmony.pack200;
018
019import java.io.IOException;
020import java.io.OutputStream;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.HashMap;
024import java.util.HashSet;
025import java.util.List;
026import java.util.Map;
027import java.util.Set;
028import java.util.TreeSet;
029
030import org.objectweb.asm.Type;
031
032/**
033 * Pack200 Constant Pool Bands
034 */
035public class CpBands extends BandSet {
036
037    // Don't need to include default attribute names in the constant pool bands
038    private final Set<String> defaultAttributeNames = new HashSet<>();
039
040    private final Set<CPUTF8> cp_Utf8 = new TreeSet<>();
041    private final Set<CPInt> cp_Int = new TreeSet<>();
042    private final Set<CPFloat> cp_Float = new TreeSet<>();
043    private final Set<CPLong> cp_Long = new TreeSet<>();
044    private final Set<CPDouble> cp_Double = new TreeSet<>();
045    private final Set<CPString> cp_String = new TreeSet<>();
046    private final Set<CPClass> cp_Class = new TreeSet<>();
047    private final Set<CPSignature> cp_Signature = new TreeSet<>();
048    private final Set<CPNameAndType> cp_Descr = new TreeSet<>();
049    private final Set<CPMethodOrField> cp_Field = new TreeSet<>();
050    private final Set<CPMethodOrField> cp_Method = new TreeSet<>();
051    private final Set<CPMethodOrField> cp_Imethod = new TreeSet<>();
052
053    private final Map<String, CPUTF8> stringsToCpUtf8 = new HashMap<>();
054    private final Map<String, CPNameAndType> stringsToCpNameAndType = new HashMap<>();
055    private final Map<String, CPClass> stringsToCpClass = new HashMap<>();
056    private final Map<String, CPSignature> stringsToCpSignature = new HashMap<>();
057    private final Map<String, CPMethodOrField> stringsToCpMethod = new HashMap<>();
058    private final Map<String, CPMethodOrField> stringsToCpField = new HashMap<>();
059    private final Map<String, CPMethodOrField> stringsToCpIMethod = new HashMap<>();
060
061    private final Map<Object, CPConstant<?>> objectsToCPConstant = new HashMap<>();
062
063    private final Segment segment;
064
065    public CpBands(final Segment segment, final int effort) {
066        super(effort, segment.getSegmentHeader());
067        this.segment = segment;
068        defaultAttributeNames.add("AnnotationDefault");
069        defaultAttributeNames.add("RuntimeVisibleAnnotations");
070        defaultAttributeNames.add("RuntimeInvisibleAnnotations");
071        defaultAttributeNames.add("RuntimeVisibleParameterAnnotations");
072        defaultAttributeNames.add("RuntimeInvisibleParameterAnnotations");
073        defaultAttributeNames.add("Code");
074        defaultAttributeNames.add("LineNumberTable");
075        defaultAttributeNames.add("LocalVariableTable");
076        defaultAttributeNames.add("LocalVariableTypeTable");
077        defaultAttributeNames.add("ConstantValue");
078        defaultAttributeNames.add("Deprecated");
079        defaultAttributeNames.add("EnclosingMethod");
080        defaultAttributeNames.add("Exceptions");
081        defaultAttributeNames.add("InnerClasses");
082        defaultAttributeNames.add("Signature");
083        defaultAttributeNames.add("SourceFile");
084    }
085
086    @Override
087    public void pack(final OutputStream out) throws IOException, Pack200Exception {
088        PackingUtils.log("Writing constant pool bands...");
089        writeCpUtf8(out);
090        writeCpInt(out);
091        writeCpFloat(out);
092        writeCpLong(out);
093        writeCpDouble(out);
094        writeCpString(out);
095        writeCpClass(out);
096        writeCpSignature(out);
097        writeCpDescr(out);
098        writeCpMethodOrField(cp_Field, out, "cp_Field");
099        writeCpMethodOrField(cp_Method, out, "cp_Method");
100        writeCpMethodOrField(cp_Imethod, out, "cp_Imethod");
101    }
102
103    private void writeCpUtf8(final OutputStream out) throws IOException, Pack200Exception {
104        PackingUtils.log("Writing " + cp_Utf8.size() + " UTF8 entries...");
105        final int[] cpUtf8Prefix = new int[cp_Utf8.size() - 2];
106        final int[] cpUtf8Suffix = new int[cp_Utf8.size() - 1];
107        final List<Character> chars = new ArrayList<>();
108        final List<Integer> bigSuffix = new ArrayList<>();
109        final List<Character> bigChars = new ArrayList<>();
110        final Object[] cpUtf8Array = cp_Utf8.toArray();
111        final String first = ((CPUTF8) cpUtf8Array[1]).getUnderlyingString();
112        cpUtf8Suffix[0] = first.length();
113        addCharacters(chars, first.toCharArray());
114        for (int i = 2; i < cpUtf8Array.length; i++) {
115            final char[] previous = ((CPUTF8) cpUtf8Array[i - 1]).getUnderlyingString().toCharArray();
116            String currentStr = ((CPUTF8) cpUtf8Array[i]).getUnderlyingString();
117            final char[] current = currentStr.toCharArray();
118            int prefix = 0;
119            for (int j = 0; j < previous.length; j++) {
120                if (previous[j] != current[j]) {
121                    break;
122                }
123                prefix++;
124            }
125            cpUtf8Prefix[i - 2] = prefix;
126            currentStr = currentStr.substring(prefix);
127            final char[] suffix = currentStr.toCharArray();
128            if (suffix.length > 1000) { // big suffix (1000 is arbitrary - can we
129                // do better?)
130                cpUtf8Suffix[i - 1] = 0;
131                bigSuffix.add(Integer.valueOf(suffix.length));
132                addCharacters(bigChars, suffix);
133            } else {
134                cpUtf8Suffix[i - 1] = suffix.length;
135                addCharacters(chars, suffix);
136            }
137        }
138        final int[] cpUtf8Chars = new int[chars.size()];
139        final int[] cpUtf8BigSuffix = new int[bigSuffix.size()];
140        final int[][] cpUtf8BigChars = new int[bigSuffix.size()][];
141        Arrays.setAll(cpUtf8Chars, i -> chars.get(i).charValue());
142        for (int i = 0; i < cpUtf8BigSuffix.length; i++) {
143            final int numBigChars = bigSuffix.get(i).intValue();
144            cpUtf8BigSuffix[i] = numBigChars;
145            cpUtf8BigChars[i] = new int[numBigChars];
146            Arrays.setAll(cpUtf8BigChars[i], j -> bigChars.remove(0).charValue());
147        }
148
149        byte[] encodedBand = encodeBandInt("cpUtf8Prefix", cpUtf8Prefix, Codec.DELTA5);
150        out.write(encodedBand);
151        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8Prefix[" + cpUtf8Prefix.length + "]");
152
153        encodedBand = encodeBandInt("cpUtf8Suffix", cpUtf8Suffix, Codec.UNSIGNED5);
154        out.write(encodedBand);
155        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8Suffix[" + cpUtf8Suffix.length + "]");
156
157        encodedBand = encodeBandInt("cpUtf8Chars", cpUtf8Chars, Codec.CHAR3);
158        out.write(encodedBand);
159        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8Chars[" + cpUtf8Chars.length + "]");
160
161        encodedBand = encodeBandInt("cpUtf8BigSuffix", cpUtf8BigSuffix, Codec.DELTA5);
162        out.write(encodedBand);
163        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8BigSuffix[" + cpUtf8BigSuffix.length + "]");
164
165        for (int i = 0; i < cpUtf8BigChars.length; i++) {
166            encodedBand = encodeBandInt("cpUtf8BigChars " + i, cpUtf8BigChars[i], Codec.DELTA5);
167            out.write(encodedBand);
168            PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8BigChars" + i + "["
169                + cpUtf8BigChars[i].length + "]");
170        }
171    }
172
173    private void addCharacters(final List<Character> chars, final char[] charArray) {
174        for (char element : charArray) {
175            chars.add(Character.valueOf(element));
176        }
177    }
178
179    private void writeCpInt(final OutputStream out) throws IOException, Pack200Exception {
180        PackingUtils.log("Writing " + cp_Int.size() + " Integer entries...");
181        final int[] cpInt = new int[cp_Int.size()];
182        int i = 0;
183        for (final CPInt integer : cp_Int) {
184            cpInt[i] = integer.getInt();
185            i++;
186        }
187        final byte[] encodedBand = encodeBandInt("cp_Int", cpInt, Codec.UDELTA5);
188        out.write(encodedBand);
189        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Int[" + cpInt.length + "]");
190    }
191
192    private void writeCpFloat(final OutputStream out) throws IOException, Pack200Exception {
193        PackingUtils.log("Writing " + cp_Float.size() + " Float entries...");
194        final int[] cpFloat = new int[cp_Float.size()];
195        int i = 0;
196        for (final CPFloat fl : cp_Float) {
197            cpFloat[i] = Float.floatToIntBits(fl.getFloat());
198            i++;
199        }
200        final byte[] encodedBand = encodeBandInt("cp_Float", cpFloat, Codec.UDELTA5);
201        out.write(encodedBand);
202        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Float[" + cpFloat.length + "]");
203    }
204
205    private void writeCpLong(final OutputStream out) throws IOException, Pack200Exception {
206        PackingUtils.log("Writing " + cp_Long.size() + " Long entries...");
207        final int[] highBits = new int[cp_Long.size()];
208        final int[] loBits = new int[cp_Long.size()];
209        int i = 0;
210        for (final CPLong lng : cp_Long) {
211            final long l = lng.getLong();
212            highBits[i] = (int) (l >> 32);
213            loBits[i] = (int) l;
214            i++;
215        }
216        byte[] encodedBand = encodeBandInt("cp_Long_hi", highBits, Codec.UDELTA5);
217        out.write(encodedBand);
218        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Long_hi[" + highBits.length + "]");
219
220        encodedBand = encodeBandInt("cp_Long_lo", loBits, Codec.DELTA5);
221        out.write(encodedBand);
222        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Long_lo[" + loBits.length + "]");
223    }
224
225    private void writeCpDouble(final OutputStream out) throws IOException, Pack200Exception {
226        PackingUtils.log("Writing " + cp_Double.size() + " Double entries...");
227        final int[] highBits = new int[cp_Double.size()];
228        final int[] loBits = new int[cp_Double.size()];
229        int i = 0;
230        for (final CPDouble dbl : cp_Double) {
231            final long l = Double.doubleToLongBits(dbl.getDouble());
232            highBits[i] = (int) (l >> 32);
233            loBits[i] = (int) l;
234            i++;
235        }
236        byte[] encodedBand = encodeBandInt("cp_Double_hi", highBits, Codec.UDELTA5);
237        out.write(encodedBand);
238        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Double_hi[" + highBits.length + "]");
239
240        encodedBand = encodeBandInt("cp_Double_lo", loBits, Codec.DELTA5);
241        out.write(encodedBand);
242        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Double_lo[" + loBits.length + "]");
243    }
244
245    private void writeCpString(final OutputStream out) throws IOException, Pack200Exception {
246        PackingUtils.log("Writing " + cp_String.size() + " String entries...");
247        final int[] cpString = new int[cp_String.size()];
248        int i = 0;
249        for (final CPString cpStr : cp_String) {
250            cpString[i] = cpStr.getIndexInCpUtf8();
251            i++;
252        }
253        final byte[] encodedBand = encodeBandInt("cpString", cpString, Codec.UDELTA5);
254        out.write(encodedBand);
255        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpString[" + cpString.length + "]");
256    }
257
258    private void writeCpClass(final OutputStream out) throws IOException, Pack200Exception {
259        PackingUtils.log("Writing " + cp_Class.size() + " Class entries...");
260        final int[] cpClass = new int[cp_Class.size()];
261        int i = 0;
262        for (final CPClass cpCl : cp_Class) {
263            cpClass[i] = cpCl.getIndexInCpUtf8();
264            i++;
265        }
266        final byte[] encodedBand = encodeBandInt("cpClass", cpClass, Codec.UDELTA5);
267        out.write(encodedBand);
268        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpClass[" + cpClass.length + "]");
269    }
270
271    private void writeCpSignature(final OutputStream out) throws IOException, Pack200Exception {
272        PackingUtils.log("Writing " + cp_Signature.size() + " Signature entries...");
273        final int[] cpSignatureForm = new int[cp_Signature.size()];
274        final List<CPClass> classes = new ArrayList<>();
275        int i = 0;
276        for (final CPSignature cpS : cp_Signature) {
277            classes.addAll(cpS.getClasses());
278            cpSignatureForm[i] = cpS.getIndexInCpUtf8();
279            i++;
280        }
281        final int[] cpSignatureClasses = new int[classes.size()];
282        Arrays.setAll(cpSignatureClasses, j -> classes.get(j).getIndex());
283
284        byte[] encodedBand = encodeBandInt("cpSignatureForm", cpSignatureForm, Codec.DELTA5);
285        out.write(encodedBand);
286        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpSignatureForm[" + cpSignatureForm.length + "]");
287
288        encodedBand = encodeBandInt("cpSignatureClasses", cpSignatureClasses, Codec.UDELTA5);
289        out.write(encodedBand);
290        PackingUtils
291            .log("Wrote " + encodedBand.length + " bytes from cpSignatureClasses[" + cpSignatureClasses.length + "]");
292    }
293
294    private void writeCpDescr(final OutputStream out) throws IOException, Pack200Exception {
295        PackingUtils.log("Writing " + cp_Descr.size() + " Descriptor entries...");
296        final int[] cpDescrName = new int[cp_Descr.size()];
297        final int[] cpDescrType = new int[cp_Descr.size()];
298        int i = 0;
299        for (final CPNameAndType nameAndType : cp_Descr) {
300            cpDescrName[i] = nameAndType.getNameIndex();
301            cpDescrType[i] = nameAndType.getTypeIndex();
302            i++;
303        }
304
305        byte[] encodedBand = encodeBandInt("cp_Descr_Name", cpDescrName, Codec.DELTA5);
306        out.write(encodedBand);
307        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Descr_Name[" + cpDescrName.length + "]");
308
309        encodedBand = encodeBandInt("cp_Descr_Type", cpDescrType, Codec.UDELTA5);
310        out.write(encodedBand);
311        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Descr_Type[" + cpDescrType.length + "]");
312    }
313
314    private void writeCpMethodOrField(final Set<CPMethodOrField> cp, final OutputStream out, final String name)
315        throws IOException, Pack200Exception {
316        PackingUtils.log("Writing " + cp.size() + " Method and Field entries...");
317        final int[] cp_methodOrField_class = new int[cp.size()];
318        final int[] cp_methodOrField_desc = new int[cp.size()];
319        int i = 0;
320        for (final CPMethodOrField mOrF : cp) {
321            cp_methodOrField_class[i] = mOrF.getClassIndex();
322            cp_methodOrField_desc[i] = mOrF.getDescIndex();
323            i++;
324        }
325        byte[] encodedBand = encodeBandInt(name + "_class", cp_methodOrField_class, Codec.DELTA5);
326        out.write(encodedBand);
327        PackingUtils.log(
328            "Wrote " + encodedBand.length + " bytes from " + name + "_class[" + cp_methodOrField_class.length + "]");
329
330        encodedBand = encodeBandInt(name + "_desc", cp_methodOrField_desc, Codec.UDELTA5);
331        out.write(encodedBand);
332        PackingUtils
333            .log("Wrote " + encodedBand.length + " bytes from " + name + "_desc[" + cp_methodOrField_desc.length + "]");
334    }
335
336    /**
337     * All input classes for the segment have now been read in, so this method is called so that this class can
338     * calculate/complete anything it could not do while classes were being read.
339     */
340    public void finaliseBands() {
341        addCPUtf8("");
342        removeSignaturesFromCpUTF8();
343        addIndices();
344        segmentHeader.setCp_Utf8_count(cp_Utf8.size());
345        segmentHeader.setCp_Int_count(cp_Int.size());
346        segmentHeader.setCp_Float_count(cp_Float.size());
347        segmentHeader.setCp_Long_count(cp_Long.size());
348        segmentHeader.setCp_Double_count(cp_Double.size());
349        segmentHeader.setCp_String_count(cp_String.size());
350        segmentHeader.setCp_Class_count(cp_Class.size());
351        segmentHeader.setCp_Signature_count(cp_Signature.size());
352        segmentHeader.setCp_Descr_count(cp_Descr.size());
353        segmentHeader.setCp_Field_count(cp_Field.size());
354        segmentHeader.setCp_Method_count(cp_Method.size());
355        segmentHeader.setCp_Imethod_count(cp_Imethod.size());
356    }
357
358    private void removeSignaturesFromCpUTF8() {
359        cp_Signature.forEach(signature -> {
360            final String sigStr = signature.getUnderlyingString();
361            final CPUTF8 utf8 = signature.getSignatureForm();
362            final String form = utf8.getUnderlyingString();
363            if (!sigStr.equals(form)) {
364                removeCpUtf8(sigStr);
365            }
366        });
367    }
368
369        private void addIndices() {
370                for (Set<? extends ConstantPoolEntry> set : Arrays.asList(cp_Utf8, cp_Int, cp_Float, cp_Long, cp_Double,
371                                cp_String, cp_Class, cp_Signature, cp_Descr, cp_Field, cp_Method, cp_Imethod)) {
372                        int j = 0;
373                        for (final ConstantPoolEntry entry : set) {
374                                entry.setIndex(j);
375                                j++;
376                        }
377                }
378                final Map<CPClass, Integer> classNameToIndex = new HashMap<>();
379                cp_Field.forEach(mOrF -> {
380                        final CPClass cpClassName = mOrF.getClassName();
381                        final Integer index = classNameToIndex.get(cpClassName);
382                        if (index == null) {
383                                classNameToIndex.put(cpClassName, Integer.valueOf(1));
384                                mOrF.setIndexInClass(0);
385                        } else {
386                                final int theIndex = index.intValue();
387                                mOrF.setIndexInClass(theIndex);
388                                classNameToIndex.put(cpClassName, Integer.valueOf(theIndex + 1));
389                        }
390                });
391                classNameToIndex.clear();
392                final Map<CPClass, Integer> classNameToConstructorIndex = new HashMap<>();
393                cp_Method.forEach(mOrF -> {
394                        final CPClass cpClassName = mOrF.getClassName();
395                        final Integer index = classNameToIndex.get(cpClassName);
396                        if (index == null) {
397                                classNameToIndex.put(cpClassName, Integer.valueOf(1));
398                                mOrF.setIndexInClass(0);
399                        } else {
400                                final int theIndex = index.intValue();
401                                mOrF.setIndexInClass(theIndex);
402                                classNameToIndex.put(cpClassName, Integer.valueOf(theIndex + 1));
403                        }
404                        if (mOrF.getDesc().getName().equals("<init>")) {
405                                final Integer constructorIndex = classNameToConstructorIndex.get(cpClassName);
406                                if (constructorIndex == null) {
407                                        classNameToConstructorIndex.put(cpClassName, Integer.valueOf(1));
408                                        mOrF.setIndexInClassForConstructor(0);
409                                } else {
410                                        final int theIndex = constructorIndex.intValue();
411                                        mOrF.setIndexInClassForConstructor(theIndex);
412                                        classNameToConstructorIndex.put(cpClassName, Integer.valueOf(theIndex + 1));
413                                }
414                        }
415                });
416        }
417
418    private void removeCpUtf8(final String string) {
419        final CPUTF8 utf8 = stringsToCpUtf8.get(string);
420        if ((utf8 != null) && (stringsToCpClass.get(string) == null)) { // don't remove if strings are also in cpclass
421            stringsToCpUtf8.remove(string);
422            cp_Utf8.remove(utf8);
423        }
424    }
425
426    void addCPUtf8(final String utf8) {
427        getCPUtf8(utf8);
428    }
429
430    public CPUTF8 getCPUtf8(final String utf8) {
431        if (utf8 == null) {
432            return null;
433        }
434        CPUTF8 cpUtf8 = stringsToCpUtf8.get(utf8);
435        if (cpUtf8 == null) {
436            cpUtf8 = new CPUTF8(utf8);
437            cp_Utf8.add(cpUtf8);
438            stringsToCpUtf8.put(utf8, cpUtf8);
439        }
440        return cpUtf8;
441    }
442
443    public CPSignature getCPSignature(final String signature) {
444        if (signature == null) {
445            return null;
446        }
447        CPSignature cpS = stringsToCpSignature.get(signature);
448        if (cpS == null) {
449            final List<CPClass> cpClasses = new ArrayList<>();
450            CPUTF8 signatureUTF8;
451            if (signature.length() > 1 && signature.indexOf('L') != -1) {
452                final List<String> classes = new ArrayList<>();
453                final char[] chars = signature.toCharArray();
454                final StringBuilder signatureString = new StringBuilder();
455                for (int i = 0; i < chars.length; i++) {
456                    signatureString.append(chars[i]);
457                    if (chars[i] == 'L') {
458                        final StringBuilder className = new StringBuilder();
459                        for (int j = i + 1; j < chars.length; j++) {
460                            final char c = chars[j];
461                            if (!Character.isLetter(c) && !Character.isDigit(c) && (c != '/') && (c != '$')
462                                && (c != '_')) {
463                                classes.add(className.toString());
464                                i = j - 1;
465                                break;
466                            }
467                            className.append(c);
468                        }
469                    }
470                }
471                removeCpUtf8(signature);
472                for (String className : classes) {
473                    CPClass cpClass = null;
474                    if (className != null) {
475                        className = className.replace('.', '/');
476                        cpClass = stringsToCpClass.get(className);
477                        if (cpClass == null) {
478                            final CPUTF8 cpUtf8 = getCPUtf8(className);
479                            cpClass = new CPClass(cpUtf8);
480                            cp_Class.add(cpClass);
481                            stringsToCpClass.put(className, cpClass);
482                        }
483                    }
484                    cpClasses.add(cpClass);
485                }
486
487                signatureUTF8 = getCPUtf8(signatureString.toString());
488            } else {
489                signatureUTF8 = getCPUtf8(signature);
490            }
491            cpS = new CPSignature(signature, signatureUTF8, cpClasses);
492            cp_Signature.add(cpS);
493            stringsToCpSignature.put(signature, cpS);
494        }
495        return cpS;
496    }
497
498    public CPClass getCPClass(String className) {
499        if (className == null) {
500            return null;
501        }
502        className = className.replace('.', '/');
503        CPClass cpClass = stringsToCpClass.get(className);
504        if (cpClass == null) {
505            final CPUTF8 cpUtf8 = getCPUtf8(className);
506            cpClass = new CPClass(cpUtf8);
507            cp_Class.add(cpClass);
508            stringsToCpClass.put(className, cpClass);
509        }
510        if (cpClass.isInnerClass()) {
511            segment.getClassBands().currentClassReferencesInnerClass(cpClass);
512        }
513        return cpClass;
514    }
515
516    public void addCPClass(final String className) {
517        getCPClass(className);
518    }
519
520    public CPNameAndType getCPNameAndType(final String name, final String signature) {
521        final String descr = name + ":" + signature;
522        CPNameAndType nameAndType = stringsToCpNameAndType.get(descr);
523        if (nameAndType == null) {
524            nameAndType = new CPNameAndType(getCPUtf8(name), getCPSignature(signature));
525            stringsToCpNameAndType.put(descr, nameAndType);
526            cp_Descr.add(nameAndType);
527        }
528        return nameAndType;
529    }
530
531    public CPMethodOrField getCPField(final CPClass cpClass, final String name, final String desc) {
532        final String key = cpClass.toString() + ":" + name + ":" + desc;
533        CPMethodOrField cpF = stringsToCpField.get(key);
534        if (cpF == null) {
535            final CPNameAndType nAndT = getCPNameAndType(name, desc);
536            cpF = new CPMethodOrField(cpClass, nAndT);
537            cp_Field.add(cpF);
538            stringsToCpField.put(key, cpF);
539        }
540        return cpF;
541    }
542
543    public CPConstant<?> getConstant(final Object value) {
544        CPConstant<?> constant = objectsToCPConstant.get(value);
545        if (constant == null) {
546            if (value instanceof Integer) {
547                constant = new CPInt(((Integer) value).intValue());
548                cp_Int.add((CPInt) constant);
549            } else if (value instanceof Long) {
550                constant = new CPLong(((Long) value).longValue());
551                cp_Long.add((CPLong) constant);
552            } else if (value instanceof Float) {
553                constant = new CPFloat(((Float) value).floatValue());
554                cp_Float.add((CPFloat) constant);
555            } else if (value instanceof Double) {
556                constant = new CPDouble(((Double) value).doubleValue());
557                cp_Double.add((CPDouble) constant);
558            } else if (value instanceof String) {
559                constant = new CPString(getCPUtf8((String) value));
560                cp_String.add((CPString) constant);
561            } else if (value instanceof Type) {
562                String className = ((Type) value).getClassName();
563                if (className.endsWith("[]")) {
564                    className = "[L" + className.substring(0, className.length() - 2);
565                    while (className.endsWith("[]")) {
566                        className = "[" + className.substring(0, className.length() - 2);
567                    }
568                    className += ";";
569                }
570                constant = getCPClass(className);
571            }
572            objectsToCPConstant.put(value, constant);
573        }
574        return constant;
575    }
576
577    public CPMethodOrField getCPMethod(final CPClass cpClass, final String name, final String desc) {
578        final String key = cpClass.toString() + ":" + name + ":" + desc;
579        CPMethodOrField cpM = stringsToCpMethod.get(key);
580        if (cpM == null) {
581            final CPNameAndType nAndT = getCPNameAndType(name, desc);
582            cpM = new CPMethodOrField(cpClass, nAndT);
583            cp_Method.add(cpM);
584            stringsToCpMethod.put(key, cpM);
585        }
586        return cpM;
587    }
588
589    public CPMethodOrField getCPIMethod(final CPClass cpClass, final String name, final String desc) {
590        final String key = cpClass.toString() + ":" + name + ":" + desc;
591        CPMethodOrField cpIM = stringsToCpIMethod.get(key);
592        if (cpIM == null) {
593            final CPNameAndType nAndT = getCPNameAndType(name, desc);
594            cpIM = new CPMethodOrField(cpClass, nAndT);
595            cp_Imethod.add(cpIM);
596            stringsToCpIMethod.put(key, cpIM);
597        }
598        return cpIM;
599    }
600
601    public CPMethodOrField getCPField(final String owner, final String name, final String desc) {
602        return getCPField(getCPClass(owner), name, desc);
603    }
604
605    public CPMethodOrField getCPMethod(final String owner, final String name, final String desc) {
606        return getCPMethod(getCPClass(owner), name, desc);
607    }
608
609    public CPMethodOrField getCPIMethod(final String owner, final String name, final String desc) {
610        return getCPIMethod(getCPClass(owner), name, desc);
611    }
612
613    public boolean existsCpClass(final String className) {
614        final CPClass cpClass = stringsToCpClass.get(className);
615        return cpClass != null;
616    }
617
618}