Package org.apache.harmony.pack200

Source Code of org.apache.harmony.pack200.CpBands

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.harmony.pack200;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantDouble;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantFloat;
import org.apache.bcel.classfile.ConstantInteger;
import org.apache.bcel.classfile.ConstantInterfaceMethodref;
import org.apache.bcel.classfile.ConstantLong;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.ConstantString;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.classfile.JavaClass;

/**
* Pack200 Constant Pool Bands
*/
public class CpBands extends BandSet {

    private final SegmentHeader segmentHeader;

    // Don't need to include default attribute names in the constant pool bands
    private final Set defaultAttributeNames = new HashSet();

    private final Set cp_Utf8 = new TreeSet();
    private final Set cp_Int = new TreeSet();
    private final Set cp_Float = new TreeSet();
    private final Set cp_Long = new TreeSet();
    private final Set cp_Double = new TreeSet();
    private final Set cp_String = new TreeSet();
    private final Set cp_Class = new TreeSet();
    private final Set cp_Signature = new TreeSet();
    private final Set cp_Descr = new TreeSet();
    private final Set cp_Field = new TreeSet();
    private final Set cp_Method = new TreeSet();
    private final Set cp_Imethod = new TreeSet();

    private final Map stringsToCpUtf8 = new HashMap();
    private final Map stringsToCpNameAndType = new HashMap();
    // private final Map stringsToCpString = new HashMap();
    private final Map stringsToCpClass = new HashMap();
    private final Map stringsToCpSignature = new HashMap();

    private final Map objectsToCPConstant = new HashMap();

    private ConstantPool currentConstantPool;
    private JavaClass currentClass;

    public CpBands(SegmentHeader segmentHeader) {
        this.segmentHeader = segmentHeader;
        defaultAttributeNames.add("AnnotationDefault");
        defaultAttributeNames.add("RuntimeVisibleAnnotations");
        defaultAttributeNames.add("RuntimeInvisibleAnnotations");
        defaultAttributeNames.add("RuntimeVisibleParameterAnnotations");
        defaultAttributeNames.add("RuntimeInvisibleParameterAnnotations");
        defaultAttributeNames.add("Code");
        defaultAttributeNames.add("LineNumberTable");
        defaultAttributeNames.add("LocalVariableTable");
        defaultAttributeNames.add("LocalVariableTypeTable");
        defaultAttributeNames.add("ConstantValue");
        defaultAttributeNames.add("Deprecated");
        defaultAttributeNames.add("EnclosingMethod");
        defaultAttributeNames.add("Exceptions");
        defaultAttributeNames.add("InnerClasses");
        defaultAttributeNames.add("Signature");
        defaultAttributeNames.add("SourceFile");
    }

    public void pack(OutputStream out) throws IOException, Pack200Exception {
        writeCpUtf8(out);
        writeCpInt(out);
        writeCpFloat(out);
        writeCpLong(out);
        writeCpDouble(out);
        writeCpString(out);
        writeCpClass(out);
        writeCpSignature(out);
        writeCpDescr(out);
        writeCpMethodOrField(cp_Field, out);
        writeCpMethodOrField(cp_Method, out);
        writeCpMethodOrField(cp_Imethod, out);
    }

