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