    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}