    private void writeCpUtf8(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpUtf8Prefix = new int[cp_Utf8.size() - 2];
        int[] cpUtf8Suffix = new int[cp_Utf8.size() - 1];
        List chars = new ArrayList();
        List bigSuffix = new ArrayList();
        List bigChars = new ArrayList();
        Object[] cpUtf8Array = cp_Utf8.toArray();
        String first = ((CPUTF8) cpUtf8Array[1]).getUnderlyingString();
        cpUtf8Suffix[0] = first.length();
        addCharacters(chars, first.toCharArray());
        for (int i = 2; i < cpUtf8Array.length; i++) {
            char[] previous = ((CPUTF8) cpUtf8Array[i - 1])
                    .getUnderlyingString().toCharArray();
            String currentStr = ((CPUTF8) cpUtf8Array[i]).getUnderlyingString();
            char[] current = currentStr.toCharArray();
            int prefix = 0;
            for (int j = 0; j < previous.length; j++) {
                if (previous[j] == current[j]) {
                    prefix++;
                } else {
                    break;
                }
            }
            cpUtf8Prefix[i - 2] = prefix;
            currentStr = currentStr.substring(prefix);
            char[] suffix = currentStr.toCharArray();
            if (suffix.length > 100) { // big suffix (100 is arbitrary - can we
                                        // do better?)
                cpUtf8Suffix[i - 1] = 0;
                bigSuffix.add(new Integer(suffix.length));
                addCharacters(bigChars, suffix);
            } else {
                cpUtf8Suffix[i - 1] = suffix.length;
                addCharacters(chars, suffix);
            }
        }
        int[] cpUtf8Chars = new int[chars.size()];
        int[] cpUtf8BigSuffix = new int[bigSuffix.size()];
        int[] cpUtf8BigChars = new int[bigChars.size()];
        for (int i = 0; i < cpUtf8Chars.length; i++) {
            cpUtf8Chars[i] = ((Character) chars.get(i)).charValue();
        }
        for (int i = 0; i < cpUtf8BigSuffix.length; i++) {
            cpUtf8BigSuffix[i] = ((Integer) bigSuffix.get(i)).intValue();
        }
        for (int i = 0; i < cpUtf8BigChars.length; i++) {
            cpUtf8BigChars[i] = ((Character) bigChars.get(i)).charValue();
        }
        out.write(encodeBandInt(cpUtf8Prefix, Codec.DELTA5));
        out.write(encodeBandInt(cpUtf8Suffix, Codec.UNSIGNED5));
        out.write(encodeBandInt(cpUtf8Chars, Codec.CHAR3));
        out.write(encodeBandInt(cpUtf8BigSuffix, Codec.DELTA5));
        out.write(encodeBandInt(cpUtf8BigChars, Codec.DELTA5));
    }

    private void addCharacters(List chars, char[] charArray) {
        for (int i = 0; i < charArray.length; i++) {
            chars.add(new Character(charArray[i]));
        }
    }

    private void writeCpInt(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpInt = new int[cp_Int.size()];
        int i = 0;
        for (Iterator iterator = cp_Int.iterator(); iterator.hasNext();) {
            CPInt integer = (CPInt) iterator.next();
            cpInt[i] = integer.getInt();
            i++;
        }
        out.write(encodeBandInt(cpInt, Codec.UDELTA5));
    }

    private void writeCpFloat(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpFloat = new int[cp_Float.size()];
        int i = 0;
        for (Iterator iterator = cp_Float.iterator(); iterator.hasNext();) {
            CPFloat fl = (CPFloat) iterator.next();
            cpFloat[i] = Float.floatToIntBits(fl.getFloat());
            i++;
        }
        out.write(encodeBandInt(cpFloat, Codec.UDELTA5));
    }

    private void writeCpLong(OutputStream out) throws IOException,
            Pack200Exception {
        int[] highBits = new int[cp_Long.size()];
        int[] loBits = new int[cp_Long.size()];
        int i = 0;
        for (Iterator iterator = cp_Long.iterator(); iterator.hasNext();) {
            CPLong lng = (CPLong) iterator.next();
            long l = lng.getLong();
            highBits[i] = (int) (l >> 32);
            loBits[i] = (int) l;
            i++;
        }
        out.write(encodeBandInt(highBits, Codec.UDELTA5));
        out.write(encodeBandInt(loBits, Codec.DELTA5));
    }

