axis-java-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject cvs commit: xml-axis/java/src/org/apache/axis/components/bytecode ClassReader.java ParamReader.java ExtractorFactory.java
Date Mon, 29 Jul 2002 15:08:00 GMT
tomj        2002/07/29 08:07:59

  Modified:    java/src/org/apache/axis/components/bytecode
                        ParamReader.java ExtractorFactory.java
  Added:       java/src/org/apache/axis/components/bytecode
                        ClassReader.java
  Log:
  Fix a bug handling parameters of type double or long, which occupy two
  slots in the local variable table.
  
  Update Built in bytecode reader to be the default.
  
  This removes Axis dependancy on tt-bytecode.jar (or any other bytecode jar).
  
  We can now remove the Extractor factory and support for other bytecode readers
  if we want, and use this class as the single way to check for debug info in
  class files.
  
  We will let this code soak a bit before we do anything too drastic however.
  
  Revision  Changes    Path
  1.4       +137 -319  xml-axis/java/src/org/apache/axis/components/bytecode/ParamReader.java
  
  Index: ParamReader.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/components/bytecode/ParamReader.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ParamReader.java	19 Jul 2002 21:15:11 -0000	1.3
  +++ ParamReader.java	29 Jul 2002 15:07:59 -0000	1.4
  @@ -56,17 +56,14 @@
   
   import org.apache.axis.utils.JavaUtils;
   
  -import java.io.ByteArrayInputStream;
  -import java.io.EOFException;
   import java.io.IOException;
  -import java.io.InputStream;
   import java.lang.reflect.Method;
   import java.lang.reflect.Modifier;
   import java.util.HashMap;
   import java.util.Map;
   
   /**
  - * this is the class file reader for obtaining the parameter names
  + * This is the class file reader for obtaining the parameter names
    * for declared methods in a class.  The class must have debugging
    * attributes for us to obtain this information. <p>
    *
  @@ -79,324 +76,145 @@
    *
    * @author Edwin Smith, Macromedia
    */
  -public class ParamReader extends ByteArrayInputStream {
  -    // constants values that appear in java class files,
  -    // from jvm spec 2nd ed, section 4.4, pp 103
  -    private static final int CONSTANT_Class = 7;
  -    private static final int CONSTANT_Fieldref = 9;
  -    private static final int CONSTANT_Methodref = 10;
  -    private static final int CONSTANT_InterfaceMethodref = 11;
  -    private static final int CONSTANT_String = 8;
  -    private static final int CONSTANT_Integer = 3;
  -    private static final int CONSTANT_Float = 4;
  -    private static final int CONSTANT_Long = 5;
  -    private static final int CONSTANT_Double = 6;
  -    private static final int CONSTANT_NameAndType = 12;
  -    private static final int CONSTANT_Utf8 = 1;
  -
  -    private String methodName;
  -    private Map methods = new HashMap();
  -
  -    /**
  -     * load the bytecode for a given class, by using the class's defining
  -     * classloader and assuming that for a class named P.C, the bytecodes are
  -     * in a resource named /P/C.class.
  -     * @param c the class of interest
  -     * @return a byte array containing the bytecode
  -     * @throws IOException
  -     */
  -    private static byte[] getBytes(Class c) throws IOException {
  -        InputStream fin = c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class");
  -        try {
  -            int length = fin.available();
  -            byte[] b = new byte[length];
  -            fin.read(b);
  -            return b;
  -        } finally {
  -            fin.close();
  -        }
  -    }
  -
  -    /**
  -     * process a class file, given it's class.  We'll use the defining
  -     * classloader to locate the bytecode.
  -     * @param c
  -     * @throws IOException
  -     */
  -    public ParamReader(Class c) throws IOException {
  -        this(getBytes(c));
  -    }
  -
  -    /**
  -     * process the given class bytes directly.
  -     * @param b
  -     * @throws IOException
  -     */
  -    public ParamReader(byte[] b) throws IOException {
  -        super(b);
  -
  -        // check the magic number
  -        if (readInt() != 0xCAFEBABE) {
  -            // not a class file!
  +public class ParamReader
  +		extends ClassReader
  +{
  +	private String methodName;
  +	private Map methods = new HashMap();
  +	private Class[] paramTypes;
  +
  +	/**
  +	 * process a class file, given it's class.  We'll use the defining
  +	 * classloader to locate the bytecode.
  +	 * @param c
  +	 * @throws IOException
  +	 */
  +	public ParamReader(Class c) throws IOException
  +	{
  +		this(getBytes(c));
  +	}
  +
  +	/**
  +	 * process the given class bytes directly.
  +	 * @param b
  +	 * @throws IOException
  +	 */
  +	public ParamReader (byte[] b) throws IOException
  +	{
  +		super(b, findAttributeReaders(ParamReader.class));
  +
  +		// check the magic number
  +		if (readInt() != 0xCAFEBABE)
  +		{
  +			// not a class file!
               throw new IOException(JavaUtils.getMessage("badClassFile00"));
  -        }
  +		}
   
  -        readShort(); // minor version
  -        readShort(); // major version
  +		readShort(); // minor version
  +		readShort(); // major version
   
  -        readCpool(); // slurp in the constant pool
  +		readCpool(); // slurp in the constant pool
   
  -        readShort(); // access flags
  -        readShort(); // this class name
  -        readShort(); // super class name
  -
  -        int count = readShort(); // ifaces count
  -        for (int i = 0; i < count; i++) {
  -            readShort(); // interface index
  -        }
  -
  -        count = readShort(); // fields count
  -        for (int i = 0; i < count; i++) {
  -            readShort(); // access flags
  -            readShort(); // name index
  -            readShort(); // descriptor index
  -            skipAttributes(); // field attributes
  -        }
  -
  -        count = readShort(); // methods count
  -        for (int i = 0; i < count; i++) {
  -            readShort(); // access flags
  -            int m = readShort(); // name index
  -            String name = getUtf8(m);
  -            int d = readShort(); // descriptor index
  -            this.methodName = name + getUtf8(d);
  -            readAttributes(); // method attributes
  -        }
  -
  -    }
  -
  -    /**
  -     * @return the next unsigned 16 bit value
  -     */
  -    private int readShort() {
  -        return (read() << 8) | read();
  -    }
  -
  -    /**
  -     * @return the next signed 32 bit value
  -     */
  -    private int readInt() {
  -        return (read() << 24) | (read() << 16) | (read() << 8) | read();
  -    }
  -
  -    /**
  -     * skip n bytes in the input stream.
  -     */
  -    private void skipFully(int n) throws IOException {
  -        while (n > 0) {
  -            int c = (int) skip(n);
  -            if (c < 0)
  -                throw new EOFException(JavaUtils.getMessage("unexpectedEOF00"));
  -            n -= c;
  -        }
  -    }
  -
  -    /**
  -     * the constant pool.  constant pool indices in the class file
  -     * directly index into this array.  The value stored in this array
  -     * is the position in the class file where that constant begins.
  -     */
  -    private int cpoolIndex[];
  -
  -    private String getUtf8(int i) throws IOException {
  -        int oldPos = pos;
  -        try {
  -            pos = cpoolIndex[i];
  -            read(); //  CONSTANT_Utf8
  -            int len = readShort();
  -            skipFully(len);
  -            return new String(buf, pos - len, len, "utf-8");
  -        } finally {
  -            pos = oldPos;
  -        }
  -    }
  -
  -    private void readCpool() throws IOException {
  -        int count = readShort(); // cpool count
  -        cpoolIndex = new int[count];
  -        for (int i = 1; i < count; i++) {
  -            cpoolIndex[i] = super.pos;
  -
  -            int c = read();
  -            switch (c) // constant pool tag
  -            {
  -                case CONSTANT_Fieldref:
  -                case CONSTANT_Methodref:
  -                case CONSTANT_InterfaceMethodref:
  -                case CONSTANT_NameAndType:
  -
  -                    readShort(); // class index or (12) name index
  -                    // fall through
  -
  -                case CONSTANT_Class:
  -                case CONSTANT_String:
  -
  -                    readShort(); // string index or class index
  -                    break;
  -
  -                case CONSTANT_Long:
  -                case CONSTANT_Double:
  -
  -                    readInt(); // hi-value
  -
  -                    // see jvm spec section 4.4.5 - double and long cpool
  -                    // entries occupy two "slots" in the cpool table.
  -                    i++;
  -                    // fall through
  -
  -                case CONSTANT_Integer:
  -                case CONSTANT_Float:
  -
  -                    readInt(); // value
  -                    break;
  -
  -                case CONSTANT_Utf8:
  -
  -                    int len = readShort();
  -                    skipFully(len);
  -                    break;
  -
  -                default:
  -                    // corrupt class file
  -                    throw new IllegalStateException(
  -                            JavaUtils.getMessage("unexpectedBytes00"));
  -            }
  -        }
  -    }
  -
  -    private void skipAttributes() throws IOException {
  -        int count = readShort();
  -        for (int i = 0; i < count; i++) {
  -            readShort(); // name index
  -            skipFully(readInt());
  -        }
  -    }
  -
  -    /**
  -     * read an attributes array.  the elements of a class file that
  -     * can contain attributes are: fields, methods, the class itself,
  -     * and some other types of attributes.
  -     */
  -    private void readAttributes() throws IOException {
  -        int count = readShort();
  -        for (int i = 0; i < count; i++) {
  -            int nameIndex = readShort(); // name index
  -            int attrLen = readInt();
  -
  -            String attrName = getUtf8(nameIndex);
  -
  -            if ("Code".equals(attrName)) {
  -                readShort(); // max stack
  -                readShort(); // max locals
  -                skipFully(readInt()); // code
  -                skipFully(8 * readShort()); // exception table
  -
  -                // read the code attributes (recursive).  This is where
  -                // we will find the LocalVariableTable attribute.
  -                readAttributes();
  -            } else if ("LocalVariableTable".equals(attrName)) {
  -                int len = readShort(); // table length
  -                String[] names = null;
  -                if (methods != null && methodName != null) {
  -                    names = new String[len];
  -                    methods.put(methodName, names);
  -                }
  -                for (int j = 0; j < len; j++) {
  -                    readShort(); // start pc
  -                    readShort(); // length
  -                    int n = readShort(); // name_index
  -                    readShort(); // descriptor_index
  -                    int index = readShort(); // index
  -
  -                    if (names != null) {
  -                        names[index] = getUtf8(n);
  -                    }
  -                }
  -            } else {
  -                // don't care what attribute this is
  -                skipFully(attrLen);
  -            }
  -        }
  -    }
  -
  -    private void addDescriptor(StringBuffer b, Class c) {
  -        if (c.isPrimitive()) {
  -            if (c == void.class)
  -                b.append('V');
  -            else if (c == int.class)
  -                b.append('I');
  -            else if (c == boolean.class)
  -                b.append('Z');
  -            else if (c == byte.class)
  -                b.append('B');
  -            else if (c == short.class)
  -                b.append('S');
  -            else if (c == long.class)
  -                b.append('J');
  -            else if (c == char.class)
  -                b.append('C');
  -            else if (c == float.class)
  -                b.append('F');
  -            else if (c == double.class) b.append('D');
  -        } else if (c.isArray()) {
  -            b.append('[');
  -            addDescriptor(b, c.getComponentType());
  -        } else {
  -            b.append('L').append(c.getName().replace('.', '/')).append(';');
  -        }
  -    }
  -
  -    /**
  -     * return the names of the declared parameters for the given method.
  -     * If we cannot determine the names, return null.  The returned array will
  -     * have one name per parameter.  The length of the array will be the same
  -     * as the length of the Class[] array returned by Method.getParameterTypes().
  -     * @param method
  -     * @return String[] array of names, one per parameter, or null
  -     */
  -    public String[] getParameterNames(Method method) {
  -        Class[] paramTypes = method.getParameterTypes();
  -
  -        // compute the method descriptor
  -
  -        StringBuffer b = new StringBuffer(method.getName());
  -        b.append('(');
  -
  -        for (int i = 0; i < paramTypes.length; i++) {
  -            addDescriptor(b, paramTypes[i]);
  -        }
  -
  -        b.append(')');
  -        addDescriptor(b, method.getReturnType());
  -
  -        // look up the names for this method
  -        String[] localNames = (String[]) methods.get(b.toString());
  -
  -        // we know all the local variable names, but we only need to return
  -        // the names of the parameters.
  -
  -        if (localNames != null) {
  -            String[] paramNames = new String[paramTypes.length];
  -            int j = Modifier.isStatic(method.getModifiers()) ? 0 : 1;
  -
  -            for (int i = 0; i < paramNames.length; i++) {
  -                paramNames[i] = localNames[j++];
  -            }
  -
  -            return paramNames;
  -        } else {
  -            return null;
  -        }
  -    }
  +		readShort(); // access flags
  +		readShort(); // this class name
  +		readShort(); // super class name
  +
  +		int count = readShort(); // ifaces count
  +		for (int i = 0; i < count; i++)
  +		{
  +			readShort(); // interface index
  +		}
  +
  +		count = readShort(); // fields count
  +		for (int i = 0; i < count; i++)
  +		{
  +			readShort(); // access flags
  +			readShort(); // name index
  +			readShort(); // descriptor index
  +			skipAttributes(); // field attributes
  +		}
  +
  +		count = readShort(); // methods count
  +		for (int i = 0; i < count; i++)
  +		{
  +			readShort(); // access flags
  +			int m = readShort(); // name index
  +			String name = resolveUtf8(m);
  +			int d = readShort(); // descriptor index
  +			this.methodName = name + resolveUtf8(d);
  +			readAttributes(); // method attributes
  +		}
  +
  +	}
  +
  +	/**
  +	 * return the names of the declared parameters for the given method.
  +	 * If we cannot determine the names, return null.  The returned array will
  +	 * have one name per parameter.  The length of the array will be the same
  +	 * as the length of the Class[] array returned by Method.getParameterTypes().
  +	 * @param method
  +	 * @return String[] array of names, one per parameter, or null
  +	 */
  +	public String[] getParameterNames(Method method)
  +	{
  +		paramTypes = method.getParameterTypes();
  +
  +		// look up the names for this method
  +		String[] localNames = (String[]) methods.get(getSignature(method, paramTypes));
  +
  +		// we know all the local variable names, but we only need to return
  +		// the names of the parameters.
  +
  +		if (localNames != null)
  +		{
  +			String[] paramNames = new String[paramTypes.length];
  +			int j = Modifier.isStatic(method.getModifiers()) ? 0 : 1;
  +
  +			for (int i=0; i < paramNames.length; i++)
  +			{
  +				paramNames[i] = localNames[j++];
  +				if (paramTypes[i] == double.class || paramTypes[i] == long.class)
  +				{
  +					// skip a slot for 64bit params
  +					j++;
  +				}
  +			}
  +
  +			return paramNames;
  +		}
  +		else
  +		{
  +			return null;
  +		}
  +	}
  +
  +	/**
  +	 * this is invoked when a LocalVariableTable attribute is encountered.
  +	 * @throws IOException
  +	 */
  +	public void readLocalVariableTable() throws IOException
  +	{
  +		int len = readShort(); // table length
  +		String[] names = null;
  +		if (methods != null && methodName != null)
  +		{
  +			// need enough room in the table to handle double-wide parameters
  +			names = new String[2*len];
  +			methods.put(methodName, names);
  +		}
  +		for (int j=0; j < len; j++)
  +		{
  +			readShort(); // start pc
  +			readShort(); // length
  +			int n = readShort(); // name_index
  +			readShort(); // descriptor_index
  +			int index = readShort(); // index
  +
  +			if (names != null)
  +			{
  +				names[index] = resolveUtf8(n);
  +			}
  +		}
  +	}
   
   }
  
  
  
  1.2       +13 -3     xml-axis/java/src/org/apache/axis/components/bytecode/ExtractorFactory.java
  
  Index: ExtractorFactory.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/components/bytecode/ExtractorFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ExtractorFactory.java	3 Jul 2002 17:50:24 -0000	1.1
  +++ ExtractorFactory.java	29 Jul 2002 15:07:59 -0000	1.2
  @@ -71,10 +71,14 @@
   public class ExtractorFactory {
       protected static Log log =
               LogFactory.getLog(ExtractorFactory.class.getName());
  +    
  +    // The built in Extractor, used by default
  +    public static final String defaultExtractor = Builtin.class.getName();
   
       public static Extractor getExtractor() {
           String extractorClassName =
  -                System.getProperty("axis.Extractor",org.apache.axis.components.bytecode.TechTrader.class.getName());
  +                System.getProperty("axis.Extractor", defaultExtractor);
  +        
           log.debug("axis.Extractor:" + extractorClassName);
           Extractor extractor = null;
           try {
  @@ -82,9 +86,15 @@
               if (Extractor.class.isAssignableFrom(extractorClass))
                   return (Extractor) extractorClass.newInstance();
           } catch (Exception e) {
  -            // If something goes wrong here, should we just fall
  -            // through and use the default one?
  +            // If something goes wrong here, log the error
  +            // and use the builtin one.
               log.error(JavaUtils.getMessage("exception00"), e);
  +
  +            try {
  +                return (Extractor) Builtin.class.newInstance();
  +            } catch (Exception e1) {
  +                // not much we can do here, fall through and return null
  +            }
           }
           return extractor;
       }
  
  
  
  1.1                  xml-axis/java/src/org/apache/axis/components/bytecode/ClassReader.java
  
  Index: ClassReader.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Axis" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.axis.components.bytecode;
  
  import org.apache.axis.utils.JavaUtils;
  
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.EOFException;
  import java.io.ByteArrayOutputStream;
  import java.util.Map;
  import java.util.HashMap;
  import java.lang.reflect.Method;
  import java.lang.reflect.Member;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.InvocationTargetException;
  
  /**
   * This is the class file reader for obtaining the parameter names
   * for declared methods in a class.  The class must have debugging
   * attributes for us to obtain this information. <p>
   *
   * This does not work for inherited methods.  To obtain parameter
   * names for inherited methods, you must use a paramReader for the
   * class that originally declared the method. <p>
   *
   * don't get tricky, it's the bare minimum.  Instances of this class
   * are not threadsafe -- don't share them. <p>
   *
   * @author Edwin Smith, Macromedia
   */
  public class ClassReader extends ByteArrayInputStream
  {
  	// constants values that appear in java class files,
  	// from jvm spec 2nd ed, section 4.4, pp 103
  	private static final int CONSTANT_Class = 7;
  	private static final int CONSTANT_Fieldref = 9;
  	private static final int CONSTANT_Methodref = 10;
  	private static final int CONSTANT_InterfaceMethodref = 11;
  	private static final int CONSTANT_String = 8;
  	private static final int CONSTANT_Integer = 3;
  	private static final int CONSTANT_Float = 4;
  	private static final int CONSTANT_Long = 5;
  	private static final int CONSTANT_Double = 6;
  	private static final int CONSTANT_NameAndType = 12;
  	private static final int CONSTANT_Utf8 = 1;
  	/**
  	 * the constant pool.  constant pool indices in the class file
  	 * directly index into this array.  The value stored in this array
  	 * is the position in the class file where that constant begins.
  	 */
  	private int[] cpoolIndex;
  	private Object[] cpool;
  
  	private Map attrMethods;
  
  	/**
  	 * load the bytecode for a given class, by using the class's defining
  	 * classloader and assuming that for a class named P.C, the bytecodes are
  	 * in a resource named /P/C.class.
  	 * @param c the class of interest
  	 * @return a byte array containing the bytecode
  	 * @throws IOException
  	 */
  	protected static byte[] getBytes(Class c) throws IOException
  	{
  		InputStream fin = c.getResourceAsStream('/'+c.getName().replace('.','/')+".class");
  		try
  		{
  			ByteArrayOutputStream out = new ByteArrayOutputStream();
  			byte[] buf = new byte[1024];
  			int actual;
  			do
  			{
  				actual = fin.read(buf);
  				if (actual > 0)
  				{
  					out.write(buf, 0, actual);
  				}
  			}
  			while (actual > 0);
  			return out.toByteArray();
  		}
  		finally
  		{
  			fin.close();
  		}
  	}
  
  	static String classDescriptorToName(String desc)
  	{
  		return desc.replace('/','.');
  	}
  
  	protected static Map findAttributeReaders(Class c)
  	{
  		HashMap map = new HashMap();
  		Method[] methods = c.getMethods();
  
  		for (int i=0; i < methods.length; i++)
  		{
  			String name = methods[i].getName();
  			if (name.startsWith("read") && methods[i].getReturnType() == void.class)
  			{
  				map.put(name.substring(4), methods[i]);
  			}
  		}
  
  		return map;
  	}
  
  
  	protected static String getSignature(Member method, Class[] paramTypes)
  	{
  		// compute the method descriptor
  
  		StringBuffer b = new StringBuffer((method instanceof Method) ? method.getName() : "<init>");
  		b.append('(');
  
  		for (int i=0; i < paramTypes.length; i++)
  		{
  			addDescriptor(b, paramTypes[i]);
  		}
  
  		b.append(')');
  		if (method instanceof Method)
  		{
  			addDescriptor(b, ((Method)method).getReturnType());
  		}
  		else if (method instanceof Constructor)
  		{
  			addDescriptor(b, void.class);
  		}
  
  		return b.toString();
  	}
  
  	private static void addDescriptor(StringBuffer b, Class c)
  	{
  		if (c.isPrimitive())
  		{
  			if (c == void.class) b.append('V');
  			else if (c == int.class) b.append('I');
  			else if (c == boolean.class) b.append('Z');
  			else if (c == byte.class) b.append('B');
  			else if (c == short.class) b.append('S');
  			else if (c == long.class) b.append('J');
  			else if (c == char.class) b.append('C');
  			else if (c == float.class) b.append('F');
  			else if (c == double.class) b.append('D');
  		}
  		else if (c.isArray())
  		{
  			b.append('[');
  			addDescriptor(b, c.getComponentType());
  		}
  		else
  		{
  			b.append('L').append(c.getName().replace('.','/')).append(';');
  		}
  	}
  
  
  	/**
  	 * @return the next unsigned 16 bit value
  	 */
  	final protected int readShort()
  	{
  		return (read() << 8) | read();
  	}
  
  	/**
  	 * @return the next signed 32 bit value
  	 */
  	final protected int readInt()
  	{
  		return (read() << 24) | (read() << 16) | (read() << 8) | read();
  	}
  
  	/**
  	 * skip n bytes in the input stream.
  	 */
  	protected void skipFully(int n) throws IOException
  	{
  		while (n > 0)
  		{
  			int c = (int) skip(n);
  			if (c <= 0)
                  throw new EOFException(JavaUtils.getMessage("unexpectedEOF00"));
  			n -= c;
  		}
  	}
  
  	final protected Member resolveMethod(int index) throws IOException, ClassNotFoundException,
NoSuchMethodException
  	{
  		int oldPos = pos;
  		try
  		{
  			Member m = (Member) cpool[index];
  			if (m == null)
  			{
  				pos = cpoolIndex[index];
  				Class owner = resolveClass(readShort());
  				NameAndType nt = resolveNameAndType(readShort());
  				String signature = nt.name + nt.type;
  				if (nt.name.equals("<init>"))
  				{
  					Constructor[] ctors = owner.getConstructors();
  					for (int i=0; i < ctors.length; i++)
  					{
  						String sig = getSignature(ctors[i], ctors[i].getParameterTypes());
  						if (sig.equals(signature))
  						{
  							cpool[index] = m = ctors[i];
  							return m;
  						}
  					}
  				}
  				else
  				{
  					Method[] methods = owner.getDeclaredMethods();
  					for (int i=0; i < methods.length; i++)
  					{
  						String sig = getSignature(methods[i], methods[i].getParameterTypes());
  						if (sig.equals(signature))
  						{
  							cpool[index] = m = methods[i];
  							return m;
  						}
  					}
  				}
  				throw new NoSuchMethodException(signature);
  			}
  			return m;
  		}
  		finally
  		{
  			pos = oldPos;
  		}
  
  	}
  
  	final protected Field resolveField(int i) throws IOException, ClassNotFoundException, NoSuchFieldException
  	{
  		int oldPos = pos;
  		try
  		{
  			Field f = (Field) cpool[i];
  			if (f == null)
  			{
  				pos = cpoolIndex[i];
  				Class owner = resolveClass(readShort());
  				NameAndType nt = resolveNameAndType(readShort());
  				cpool[i] = f = owner.getDeclaredField(nt.name);
  			}
  			return f;
  		}
  		finally
  		{
  			pos = oldPos;
  		}
  	}
  
  	private static class NameAndType
  	{
  		String name;
  		String type;
  
  		public NameAndType(String name, String type)
  		{
  			this.name = name;
  			this.type = type;
  		}
  	}
  
  	final protected NameAndType resolveNameAndType(int i) throws IOException
  	{
  		int oldPos = pos;
  		try
  		{
  			NameAndType nt = (NameAndType) cpool[i];
  			if (nt == null)
  			{
  				pos = cpoolIndex[i];
  				String name = resolveUtf8(readShort());
  				String type = resolveUtf8(readShort());
  				cpool[i] = nt = new NameAndType(name, type);
  			}
  			return nt;
  		}
  		finally
  		{
  			pos = oldPos;
  		}
  	}
  
  
  	final protected Class resolveClass(int i) throws IOException, ClassNotFoundException
  	{
  		int oldPos = pos;
  		try
  		{
  			Class c = (Class) cpool[i];
  			if (c == null)
  			{
  				pos = cpoolIndex[i];
  				String name = resolveUtf8(readShort());
  				cpool[i] = c = Class.forName(classDescriptorToName(name));
  			}
  			return c;
  		}
  		finally
  		{
  			pos = oldPos;
  		}
  	}
  
  	final protected String resolveUtf8(int i) throws IOException
  	{
  		int oldPos = pos;
  		try
  		{
  			String s = (String) cpool[i];
  			if (s == null)
  			{
  				pos = cpoolIndex[i];
  				int len = readShort();
  				skipFully(len);
  				cpool[i] = s = new String(buf, pos - len, len, "utf-8");
  			}
  			return s;
  		}
  		finally
  		{
  			pos = oldPos;
  		}
  	}
  
  	final protected void readCpool() throws IOException
  	{
  		int count = readShort(); // cpool count
  		cpoolIndex = new int[count];
  		cpool = new Object[count];
  		for (int i = 1; i < count; i++)
  		{
  			int c = read();
  			cpoolIndex[i] = super.pos;
  			switch (c) // constant pool tag
  			{
  			case CONSTANT_Fieldref:
  			case CONSTANT_Methodref:
  			case CONSTANT_InterfaceMethodref:
  			case CONSTANT_NameAndType:
  
  				readShort(); // class index or (12) name index
  				// fall through
  
  			case CONSTANT_Class:
  			case CONSTANT_String:
  
  				readShort(); // string index or class index
  				break;
  
  			case CONSTANT_Long:
  			case CONSTANT_Double:
  
  				readInt(); // hi-value
  
  				// see jvm spec section 4.4.5 - double and long cpool
  				// entries occupy two "slots" in the cpool table.
  				i++;
  				// fall through
  
  			case CONSTANT_Integer:
  			case CONSTANT_Float:
  
  				readInt(); // value
  				break;
  
  			case CONSTANT_Utf8:
  
  				int len = readShort();
  				skipFully(len);
  				break;
  
  			default:
  				// corrupt class file
                      throw new IllegalStateException(
                              JavaUtils.getMessage("unexpectedBytes00"));
  			}
  		}
  	}
  
  	final protected void skipAttributes() throws IOException
  	{
  		int count = readShort();
  		for (int i=0; i < count; i++)
  		{
  			readShort(); // name index
  			skipFully(readInt());
  		}
  	}
  
  	/**
  	 * read an attributes array.  the elements of a class file that
  	 * can contain attributes are: fields, methods, the class itself,
  	 * and some other types of attributes.
  	 */
  	final protected void readAttributes() throws IOException
  	{
  		int count = readShort();
  		for (int i = 0; i < count; i++)
  		{
  			int nameIndex = readShort(); // name index
  			int attrLen = readInt();
  			int curPos = pos;
  
  			String attrName = resolveUtf8(nameIndex);
  
  			Method m = (Method) attrMethods.get(attrName);
  
  			if (m != null)
  			{
  				try
  				{
  					m.invoke(this, new Object[] {});
  				}
  				catch (IllegalAccessException e)
  				{
  					pos = curPos;
  					skipFully(attrLen);
  				}
  				catch (InvocationTargetException e)
  				{
  					try
  					{
  						throw e.getTargetException();
  					}
  					catch (Error ex) { throw ex; }
  					catch (RuntimeException ex) { throw ex; }
  					catch (IOException ex) { throw ex; }
  					catch (Throwable ex)
  					{
  						pos = curPos;
  						skipFully(attrLen);
  					}
  				}
  			}
  			else
  			{
  				// don't care what attribute this is
  				skipFully(attrLen);
  			}
  		}
  	}
  
  	/**
  	 * read a code attribute
  	 * @throws IOException
  	 */
  	public void readCode() throws IOException
  	{
  		readShort(); // max stack
  		readShort(); // max locals
  		skipFully(readInt()); // code
  		skipFully(8 * readShort()); // exception table
  
  		// read the code attributes (recursive).  This is where
  		// we will find the LocalVariableTable attribute.
  		readAttributes();
  	}
  
  	protected ClassReader(byte buf[], Map attrMethods)
  	{
  		super(buf);
  
  		this.attrMethods = attrMethods;
  	}
  }
  
  
  
  

Mime
View raw message