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.HashMap;
023import java.util.HashSet;
024import java.util.Iterator;
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 defaultAttributeNames = new HashSet();
039
040    private final Set cp_Utf8 = new TreeSet();
041    private final Set cp_Int = new TreeSet();
042    private final Set cp_Float = new TreeSet();
043    private final Set cp_Long = new TreeSet();
044    private final Set cp_Double = new TreeSet();
045    private final Set cp_String = new TreeSet();
046    private final Set cp_Class = new TreeSet();
047    private final Set cp_Signature = new TreeSet();
048    private final Set cp_Descr = new TreeSet();
049    private final Set cp_Field = new TreeSet();
050    private final Set cp_Method = new TreeSet();
051    private final Set cp_Imethod = new TreeSet();
052
053    private final Map stringsToCpUtf8 = new HashMap();
054    private final Map stringsToCpNameAndType = new HashMap();
055    private final Map stringsToCpClass = new HashMap();
056    private final Map stringsToCpSignature = new HashMap();
057    private final Map stringsToCpMethod = new HashMap();
058    private final Map stringsToCpField = new HashMap();
059    private final Map stringsToCpIMethod = new HashMap();
060
061    private final Map 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 chars = new ArrayList();
108        final List bigSuffix = new ArrayList();
109        final List 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        for (int i = 0; i < cpUtf8Chars.length; i++) {
142            cpUtf8Chars[i] = ((Character) chars.get(i)).charValue();
143        }
144        for (int i = 0; i < cpUtf8BigSuffix.length; i++) {
145            final int numBigChars = ((Integer) bigSuffix.get(i)).intValue();
146            cpUtf8BigSuffix[i] = numBigChars;
147            cpUtf8BigChars[i] = new int[numBigChars];
148            for (int j = 0; j < numBigChars; j++) {
149                cpUtf8BigChars[i][j] = ((Character) bigChars.remove(0)).charValue();
150            }
151        }
152
153        byte[] encodedBand = encodeBandInt("cpUtf8Prefix", cpUtf8Prefix, Codec.DELTA5);
154        out.write(encodedBand);
155        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8Prefix[" + cpUtf8Prefix.length + "]");
156
157        encodedBand = encodeBandInt("cpUtf8Suffix", cpUtf8Suffix, Codec.UNSIGNED5);
158        out.write(encodedBand);
159        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8Suffix[" + cpUtf8Suffix.length + "]");
160
161        encodedBand = encodeBandInt("cpUtf8Chars", cpUtf8Chars, Codec.CHAR3);
162        out.write(encodedBand);
163        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8Chars[" + cpUtf8Chars.length + "]");
164
165        encodedBand = encodeBandInt("cpUtf8BigSuffix", cpUtf8BigSuffix, Codec.DELTA5);
166        out.write(encodedBand);
167        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8BigSuffix[" + cpUtf8BigSuffix.length + "]");
168
169        for (int i = 0; i < cpUtf8BigChars.length; i++) {
170            encodedBand = encodeBandInt("cpUtf8BigChars " + i, cpUtf8BigChars[i], Codec.DELTA5);
171            out.write(encodedBand);
172            PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpUtf8BigChars" + i + "["
173                + cpUtf8BigChars[i].length + "]");
174        }
175    }
176
177    private void addCharacters(final List chars, final char[] charArray) {
178        for (int i = 0; i < charArray.length; i++) {
179            chars.add(Character.valueOf(charArray[i]));
180        }
181    }
182
183    private void writeCpInt(final OutputStream out) throws IOException, Pack200Exception {
184        PackingUtils.log("Writing " + cp_Int.size() + " Integer entries...");
185        final int[] cpInt = new int[cp_Int.size()];
186        int i = 0;
187        for (final Iterator iterator = cp_Int.iterator(); iterator.hasNext();) {
188            final CPInt integer = (CPInt) iterator.next();
189            cpInt[i] = integer.getInt();
190            i++;
191        }
192        final byte[] encodedBand = encodeBandInt("cp_Int", cpInt, Codec.UDELTA5);
193        out.write(encodedBand);
194        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Int[" + cpInt.length + "]");
195    }
196
197    private void writeCpFloat(final OutputStream out) throws IOException, Pack200Exception {
198        PackingUtils.log("Writing " + cp_Float.size() + " Float entries...");
199        final int[] cpFloat = new int[cp_Float.size()];
200        int i = 0;
201        for (final Iterator iterator = cp_Float.iterator(); iterator.hasNext();) {
202            final CPFloat fl = (CPFloat) iterator.next();
203            cpFloat[i] = Float.floatToIntBits(fl.getFloat());
204            i++;
205        }
206        final byte[] encodedBand = encodeBandInt("cp_Float", cpFloat, Codec.UDELTA5);
207        out.write(encodedBand);
208        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Float[" + cpFloat.length + "]");
209    }
210
211    private void writeCpLong(final OutputStream out) throws IOException, Pack200Exception {
212        PackingUtils.log("Writing " + cp_Long.size() + " Long entries...");
213        final int[] highBits = new int[cp_Long.size()];
214        final int[] loBits = new int[cp_Long.size()];
215        int i = 0;
216        for (final Iterator iterator = cp_Long.iterator(); iterator.hasNext();) {
217            final CPLong lng = (CPLong) iterator.next();
218            final long l = lng.getLong();
219            highBits[i] = (int) (l >> 32);
220            loBits[i] = (int) l;
221            i++;
222        }
223        byte[] encodedBand = encodeBandInt("cp_Long_hi", highBits, Codec.UDELTA5);
224        out.write(encodedBand);
225        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Long_hi[" + highBits.length + "]");
226
227        encodedBand = encodeBandInt("cp_Long_lo", loBits, Codec.DELTA5);
228        out.write(encodedBand);
229        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Long_lo[" + loBits.length + "]");
230    }
231
232    private void writeCpDouble(final OutputStream out) throws IOException, Pack200Exception {
233        PackingUtils.log("Writing " + cp_Double.size() + " Double entries...");
234        final int[] highBits = new int[cp_Double.size()];
235        final int[] loBits = new int[cp_Double.size()];
236        int i = 0;
237        for (final Iterator iterator = cp_Double.iterator(); iterator.hasNext();) {
238            final CPDouble dbl = (CPDouble) iterator.next();
239            final long l = Double.doubleToLongBits(dbl.getDouble());
240            highBits[i] = (int) (l >> 32);
241            loBits[i] = (int) l;
242            i++;
243        }
244        byte[] encodedBand = encodeBandInt("cp_Double_hi", highBits, Codec.UDELTA5);
245        out.write(encodedBand);
246        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Double_hi[" + highBits.length + "]");
247
248        encodedBand = encodeBandInt("cp_Double_lo", loBits, Codec.DELTA5);
249        out.write(encodedBand);
250        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Double_lo[" + loBits.length + "]");
251    }
252
253    private void writeCpString(final OutputStream out) throws IOException, Pack200Exception {
254        PackingUtils.log("Writing " + cp_String.size() + " String entries...");
255        final int[] cpString = new int[cp_String.size()];
256        int i = 0;
257        for (final Iterator iterator = cp_String.iterator(); iterator.hasNext();) {
258            final CPString cpStr = (CPString) iterator.next();
259            cpString[i] = cpStr.getIndexInCpUtf8();
260            i++;
261        }
262        final byte[] encodedBand = encodeBandInt("cpString", cpString, Codec.UDELTA5);
263        out.write(encodedBand);
264        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpString[" + cpString.length + "]");
265    }
266
267    private void writeCpClass(final OutputStream out) throws IOException, Pack200Exception {
268        PackingUtils.log("Writing " + cp_Class.size() + " Class entries...");
269        final int[] cpClass = new int[cp_Class.size()];
270        int i = 0;
271        for (final Iterator iterator = cp_Class.iterator(); iterator.hasNext();) {
272            final CPClass cpCl = (CPClass) iterator.next();
273            cpClass[i] = cpCl.getIndexInCpUtf8();
274            i++;
275        }
276        final byte[] encodedBand = encodeBandInt("cpClass", cpClass, Codec.UDELTA5);
277        out.write(encodedBand);
278        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpClass[" + cpClass.length + "]");
279    }
280
281    private void writeCpSignature(final OutputStream out) throws IOException, Pack200Exception {
282        PackingUtils.log("Writing " + cp_Signature.size() + " Signature entries...");
283        final int[] cpSignatureForm = new int[cp_Signature.size()];
284        final List classes = new ArrayList();
285        int i = 0;
286        for (final Iterator iterator = cp_Signature.iterator(); iterator.hasNext();) {
287            final CPSignature cpS = (CPSignature) iterator.next();
288            classes.addAll(cpS.getClasses());
289            cpSignatureForm[i] = cpS.getIndexInCpUtf8();
290            i++;
291        }
292        final int[] cpSignatureClasses = new int[classes.size()];
293        for (int j = 0; j < cpSignatureClasses.length; j++) {
294            cpSignatureClasses[j] = ((CPClass) classes.get(j)).getIndex();
295        }
296
297        byte[] encodedBand = encodeBandInt("cpSignatureForm", cpSignatureForm, Codec.DELTA5);
298        out.write(encodedBand);
299        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cpSignatureForm[" + cpSignatureForm.length + "]");
300
301        encodedBand = encodeBandInt("cpSignatureClasses", cpSignatureClasses, Codec.UDELTA5);
302        out.write(encodedBand);
303        PackingUtils
304            .log("Wrote " + encodedBand.length + " bytes from cpSignatureClasses[" + cpSignatureClasses.length + "]");
305    }
306
307    private void writeCpDescr(final OutputStream out) throws IOException, Pack200Exception {
308        PackingUtils.log("Writing " + cp_Descr.size() + " Descriptor entries...");
309        final int[] cpDescrName = new int[cp_Descr.size()];
310        final int[] cpDescrType = new int[cp_Descr.size()];
311        int i = 0;
312        for (final Iterator iterator = cp_Descr.iterator(); iterator.hasNext();) {
313            final CPNameAndType nameAndType = (CPNameAndType) iterator.next();
314            cpDescrName[i] = nameAndType.getNameIndex();
315            cpDescrType[i] = nameAndType.getTypeIndex();
316            i++;
317        }
318
319        byte[] encodedBand = encodeBandInt("cp_Descr_Name", cpDescrName, Codec.DELTA5);
320        out.write(encodedBand);
321        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Descr_Name[" + cpDescrName.length + "]");
322
323        encodedBand = encodeBandInt("cp_Descr_Type", cpDescrType, Codec.UDELTA5);
324        out.write(encodedBand);
325        PackingUtils.log("Wrote " + encodedBand.length + " bytes from cp_Descr_Type[" + cpDescrType.length + "]");
326    }
327
328    private void writeCpMethodOrField(final Set cp, final OutputStream out, final String name)
329        throws IOException, Pack200Exception {
330        PackingUtils.log("Writing " + cp.size() + " Method and Field entries...");
331        final int[] cp_methodOrField_class = new int[cp.size()];
332        final int[] cp_methodOrField_desc = new int[cp.size()];
333        int i = 0;
334        for (final Iterator iterator = cp.iterator(); iterator.hasNext();) {
335            final CPMethodOrField mOrF = (CPMethodOrField) iterator.next();
336            cp_methodOrField_class[i] = mOrF.getClassIndex();
337            cp_methodOrField_desc[i] = mOrF.getDescIndex();
338            i++;
339        }
340        byte[] encodedBand = encodeBandInt(name + "_class", cp_methodOrField_class, Codec.DELTA5);
341        out.write(encodedBand);
342        PackingUtils.log(
343            "Wrote " + encodedBand.length + " bytes from " + name + "_class[" + cp_methodOrField_class.length + "]");
344
345        encodedBand = encodeBandInt(name + "_desc", cp_methodOrField_desc, Codec.UDELTA5);
346        out.write(encodedBand);
347        PackingUtils
348            .log("Wrote " + encodedBand.length + " bytes from " + name + "_desc[" + cp_methodOrField_desc.length + "]");
349    }
350
351    /**
352     * All input classes for the segment have now been read in, so this method is called so that this class can
353     * calculate/complete anything it could not do while classes were being read.
354     */
355    public void finaliseBands() {
356        addCPUtf8("");
357        removeSignaturesFromCpUTF8();
358        addIndices();
359        segmentHeader.setCp_Utf8_count(cp_Utf8.size());
360        segmentHeader.setCp_Int_count(cp_Int.size());
361        segmentHeader.setCp_Float_count(cp_Float.size());
362        segmentHeader.setCp_Long_count(cp_Long.size());
363        segmentHeader.setCp_Double_count(cp_Double.size());
364        segmentHeader.setCp_String_count(cp_String.size());
365        segmentHeader.setCp_Class_count(cp_Class.size());
366        segmentHeader.setCp_Signature_count(cp_Signature.size());
367        segmentHeader.setCp_Descr_count(cp_Descr.size());
368        segmentHeader.setCp_Field_count(cp_Field.size());
369        segmentHeader.setCp_Method_count(cp_Method.size());
370        segmentHeader.setCp_Imethod_count(cp_Imethod.size());
371    }
372
373    private void removeSignaturesFromCpUTF8() {
374        for (final Iterator iterator = cp_Signature.iterator(); iterator.hasNext();) {
375            final CPSignature signature = (CPSignature) iterator.next();
376            final String sigStr = signature.getUnderlyingString();
377            final CPUTF8 utf8 = signature.getSignatureForm();
378            final String form = utf8.getUnderlyingString();
379            if (!sigStr.equals(form)) {
380                removeCpUtf8(sigStr);
381            }
382        }
383    }
384
385    private void addIndices() {
386        final Set[] sets = {cp_Utf8, cp_Int, cp_Float, cp_Long, cp_Double, cp_String, cp_Class, cp_Signature, cp_Descr,
387            cp_Field, cp_Method, cp_Imethod};
388        for (int i = 0; i < sets.length; i++) {
389            int j = 0;
390            for (final Iterator iterator = sets[i].iterator(); iterator.hasNext();) {
391                final ConstantPoolEntry entry = (ConstantPoolEntry) iterator.next();
392                entry.setIndex(j);
393                j++;
394            }
395        }
396        final Map classNameToIndex = new HashMap();
397        for (final Iterator iterator = cp_Field.iterator(); iterator.hasNext();) {
398            final CPMethodOrField mOrF = (CPMethodOrField) iterator.next();
399            final CPClass className = mOrF.getClassName();
400            final Integer index = (Integer) classNameToIndex.get(className);
401            if (index == null) {
402                classNameToIndex.put(className, Integer.valueOf(1));
403                mOrF.setIndexInClass(0);
404            } else {
405                final int theIndex = index.intValue();
406                mOrF.setIndexInClass(theIndex);
407                classNameToIndex.put(className, Integer.valueOf(theIndex + 1));
408            }
409        }
410        classNameToIndex.clear();
411        final Map classNameToConstructorIndex = new HashMap();
412        for (final Iterator iterator = cp_Method.iterator(); iterator.hasNext();) {
413            final CPMethodOrField mOrF = (CPMethodOrField) iterator.next();
414            final CPClass className = mOrF.getClassName();
415            final Integer index = (Integer) classNameToIndex.get(className);
416            if (index == null) {
417                classNameToIndex.put(className, Integer.valueOf(1));
418                mOrF.setIndexInClass(0);
419            } else {
420                final int theIndex = index.intValue();
421                mOrF.setIndexInClass(theIndex);
422                classNameToIndex.put(className, Integer.valueOf(theIndex + 1));
423            }
424            if (mOrF.getDesc().getName().equals("<init>")) {
425                final Integer constructorIndex = (Integer) classNameToConstructorIndex.get(className);
426                if (constructorIndex == null) {
427                    classNameToConstructorIndex.put(className, Integer.valueOf(1));
428                    mOrF.setIndexInClassForConstructor(0);
429                } else {
430                    final int theIndex = constructorIndex.intValue();
431                    mOrF.setIndexInClassForConstructor(theIndex);
432                    classNameToConstructorIndex.put(className, Integer.valueOf(theIndex + 1));
433                }
434            }
435        }
436    }
437
438    private void removeCpUtf8(final String string) {
439        final CPUTF8 utf8 = (CPUTF8) stringsToCpUtf8.get(string);
440        if ((utf8 != null) && (stringsToCpClass.get(string) == null)) { // don't remove if strings are also in cpclass
441            stringsToCpUtf8.remove(string);
442            cp_Utf8.remove(utf8);
443        }
444    }
445
446    void addCPUtf8(final String utf8) {
447        getCPUtf8(utf8);
448    }
449
450    public CPUTF8 getCPUtf8(final String utf8) {
451        if (utf8 == null) {
452            return null;
453        }
454        CPUTF8 cpUtf8 = (CPUTF8) stringsToCpUtf8.get(utf8);
455        if (cpUtf8 == null) {
456            cpUtf8 = new CPUTF8(utf8);
457            cp_Utf8.add(cpUtf8);
458            stringsToCpUtf8.put(utf8, cpUtf8);
459        }
460        return cpUtf8;
461    }
462
463    public CPSignature getCPSignature(final String signature) {
464        if (signature == null) {
465            return null;
466        }
467        CPSignature cpS = (CPSignature) stringsToCpSignature.get(signature);
468        if (cpS == null) {
469            final List cpClasses = new ArrayList();
470            CPUTF8 signatureUTF8;
471            if (signature.length() > 1 && signature.indexOf('L') != -1) {
472                final List classes = new ArrayList();
473                final char[] chars = signature.toCharArray();
474                final StringBuffer signatureString = new StringBuffer();
475                for (int i = 0; i < chars.length; i++) {
476                    signatureString.append(chars[i]);
477                    if (chars[i] == 'L') {
478                        final StringBuffer className = new StringBuffer();
479                        for (int j = i + 1; j < chars.length; j++) {
480                            final char c = chars[j];
481                            if (!Character.isLetter(c) && !Character.isDigit(c) && (c != '/') && (c != '$')
482                                && (c != '_')) {
483                                classes.add(className.toString());
484                                i = j - 1;
485                                break;
486                            }
487                            className.append(c);
488                        }
489                    }
490                }
491                removeCpUtf8(signature);
492                for (final Iterator iterator2 = classes.iterator(); iterator2.hasNext();) {
493                    String className = (String) iterator2.next();
494                    CPClass cpClass = null;
495                    if (className != null) {
496                        className = className.replace('.', '/');
497                        cpClass = (CPClass) stringsToCpClass.get(className);
498                        if (cpClass == null) {
499                            final CPUTF8 cpUtf8 = getCPUtf8(className);
500                            cpClass = new CPClass(cpUtf8);
501                            cp_Class.add(cpClass);
502                            stringsToCpClass.put(className, cpClass);
503                        }
504                    }
505                    cpClasses.add(cpClass);
506                }
507
508                signatureUTF8 = getCPUtf8(signatureString.toString());
509            } else {
510                signatureUTF8 = getCPUtf8(signature);
511            }
512            cpS = new CPSignature(signature, signatureUTF8, cpClasses);
513            cp_Signature.add(cpS);
514            stringsToCpSignature.put(signature, cpS);
515        }
516        return cpS;
517    }
518
519    public CPClass getCPClass(String className) {
520        if (className == null) {
521            return null;
522        }
523        className = className.replace('.', '/');
524        CPClass cpClass = (CPClass) stringsToCpClass.get(className);
525        if (cpClass == null) {
526            final CPUTF8 cpUtf8 = getCPUtf8(className);
527            cpClass = new CPClass(cpUtf8);
528            cp_Class.add(cpClass);
529            stringsToCpClass.put(className, cpClass);
530        }
531        if (cpClass.isInnerClass()) {
532            segment.getClassBands().currentClassReferencesInnerClass(cpClass);
533        }
534        return cpClass;
535    }
536
537    public void addCPClass(final String className) {
538        getCPClass(className);
539    }
540
541    public CPNameAndType getCPNameAndType(final String name, final String signature) {
542        final String descr = name + ":" + signature;
543        CPNameAndType nameAndType = (CPNameAndType) stringsToCpNameAndType.get(descr);
544        if (nameAndType == null) {
545            nameAndType = new CPNameAndType(getCPUtf8(name), getCPSignature(signature));
546            stringsToCpNameAndType.put(descr, nameAndType);
547            cp_Descr.add(nameAndType);
548        }
549        return nameAndType;
550    }
551
552    public CPMethodOrField getCPField(final CPClass cpClass, final String name, final String desc) {
553        final String key = cpClass.toString() + ":" + name + ":" + desc;
554        CPMethodOrField cpF = (CPMethodOrField) stringsToCpField.get(key);
555        if (cpF == null) {
556            final CPNameAndType nAndT = getCPNameAndType(name, desc);
557            cpF = new CPMethodOrField(cpClass, nAndT);
558            cp_Field.add(cpF);
559            stringsToCpField.put(key, cpF);
560        }
561        return cpF;
562    }
563
564    public CPConstant getConstant(final Object value) {
565        CPConstant constant = (CPConstant) objectsToCPConstant.get(value);
566        if (constant == null) {
567            if (value instanceof Integer) {
568                constant = new CPInt(((Integer) value).intValue());
569                cp_Int.add(constant);
570            } else if (value instanceof Long) {
571                constant = new CPLong(((Long) value).longValue());
572                cp_Long.add(constant);
573            } else if (value instanceof Float) {
574                constant = new CPFloat(((Float) value).floatValue());
575                cp_Float.add(constant);
576            } else if (value instanceof Double) {
577                constant = new CPDouble(((Double) value).doubleValue());
578                cp_Double.add(constant);
579            } else if (value instanceof String) {
580                constant = new CPString(getCPUtf8((String) value));
581                cp_String.add(constant);
582            } else if (value instanceof Type) {
583                String className = ((Type) value).getClassName();
584                if (className.endsWith("[]")) {
585                    className = "[L" + className.substring(0, className.length() - 2);
586                    while (className.endsWith("[]")) {
587                        className = "[" + className.substring(0, className.length() - 2);
588                    }
589                    className += ";";
590                }
591                constant = getCPClass(className);
592            }
593            objectsToCPConstant.put(value, constant);
594        }
595        return constant;
596    }
597
598    public CPMethodOrField getCPMethod(final CPClass cpClass, final String name, final String desc) {
599        final String key = cpClass.toString() + ":" + name + ":" + desc;
600        CPMethodOrField cpM = (CPMethodOrField) stringsToCpMethod.get(key);
601        if (cpM == null) {
602            final CPNameAndType nAndT = getCPNameAndType(name, desc);
603            cpM = new CPMethodOrField(cpClass, nAndT);
604            cp_Method.add(cpM);
605            stringsToCpMethod.put(key, cpM);
606        }
607        return cpM;
608    }
609
610    public CPMethodOrField getCPIMethod(final CPClass cpClass, final String name, final String desc) {
611        final String key = cpClass.toString() + ":" + name + ":" + desc;
612        CPMethodOrField cpIM = (CPMethodOrField) stringsToCpIMethod.get(key);
613        if (cpIM == null) {
614            final CPNameAndType nAndT = getCPNameAndType(name, desc);
615            cpIM = new CPMethodOrField(cpClass, nAndT);
616            cp_Imethod.add(cpIM);
617            stringsToCpIMethod.put(key, cpIM);
618        }
619        return cpIM;
620    }
621
622    public CPMethodOrField getCPField(final String owner, final String name, final String desc) {
623        return getCPField(getCPClass(owner), name, desc);
624    }
625
626    public CPMethodOrField getCPMethod(final String owner, final String name, final String desc) {
627        return getCPMethod(getCPClass(owner), name, desc);
628    }
629
630    public CPMethodOrField getCPIMethod(final String owner, final String name, final String desc) {
631        return getCPIMethod(getCPClass(owner), name, desc);
632    }
633
634    public boolean existsCpClass(final String className) {
635        final CPClass cpClass = (CPClass) stringsToCpClass.get(className);
636        return cpClass != null;
637    }
638
639}