    private void writeCpDouble(OutputStream out) throws IOException,
            Pack200Exception {
        int[] highBits = new int[cp_Double.size()];
        int[] loBits = new int[cp_Double.size()];
        int i = 0;
        for (Iterator iterator = cp_Double.iterator(); iterator.hasNext();) {
            CPDouble dbl = (CPDouble) iterator.next();
            long l = Double.doubleToLongBits(dbl.getDouble());
            highBits[i] = (int) (l >> 32);
            loBits[i] = (int) l;
            i++;
        }
        out.write(encodeBandInt(highBits, Codec.UDELTA5));
        out.write(encodeBandInt(loBits, Codec.DELTA5));
    }

    private void writeCpString(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpString = new int[cp_String.size()];
        int i = 0;
        for (Iterator iterator = cp_String.iterator(); iterator.hasNext();) {
            CPString cpStr = (CPString) iterator.next();
            cpString[i] = cpStr.getIndexInCpUtf8();
            i++;
        }
        out.write(encodeBandInt(cpString, Codec.UDELTA5));
    }

    private void writeCpClass(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpClass = new int[cp_Class.size()];
        int i = 0;
        for (Iterator iterator = cp_Class.iterator(); iterator.hasNext();) {
            CPClass cpCl = (CPClass) iterator.next();
            cpClass[i] = cpCl.getIndexInCpUtf8();
            i++;
        }
        out.write(encodeBandInt(cpClass, Codec.UDELTA5));
    }

    private void writeCpSignature(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpSignatureForm = new int[cp_Signature.size()];
        List classes = new ArrayList();
        int i = 0;
        for (Iterator iterator = cp_Signature.iterator(); iterator.hasNext();) {
            CPSignature cpS = (CPSignature) iterator.next();
            classes.addAll(cpS.getClasses());
            cpSignatureForm[i] = cpS.getIndexInCpUtf8();
            i++;
        }
        int[] cpSignatureClasses = new int[classes.size()];
        for (int j = 0; j < cpSignatureClasses.length; j++) {
            cpSignatureClasses[j] = ((CPClass) classes.get(j)).getIndex();
        }
        out.write(encodeBandInt(cpSignatureForm, Codec.DELTA5));
        out.write(encodeBandInt(cpSignatureClasses, Codec.UDELTA5));
    }

    private void writeCpDescr(OutputStream out) throws IOException,
            Pack200Exception {
        int[] cpDescrName = new int[cp_Descr.size()];
        int[] cpDescrType = new int[cp_Descr.size()];
        int i = 0;
        for (Iterator iterator = cp_Descr.iterator(); iterator.hasNext();) {
            CPNameAndType nameAndType = (CPNameAndType) iterator.next();
            cpDescrName[i] = nameAndType.getNameIndex();
            cpDescrType[i] = nameAndType.getTypeIndex();
            i++;
        }
        out.write(encodeBandInt(cpDescrName, Codec.DELTA5));
        out.write(encodeBandInt(cpDescrType, Codec.UDELTA5));
    }

    private void writeCpMethodOrField(Set cp, OutputStream out)
            throws IOException, Pack200Exception {
        int[] cp_methodOrField_class = new int[cp.size()];
        int[] cp_methodOrField_desc = new int[cp.size()];
        int i = 0;
        for (Iterator iterator = cp.iterator(); iterator.hasNext();) {
            CPMethodOrField mOrF = (CPMethodOrField) iterator.next();
            cp_methodOrField_class[i] = mOrF.getClassIndex();
            cp_methodOrField_desc[i] = mOrF.getDescIndex();
            i++;
        }
        out.write(encodeBandInt(cp_methodOrField_class, Codec.DELTA5));
        out.write(encodeBandInt(cp_methodOrField_desc, Codec.UDELTA5));
    }

    public void setCurrentClass(JavaClass javaClass) {
        this.currentClass = javaClass;
        this.currentConstantPool = javaClass.getConstantPool();
    }

