123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.bytecode;
-
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtPrimitiveType;
- import javassist.NotFoundException;
- import java.util.Map;
-
- /**
- * A support class for dealing with descriptors.
- *
- * <p>See chapter 4.3 in "The Java Virtual Machine Specification (2nd ed.)"
- */
- public class Descriptor {
- /**
- * Converts a class name into the internal representation used in
- * the JVM.
- *
- * <p>Note that <code>toJvmName(toJvmName(s))</code> is equivalent
- * to <code>toJvmName(s)</code>.
- */
- public static String toJvmName(String classname) {
- return classname.replace('.', '/');
- }
-
- /**
- * Converts a class name from the internal representation used in
- * the JVM to the normal one used in Java.
- */
- public static String toJavaName(String classname) {
- return classname.replace('/', '.');
- }
-
- /**
- * Returns the internal representation of the class name in the
- * JVM.
- */
- public static String toJvmName(CtClass clazz) {
- if (clazz.isArray())
- return of(clazz);
- else
- return toJvmName(clazz.getName());
- }
-
- /**
- * Converts to a Java class name from a descriptor.
- *
- * @param descriptor type descriptor.
- */
- public static String toClassName(String descriptor) {
- int arrayDim = 0;
- int i = 0;
- char c = descriptor.charAt(0);
- while (c == '[') {
- ++arrayDim;
- c = descriptor.charAt(++i);
- }
-
- String name;
- if (c == 'L') {
- int i2 = descriptor.indexOf(';', i++);
- name = descriptor.substring(i, i2).replace('/', '.');
- i = i2;
- }
- else if (c == 'V')
- name = "void";
- else if (c == 'I')
- name = "int";
- else if (c == 'B')
- name = "byte";
- else if (c == 'J')
- name = "long";
- else if (c == 'D')
- name = "double";
- else if (c == 'F')
- name = "float";
- else if (c == 'C')
- name = "char";
- else if (c == 'S')
- name = "short";
- else if (c == 'Z')
- name = "boolean";
- else
- throw new RuntimeException("bad descriptor: " + descriptor);
-
- if (i + 1 != descriptor.length())
- throw new RuntimeException("multiple descriptors?: " + descriptor);
-
- if (arrayDim == 0)
- return name;
- else {
- StringBuffer sbuf = new StringBuffer(name);
- do {
- sbuf.append("[]");
- } while (--arrayDim > 0);
-
- return sbuf.toString();
- }
- }
-
- /**
- * Converts to a descriptor from a Java class name
- */
- public static String of(String classname) {
- if (classname.equals("void"))
- return "V";
- else if (classname.equals("int"))
- return "I";
- else if (classname.equals("byte"))
- return "B";
- else if (classname.equals("long"))
- return "J";
- else if (classname.equals("double"))
- return "D";
- else if (classname.equals("float"))
- return "F";
- else if (classname.equals("char"))
- return "C";
- else if (classname.equals("short"))
- return "S";
- else if (classname.equals("boolean"))
- return "Z";
- else
- return "L" + toJvmName(classname) + ";";
- }
-
- /**
- * Substitutes a class name
- * in the given descriptor string.
- *
- * @param desc descriptor string
- * @param oldname replaced JVM class name
- * @param newname substituted JVM class name
- *
- * @see Descriptor#toJvmName(String)
- */
- public static String rename(String desc, String oldname, String newname) {
- if (desc.indexOf(oldname) < 0)
- return desc;
-
- StringBuffer newdesc = new StringBuffer();
- int head = 0;
- int i = 0;
- for (;;) {
- int j = desc.indexOf('L', i);
- if (j < 0)
- break;
- else if (desc.startsWith(oldname, j + 1)
- && desc.charAt(j + oldname.length() + 1) == ';') {
- newdesc.append(desc.substring(head, j));
- newdesc.append('L');
- newdesc.append(newname);
- newdesc.append(';');
- head = i = j + oldname.length() + 2;
- }
- else {
- i = desc.indexOf(';', j) + 1;
- if (i < 1)
- break; // ';' was not found.
- }
- }
-
- if (head == 0)
- return desc;
- else {
- int len = desc.length();
- if (head < len)
- newdesc.append(desc.substring(head, len));
-
- return newdesc.toString();
- }
- }
-
- /**
- * Substitutes class names in the given descriptor string
- * according to the given <code>map</code>.
- *
- * @param map a map between replaced and substituted
- * JVM class names.
- * @see Descriptor#toJvmName(String)
- */
- public static String rename(String desc, Map map) {
- if (map == null)
- return desc;
-
- StringBuffer newdesc = new StringBuffer();
- int head = 0;
- int i = 0;
- for (;;) {
- int j = desc.indexOf('L', i);
- if (j < 0)
- break;
-
- int k = desc.indexOf(';', j);
- if (k < 0)
- break;
-
- i = k + 1;
- String name = desc.substring(j + 1, k);
- String name2 = (String)map.get(name);
- if (name2 != null) {
- newdesc.append(desc.substring(head, j));
- newdesc.append('L');
- newdesc.append(name2);
- newdesc.append(';');
- head = i;
- }
- }
-
- if (head == 0)
- return desc;
- else {
- int len = desc.length();
- if (head < len)
- newdesc.append(desc.substring(head, len));
-
- return newdesc.toString();
- }
- }
-
- /**
- * Returns the descriptor representing the given type.
- */
- public static String of(CtClass type) {
- StringBuffer sbuf = new StringBuffer();
- toDescriptor(sbuf, type);
- return sbuf.toString();
- }
-
- private static void toDescriptor(StringBuffer desc, CtClass type) {
- if (type.isArray()) {
- desc.append('[');
- try {
- toDescriptor(desc, type.getComponentType());
- }
- catch (NotFoundException e) {
- desc.append('L');
- String name = type.getName();
- desc.append(toJvmName(name.substring(0, name.length() - 2)));
- desc.append(';');
- }
- }
- else if (type.isPrimitive()) {
- CtPrimitiveType pt = (CtPrimitiveType)type;
- desc.append(pt.getDescriptor());
- }
- else { // class type
- desc.append('L');
- desc.append(type.getName().replace('.', '/'));
- desc.append(';');
- }
- }
-
- /**
- * Returns the descriptor representing a constructor receiving
- * the given parameter types.
- *
- * @param paramTypes parameter types
- */
- public static String ofConstructor(CtClass[] paramTypes) {
- return ofMethod(CtClass.voidType, paramTypes);
- }
-
- /**
- * Returns the descriptor representing a method that receives
- * the given parameter types and returns the given type.
- *
- * @param returnType return type
- * @param paramTypes parameter types
- */
- public static String ofMethod(CtClass returnType, CtClass[] paramTypes) {
- StringBuffer desc = new StringBuffer();
- desc.append('(');
- if (paramTypes != null) {
- int n = paramTypes.length;
- for (int i = 0; i < n; ++i)
- toDescriptor(desc, paramTypes[i]);
- }
-
- desc.append(')');
- if (returnType != null)
- toDescriptor(desc, returnType);
-
- return desc.toString();
- }
-
- /**
- * Returns the descriptor representing a list of parameter types.
- * For example, if the given parameter types are two <code>int</code>,
- * then this method returns <code>"(II)"</code>.
- *
- * @param paramTypes parameter types
- */
- public static String ofParameters(CtClass[] paramTypes) {
- return ofMethod(null, paramTypes);
- }
-
- /**
- * Appends a parameter type to the parameter list represented
- * by the given descriptor.
- *
- * <p><code>classname</code> must not be an array type.
- *
- * @param classname parameter type (not primitive type)
- * @param desc descriptor
- */
- public static String appendParameter(String classname, String desc) {
- int i = desc.indexOf(')');
- if (i < 0)
- return desc;
- else {
- StringBuffer newdesc = new StringBuffer();
- newdesc.append(desc.substring(0, i));
- newdesc.append('L');
- newdesc.append(classname.replace('.', '/'));
- newdesc.append(';');
- newdesc.append(desc.substring(i));
- return newdesc.toString();
- }
- }
-
- /**
- * Inserts a parameter type at the beginning of the parameter
- * list represented
- * by the given descriptor.
- *
- * <p><code>classname</code> must not be an array type.
- *
- * @param classname parameter type (not primitive type)
- * @param desc descriptor
- */
- public static String insertParameter(String classname, String desc) {
- if (desc.charAt(0) != '(')
- return desc;
- else
- return "(L" + classname.replace('.', '/') + ';'
- + desc.substring(1);
- }
-
- /**
- * Changes the return type included in the given descriptor.
- *
- * <p><code>classname</code> must not be an array type.
- *
- * @param classname return type
- * @param desc descriptor
- */
- public static String changeReturnType(String classname, String desc) {
- int i = desc.indexOf(')');
- if (i < 0)
- return desc;
- else {
- StringBuffer newdesc = new StringBuffer();
- newdesc.append(desc.substring(0, i + 1));
- newdesc.append('L');
- newdesc.append(classname.replace('.', '/'));
- newdesc.append(';');
- return newdesc.toString();
- }
- }
-
- /**
- * Returns the <code>CtClass</code> objects representing the parameter
- * types specified by the given descriptor.
- *
- * @param desc descriptor
- * @param cp the class pool used for obtaining
- * a <code>CtClass</code> object.
- */
- public static CtClass[] getParameterTypes(String desc, ClassPool cp)
- throws NotFoundException
- {
- if (desc.charAt(0) != '(')
- return null;
- else {
- int num = numOfParameters(desc);
- CtClass[] args = new CtClass[num];
- int n = 0;
- int i = 1;
- do {
- i = toCtClass(cp, desc, i, args, n++);
- } while (i > 0);
- return args;
- }
- }
-
- /**
- * Returns true if the list of the parameter types of desc1 is equal to
- * that of desc2.
- * For example, "(II)V" and "(II)I" are equal.
- */
- public static boolean eqParamTypes(String desc1, String desc2) {
- if (desc1.charAt(0) != '(')
- return false;
-
- for (int i = 0; true; ++i) {
- char c = desc1.charAt(i);
- if (c != desc2.charAt(i))
- return false;
-
- if (c == ')')
- return true;
- }
- }
-
- /**
- * Returns the signature of the given descriptor. The signature does
- * not include the return type. For example, the signature of "(I)V"
- * is "(I)".
- */
- public static String getParamDescriptor(String decl) {
- return decl.substring(0, decl.indexOf(')') + 1);
- }
-
- /**
- * Returns the <code>CtClass</code> object representing the return
- * type specified by the given descriptor.
- *
- * @param desc descriptor
- * @param cp the class pool used for obtaining
- * a <code>CtClass</code> object.
- */
- public static CtClass getReturnType(String desc, ClassPool cp)
- throws NotFoundException
- {
- int i = desc.indexOf(')');
- if (i < 0)
- return null;
- else {
- CtClass[] type = new CtClass[1];
- toCtClass(cp, desc, i + 1, type, 0);
- return type[0];
- }
- }
-
- /**
- * Returns the number of the prameters included in the given
- * descriptor.
- *
- * @param desc descriptor
- */
- public static int numOfParameters(String desc) {
- int n = 0;
- int i = 1;
- for (;;) {
- char c = desc.charAt(i);
- if (c == ')')
- break;
-
- while (c == '[')
- c = desc.charAt(++i);
-
- if (c == 'L') {
- i = desc.indexOf(';', i) + 1;
- if (i <= 0)
- throw new IndexOutOfBoundsException("bad descriptor");
- }
- else
- ++i;
-
- ++n;
- }
-
- return n;
- }
-
- /**
- * Returns a <code>CtClass</code> object representing the type
- * specified by the given descriptor.
- *
- * <p>This method works even if the package-class separator is
- * not <code>/</code> but <code>.</code> (period). For example,
- * it accepts <code>Ljava.lang.Object;</code>
- * as well as <code>Ljava/lang/Object;</code>.
- *
- * @param desc descriptor
- * @param cp the class pool used for obtaining
- * a <code>CtClass</code> object.
- */
- public static CtClass toCtClass(String desc, ClassPool cp)
- throws NotFoundException
- {
- CtClass[] clazz = new CtClass[1];
- int res = toCtClass(cp, desc, 0, clazz, 0);
- if (res >= 0)
- return clazz[0];
- else {
- // maybe, you forgot to surround the class name with
- // L and ;. It violates the protocol, but I'm tolerant...
- return cp.get(desc.replace('/', '.'));
- }
- }
-
- private static int toCtClass(ClassPool cp, String desc, int i,
- CtClass[] args, int n)
- throws NotFoundException
- {
- int i2;
- String name;
-
- int arrayDim = 0;
- char c = desc.charAt(i);
- while (c == '[') {
- ++arrayDim;
- c = desc.charAt(++i);
- }
-
- if (c == 'L') {
- i2 = desc.indexOf(';', ++i);
- name = desc.substring(i, i2++).replace('/', '.');
- }
- else {
- CtClass type = toPrimitiveClass(c);
- if (type == null)
- return -1; // error
-
- i2 = i + 1;
- if (arrayDim == 0) {
- args[n] = type;
- return i2; // neither an array type or a class type
- }
- else
- name = type.getName();
- }
-
- if (arrayDim > 0) {
- StringBuffer sbuf = new StringBuffer(name);
- while (arrayDim-- > 0)
- sbuf.append("[]");
-
- name = sbuf.toString();
- }
-
- args[n] = cp.get(name);
- return i2;
- }
-
- private static CtClass toPrimitiveClass(char c) {
- CtClass type = null;
- switch (c) {
- case 'Z' :
- type = CtClass.booleanType;
- break;
- case 'C' :
- type = CtClass.charType;
- break;
- case 'B' :
- type = CtClass.byteType;
- break;
- case 'S' :
- type = CtClass.shortType;
- break;
- case 'I' :
- type = CtClass.intType;
- break;
- case 'J' :
- type = CtClass.longType;
- break;
- case 'F' :
- type = CtClass.floatType;
- break;
- case 'D' :
- type = CtClass.doubleType;
- break;
- case 'V' :
- type = CtClass.voidType;
- break;
- }
-
- return type;
- }
-
- /**
- * Computes the dimension of the array represented by the given
- * descriptor. For example, if the descriptor is <code>"[[I"</code>,
- * then this method returns 2.
- *
- * @param desc the descriptor.
- * @return 0 if the descriptor does not represent an array type.
- */
- public static int arrayDimension(String desc) {
- int dim = 0;
- while (desc.charAt(dim) == '[')
- ++dim;
-
- return dim;
- }
-
- /**
- * Returns the descriptor of the type of the array component.
- * For example, if the given descriptor is
- * <code>"[[Ljava/lang/String;"</code> and the given dimension is 2,
- * then this method returns <code>"Ljava/lang/String;"</code>.
- *
- * @param desc the descriptor.
- * @param dim the array dimension.
- */
- public static String toArrayComponent(String desc, int dim) {
- return desc.substring(dim);
- }
-
- /**
- * Computes the data size specified by the given descriptor.
- * For example, if the descriptor is "D", this method returns 2.
- *
- * <p>If the descriptor represents a method type, this method returns
- * (the size of the returned value) - (the sum of the data sizes
- * of all the parameters). For example, if the descriptor is
- * <code>"(I)D"</code>, then this method returns 1 (= 2 - 1).
- *
- * @param desc descriptor
- */
- public static int dataSize(String desc) {
- return dataSize(desc, true);
- }
-
- /**
- * Computes the data size of parameters.
- * If one of the parameters is double type, the size of that parameter
- * is 2 words. For example, if the given descriptor is
- * <code>"(IJ)D"</code>, then this method returns 3. The size of the
- * return type is not computed.
- *
- * @param desc a method descriptor.
- */
- public static int paramSize(String desc) {
- return -dataSize(desc, false);
- }
-
- private static int dataSize(String desc, boolean withRet) {
- int n = 0;
- char c = desc.charAt(0);
- if (c == '(') {
- int i = 1;
- for (;;) {
- c = desc.charAt(i);
- if (c == ')') {
- c = desc.charAt(i + 1);
- break;
- }
-
- boolean array = false;
- while (c == '[') {
- array = true;
- c = desc.charAt(++i);
- }
-
- if (c == 'L') {
- i = desc.indexOf(';', i) + 1;
- if (i <= 0)
- throw new IndexOutOfBoundsException("bad descriptor");
- }
- else
- ++i;
-
- if (!array && (c == 'J' || c == 'D'))
- n -= 2;
- else
- --n;
- }
- }
-
- if (withRet)
- if (c == 'J' || c == 'D')
- n += 2;
- else if (c != 'V')
- ++n;
-
- return n;
- }
-
- /**
- * An Iterator over a descriptor.
- */
- public static class Iterator {
- private String desc;
- private int index, curPos;
- private boolean param;
-
- /**
- * Constructs an iterator.
- *
- * @param s descriptor.
- */
- public Iterator(String s) {
- desc = s;
- index = curPos = 0;
- param = false;
- }
-
- /**
- * Returns true if the iteration has more elements.
- */
- public boolean hasNext() {
- return index < desc.length();
- }
-
- /**
- * Returns true if the current element is a parameter type.
- */
- public boolean isParameter() { return param; }
-
- /**
- * Returns the first character of the current element.
- */
- public char currentChar() { return desc.charAt(curPos); }
-
- /**
- * Returns true if the current element is double or long type.
- */
- public boolean is2byte() {
- char c = currentChar();
- return c == 'D' || c == 'J';
- }
-
- /**
- * Returns the position of the next type character.
- * That type character becomes a new current element.
- */
- public int next() {
- int nextPos = index;
- char c = desc.charAt(nextPos);
- if (c == '(') {
- ++index;
- c = desc.charAt(++nextPos);
- param = true;
- }
-
- if (c == ')') {
- ++index;
- c = desc.charAt(++nextPos);
- param = false;
- }
-
- while (c == '[')
- c = desc.charAt(++nextPos);
-
- if (c == 'L') {
- nextPos = desc.indexOf(';', nextPos) + 1;
- if (nextPos <= 0)
- throw new IndexOutOfBoundsException("bad descriptor");
- }
- else
- ++nextPos;
-
- curPos = index;
- index = nextPos;
- return curPos;
- }
- }
- }
|