View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.classfile;
    18
    19  import java.io.ByteArrayInputStream;
    20  import java.io.DataInputStream;
    21  import java.io.DataOutputStream;
    22  import java.io.IOException;
    23  import org.apache.bcel.Constants;
    24
    25  /***
    26   * This class is derived from <em>Attribute</em> and represents a reference
    27   * to a GJ attribute.
    28   *
    29   * @version $Id: Signature.java 386056 2006-03-15 11:31:56Z tcurdt $
    30   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    31   * @see     Attribute
    32   */
    33  public final class Signature extends Attribute {
    34
    35      private int signature_index;
    36
    37
    38      /***
    39       * Initialize from another object. Note that both objects use the same
    40       * references (shallow copy). Use clone() for a physical copy.
    41       */
    42      public Signature(Signature c) {
    43          this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
    44      }
    45
    46
    47      /***
    48       * Construct object from file stream.
    49       * @param name_index Index in constant pool to CONSTANT_Utf8
    50       * @param length Content length in bytes
    51       * @param file Input stream
    52       * @param constant_pool Array of constants
    53       * @throws IOException
    54       */
    55      Signature(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
    56              throws IOException {
    57          this(name_index, length, file.readUnsignedShort(), constant_pool);
    58      }
    59
    60
    61      /***
    62       * @param name_index Index in constant pool to CONSTANT_Utf8
    63       * @param length Content length in bytes
    64       * @param signature_index Index in constant pool to CONSTANT_Utf8
    65       * @param constant_pool Array of constants
    66       */
    67      public Signature(int name_index, int length, int signature_index, ConstantPool constant_pool) {
    68          super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool);
    69          this.signature_index = signature_index;
    70      }
    71
    72
    73      /***
    74       * Called by objects that are traversing the nodes of the tree implicitely
    75       * defined by the contents of a Java class. I.e., the hierarchy of methods,
    76       * fields, attributes, etc. spawns a tree of objects.
    77       *
    78       * @param v Visitor object
    79       */
    80      public void accept( Visitor v ) {
    81          //System.err.println("Visiting non-standard Signature object");
    82          v.visitSignature(this);
    83      }
    84
    85
    86      /***
    87       * Dump source file attribute to file stream in binary format.
    88       *
    89       * @param file Output file stream
    90       * @throws IOException
    91       */
    92      public final void dump( DataOutputStream file ) throws IOException {
    93          super.dump(file);
    94          file.writeShort(signature_index);
    95      }
    96
    97
    98      /***
    99       * @return Index in constant pool of source file name.
    100      */
    101     public final int getSignatureIndex() {
    102         return signature_index;
    103     }
    104
    105
    106     /***
    107      * @param signature_index the index info the constant pool of this signature
    108      */
    109     public final void setSignatureIndex( int signature_index ) {
    110         this.signature_index = signature_index;
    111     }
    112
    113
    114     /***
    115      * @return GJ signature.
    116      */
    117     public final String getSignature() {
    118         ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(signature_index,
    119                 Constants.CONSTANT_Utf8);
    120         return c.getBytes();
    121     }
    122
    123     /***
    124      * Extends ByteArrayInputStream to make 'unreading' chars possible.
    125      */
    126     private static final class MyByteArrayInputStream extends ByteArrayInputStream {
    127
    128         MyByteArrayInputStream(String data) {
    129             super(data.getBytes());
    130         }
    131
    132
    133         final int mark() {
    134             return pos;
    135         }
    136
    137
    138         final String getData() {
    139             return new String(buf);
    140         }
    141
    142
    143         final void reset( int p ) {
    144             pos = p;
    145         }
    146
    147
    148         final void unread() {
    149             if (pos > 0) {
    150                 pos--;
    151             }
    152         }
    153     }
    154
    155
    156     private static boolean identStart( int ch ) {
    157         return ch == 'T' || ch == 'L';
    158     }
    159
    160
    161     private static final void matchIdent( MyByteArrayInputStream in, StringBuffer buf ) {
    162         int ch;
    163         if ((ch = in.read()) == -1) {
    164             throw new RuntimeException("Illegal signature: " + in.getData()
    165                     + " no ident, reaching EOF");
    166         }
    167         //System.out.println("return from ident:" + (char)ch);
    168         if (!identStart(ch)) {
    169             StringBuffer buf2 = new StringBuffer();
    170             int count = 1;
    171             while (Character.isJavaIdentifierPart((char) ch)) {
    172                 buf2.append((char) ch);
    173                 count++;
    174                 ch = in.read();
    175             }
    176             if (ch == ':') { // Ok, formal parameter
    177                 in.skip("Ljava/lang/Object".length());
    178                 buf.append(buf2);
    179                 ch = in.read();
    180                 in.unread();
    181                 //System.out.println("so far:" + buf2 + ":next:" +(char)ch);
    182             } else {
    183                 for (int i = 0; i < count; i++) {
    184                     in.unread();
    185                 }
    186             }
    187             return;
    188         }
    189         StringBuffer buf2 = new StringBuffer();
    190         ch = in.read();
    191         do {
    192             buf2.append((char) ch);
    193             ch = in.read();
    194             //System.out.println("within ident:"+ (char)ch);
    195         } while ((ch != -1) && (Character.isJavaIdentifierPart((char) ch) || (ch == '/')));
    196         buf.append(buf2.toString().replace('/', '.'));
    197         //System.out.println("regular return ident:"+ (char)ch + ":" + buf2);
    198         if (ch != -1) {
    199             in.unread();
    200         }
    201     }
    202
    203
    204     private static final void matchGJIdent( MyByteArrayInputStream in, StringBuffer buf ) {
    205         int ch;
    206         matchIdent(in, buf);
    207         ch = in.read();
    208         if ((ch == '<') || ch == '(') { // Parameterized or method
    209             //System.out.println("Enter <");
    210             buf.append((char) ch);
    211             matchGJIdent(in, buf);
    212             while (((ch = in.read()) != '>') && (ch != ')')) { // List of parameters
    213                 if (ch == -1) {
    214                     throw new RuntimeException("Illegal signature: " + in.getData()
    215                             + " reaching EOF");
    216                 }
    217                 //System.out.println("Still no >");
    218                 buf.append(", ");
    219                 in.unread();
    220                 matchGJIdent(in, buf); // Recursive call
    221             }
    222             //System.out.println("Exit >");
    223             buf.append((char) ch);
    224         } else {
    225             in.unread();
    226         }
    227         ch = in.read();
    228         if (identStart(ch)) {
    229             in.unread();
    230             matchGJIdent(in, buf);
    231         } else if (ch == ')') {
    232             in.unread();
    233             return;
    234         } else if (ch != ';') {
    235             throw new RuntimeException("Illegal signature: " + in.getData() + " read " + (char) ch);
    236         }
    237     }
    238
    239
    240     public static String translate( String s ) {
    241         //System.out.println("Sig:" + s);
    242         StringBuffer buf = new StringBuffer();
    243         matchGJIdent(new MyByteArrayInputStream(s), buf);
    244         return buf.toString();
    245     }
    246
    247
    248     public static final boolean isFormalParameterList( String s ) {
    249         return s.startsWith("<") && (s.indexOf(':') > 0);
    250     }
    251
    252
    253     public static final boolean isActualParameterList( String s ) {
    254         return s.startsWith("L") && s.endsWith(">;");
    255     }
    256
    257
    258     /***
    259      * @return String representation
    260      */
    261     public final String toString() {
    262         String s = getSignature();
    263         return "Signature(" + s + ")";
    264     }
    265
    266
    267     /***
    268      * @return deep copy of this attribute
    269      */
    270     public Attribute copy( ConstantPool _constant_pool ) {
    271         return (Signature) clone();
    272     }
    273 }