    public void finaliseBands() {
        addCPUtf8("");
        removeSignaturesFromCpUTF8();
        addIndices();
        segmentHeader.setCp_Utf8_count(cp_Utf8.size());
        segmentHeader.setCp_Int_count(cp_Int.size());
        segmentHeader.setCp_Float_count(cp_Float.size());
        segmentHeader.setCp_Long_count(cp_Long.size());
        segmentHeader.setCp_Double_count(cp_Double.size());
        segmentHeader.setCp_String_count(cp_String.size());
        segmentHeader.setCp_Class_count(cp_Class.size());
        segmentHeader.setCp_Signature_count(cp_Signature.size());
        segmentHeader.setCp_Descr_count(cp_Descr.size());
        segmentHeader.setCp_Field_count(cp_Field.size());
        segmentHeader.setCp_Method_count(cp_Method.size());
        segmentHeader.setCp_Imethod_count(cp_Imethod.size());
    }

    private void removeSignaturesFromCpUTF8() {
        for (Iterator iterator = cp_Signature.iterator(); iterator.hasNext();) {
            CPSignature signature = (CPSignature) iterator.next();
            String sigStr = signature.getUnderlyingString();
            CPUTF8 utf8 = signature.getSignatureForm();
            String form = utf8.getUnderlyingString();
            if (!sigStr.equals(form)) {
                removeCpUtf8(sigStr);
            }
        }
    }

    private void addIndices() {
        Set[] sets = new Set[] { cp_Utf8, cp_String, cp_Class, cp_Signature,
                cp_Descr };
        for (int i = 0; i < sets.length; i++) {
            int j = 0;
            for (Iterator iterator = sets[i].iterator(); iterator.hasNext();) {
                ConstantPoolEntry entry = (ConstantPoolEntry) iterator.next();
                entry.setIndex(j);
                j++;
            }
        }
    }

    private void removeCpUtf8(String string) {
        CPUTF8 utf8 = (CPUTF8) stringsToCpUtf8.get(string);
        if (utf8 != null) {
            stringsToCpUtf8.remove(string);
            cp_Utf8.remove(utf8);
        }
    }

    public void addConstantClass(ConstantClass constant) {
        String className = constant.getBytes(currentConstantPool);
        addCPClass(className);
    }

    public void addConstantDouble(ConstantDouble constant) {
        double d = (constant).getBytes();
        Double bigD = new Double(d);
        CPDouble cpd = (CPDouble) objectsToCPConstant.get(bigD);
        if(cpd == null) {
            cpd = new CPDouble(d);
            cp_Double.add(cpd);
            objectsToCPConstant.put(bigD, cpd);
        }
    }

    public void addConstantFieldref(ConstantFieldref constant) {
        ConstantFieldref cf = constant;
        ConstantNameAndType cnat = (ConstantNameAndType) currentConstantPool
                .getConstant(cf.getNameAndTypeIndex());
        CPNameAndType nat = getCPNameAndType(cnat.getName(currentConstantPool),
                cnat.getSignature(currentConstantPool));
        cp_Field.add(new CPMethodOrField(getCPClass(cf
                .getClass(currentConstantPool)), nat));
    }

    public void addConstantFloat(ConstantFloat constant) {
        float f = (constant).getBytes();
        Float bigF = new Float(f);
        CPFloat cpf = (CPFloat) objectsToCPConstant.get(bigF);
        if(cpf == null) {
            cpf = new CPFloat(f);
            cp_Float.add(cpf);
            objectsToCPConstant.put(bigF, cpf);
        }
    }

    public void addConstantInteger(ConstantInteger constant) {
        int i = (constant).getBytes();
        Integer bigI = new Integer(i);
        CPInt cpi = (CPInt) objectsToCPConstant.get(bigI);
        if(cpi == null) {
            cpi = new CPInt(i);
            cp_Int.add(cpi);
            objectsToCPConstant.put(bigI, cpi);
        }
    }

    public void addConstantInterfaceMethodref(
            ConstantInterfaceMethodref constant) {
        ConstantNameAndType cnat = (ConstantNameAndType) currentConstantPool
                .getConstant(constant.getNameAndTypeIndex());
        String signature = cnat.getSignature(currentConstantPool);
        CPNameAndType nat = getCPNameAndType(cnat.getName(currentConstantPool),
                signature);
        cp_Imethod.add(new CPMethodOrField(getCPClass(constant
                .getClass(currentConstantPool)), nat));
    }

    public void addConstantLong(ConstantLong constant) {
        long l = (constant).getBytes();
        Long bigL = new Long(l);
        CPLong cpl = (CPLong) objectsToCPConstant.get(bigL);
        if(cpl == null) {
            cpl = new CPLong(l);
            cp_Long.add(cpl);
            objectsToCPConstant.put(bigL, cpl);
        }
    }

    public void addConstantMethodref(ConstantMethodref constant) {
        ConstantNameAndType cnat = (ConstantNameAndType) currentConstantPool
                .getConstant(constant.getNameAndTypeIndex());
        String signature = cnat.getSignature(currentConstantPool);
        CPNameAndType nat = getCPNameAndType(cnat.getName(currentConstantPool),
                signature);
        cp_Method.add(new CPMethodOrField(getCPClass(constant
                .getClass(currentConstantPool)), nat));
    }

    public void addConstantNameAndType(ConstantNameAndType constant) {
        String name = constant.getName(currentConstantPool);
        String signature = constant.getSignature(currentConstantPool);
        addCPNameAndType(name, signature);
    }

    public void addConstantString(ConstantString constant) {
        String string = constant.getBytes(currentConstantPool);
        CPString cpString = (CPString) objectsToCPConstant.get(string);
        if (cpString == null) {
            cpString = new CPString(getCPUtf8(string));
            cp_String.add(cpString);
            objectsToCPConstant.put(string, cpString);
        }
    }

    public void addConstantUtf8(ConstantUtf8 constant) {
        String utf8 = constant.getBytes();
        if (!defaultAttributeNames.contains(utf8)) {
            if (utf8.endsWith(".java")) {
                if (!isPredictableSourceFileName(currentClass.getClassName(), utf8)) {
                    addCPUtf8(utf8);
                }
            } else {
                addCPUtf8(utf8);
            }
        }
    }

    private void addCPUtf8(String utf8) {
        getCPUtf8(utf8);
    }

    public CPUTF8 getCPUtf8(String utf8) {
        CPUTF8 cpUtf8 = (CPUTF8) stringsToCpUtf8.get(utf8);
        if (cpUtf8 == null) {
            cpUtf8 = new CPUTF8(utf8);
            cp_Utf8.add(cpUtf8);
            stringsToCpUtf8.put(utf8, cpUtf8);
        }
        return cpUtf8;
    }

    public void addCPNameAndType(String name, String signature) {
        getCPNameAndType(name, signature);
    }

    public void addCPSignature(String signature) {
        getCPSignature(signature);
    }

    public CPSignature getCPSignature(String signature) {
        CPSignature cpS = (CPSignature) stringsToCpSignature.get(signature);
        if (cpS == null) {
            List cpClasses = new ArrayList();
            CPUTF8 signatureUTF8;
            if (signature.length() > 1 && signature.indexOf("L") != -1) {
                List classes = new ArrayList();
                char[] chars = signature.toCharArray();
                StringBuffer signatureString = new StringBuffer();
                for (int i = 0; i < chars.length; i++) {
                    signatureString.append(chars[i]);
                    if (chars[i] == 'L') {
                        StringBuffer className = new StringBuffer();
                        for (int j = i + 1; j < chars.length; j++) {
                            char c = chars[j];
                            if (Character.isLetter(c) || Character.isDigit(c)
                                    || c == '/') {
                                className.append(c);
                            } else {
                                classes.add(className.toString());
                                i = j - 1;
                                break;
                            }
                        }
                    }
                }
                removeCpUtf8(signature);
                for (Iterator iterator2 = classes.iterator(); iterator2
                        .hasNext();) {
                    cpClasses.add(getCPClass((String) iterator2.next()));
                }

                signatureUTF8 = getCPUtf8(signatureString.toString());
            } else {
                signatureUTF8 = getCPUtf8(signature);
            }
            cpS = new CPSignature(signature, signatureUTF8, cpClasses);
            cp_Signature.add(cpS);
            stringsToCpSignature.put(signature, cpS);
        }
        return cpS;
    }

    public CPClass getCPClass(String className) {
        className = className.replace('.', '/');
        CPClass cpClass = (CPClass) stringsToCpClass.get(className);
        if (cpClass == null) {
            CPUTF8 cpUtf8 = getCPUtf8(className);
            cpClass = new CPClass(cpUtf8);
            cp_Class.add(cpClass);
            stringsToCpClass.put(className, cpClass);
        }
        return cpClass;
    }

    public void addCPClass(String className) {
        getCPClass(className);
    }

    public CPNameAndType getCPNameAndType(String name, String signature) {
        String descr = name + ":" + signature;
        CPNameAndType nameAndType = (CPNameAndType) stringsToCpNameAndType
                .get(descr);
        if (nameAndType == null) {
            nameAndType = new CPNameAndType(getCPUtf8(name),
                    getCPSignature(signature));
            stringsToCpNameAndType.put(descr, nameAndType);
            cp_Descr.add(nameAndType);
        }
        return nameAndType;
    }

    public CPConstant getCPConstant(Constant theConstant, ConstantPool cp) {
        CPConstant cpC;
        if(theConstant instanceof ConstantDouble) {
            Double key = new Double(((ConstantDouble)theConstant).getBytes());
            cpC = (CPConstant) objectsToCPConstant.get(key);
            if(cpC == null) {
                cpC = new CPDouble(key.doubleValue());
                cp_Double.add(cpC);
                objectsToCPConstant.put(key, cpC);
            }
        } else if (theConstant instanceof ConstantFloat) {
            Float key = new Float(((ConstantFloat)theConstant).getBytes());
            cpC = (CPConstant) objectsToCPConstant.get(key);
            if(cpC == null) {
                cpC = new CPFloat(key.floatValue());
                cp_Float.add(cpC);
                objectsToCPConstant.put(key, cpC);
            }
        } else if (theConstant instanceof ConstantInteger) {
            Integer key = new Integer(((ConstantInteger)theConstant).getBytes());
            cpC = (CPConstant) objectsToCPConstant.get(key);
            if(cpC == null) {
                cpC = new CPInt(key.intValue());
                cp_Int.add(cpC);
                objectsToCPConstant.put(key, cpC);
            }
        } else if (theConstant instanceof ConstantLong) {
            Long key = new Long(((ConstantLong)theConstant).getBytes());
            cpC = (CPConstant) objectsToCPConstant.get(key);
            if(cpC == null) {
                cpC = new CPLong(key.longValue());
                cp_Long.add(cpC);
                objectsToCPConstant.put(key, cpC);
            }
        } else if (theConstant instanceof ConstantString) {
            String key = ((ConstantString)theConstant).getBytes(cp);
            cpC = (CPConstant) objectsToCPConstant.get(key);
            if(cpC == null) {
                cpC = new CPString(getCPUtf8(key));
                cp_String.add(cpC);
                objectsToCPConstant.put(key, cpC);
            }
        } else if (theConstant instanceof ConstantClass) {
            cpC = getCPClass(((ConstantClass)theConstant).getBytes(cp));
        } else {
            throw new RuntimeException("Unexpected constant type: " + theConstant.getClass());
        }
        return cpC;
    }

    public CPMethodOrField getCPMethodOrField(Constant constant) {
        // TODO Auto-generated method stub
        return null;
    }

}
TOP

Related Classes of org.apache.harmony.pack200.CpBands

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.