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.Const;
26  
27  /**
28   * This class is derived from <em>Attribute</em> and represents a reference
29   * to a GJ attribute.
30   *
31   * @see     Attribute
32   */
33  public final class Signature extends Attribute {
34  
35      private int signatureIndex;
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 Signaturee/Signature.html#Signature">Signature(final 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 input Input stream
52       * @param constant_pool Array of constants
53       * @throws IOException
54       */
55      Signature(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
56              throws IOException {
57          this(name_index, length, input.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 signatureIndex Index in constant pool to CONSTANT_Utf8
65       * @param constant_pool Array of constants
66       */
67      public Signature(final int name_index, final int length, final int signatureIndex, final ConstantPool constant_pool) {
68          super(Const.ATTR_SIGNATURE, name_index, length, constant_pool);
69          this.signatureIndex = signatureIndex;
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      @Override
81      public void accept( final Visitor v ) {
82          //System.err.println("Visiting non-standard Signature object");
83          v.visitSignature(this);
84      }
85  
86  
87      /**
88       * Dump source file attribute to file stream in binary format.
89       *
90       * @param file Output file stream
91       * @throws IOException
92       */
93      @Override
94      public void dump( final DataOutputStream file ) throws IOException {
95          super.dump(file);
96          file.writeShort(signatureIndex);
97      }
98  
99  
100     /**
101      * @return Index in constant pool of source file name.
102      */
103     public int getSignatureIndex() {
104         return signatureIndex;
105     }
106 
107 
108     /**
109      * @param signatureIndex the index info the constant pool of this signature
110      */
111     public void setSignatureIndex( final int signatureIndex ) {
112         this.signatureIndex = signatureIndex;
113     }
114 
115 
116     /**
117      * @return GJ signature.
118      */
119     public String getSignature() {
120         final ConstantUtf8./../../../org/apache/bcel/classfile/ConstantUtf8.html#ConstantUtf8">ConstantUtf8 c = (ConstantUtf8) super.getConstantPool().getConstant(signatureIndex,
121                 Const.CONSTANT_Utf8);
122         return c.getBytes();
123     }
124 
125     /**
126      * Extends ByteArrayInputStream to make 'unreading' chars possible.
127      */
128     private static final class MyByteArrayInputStream extends ByteArrayInputStream {
129 
130         MyByteArrayInputStream(final String data) {
131             super(data.getBytes());
132         }
133 
134 
135         String getData() {
136             return new String(buf);
137         }
138 
139 
140         void unread() {
141             if (pos > 0) {
142                 pos--;
143             }
144         }
145     }
146 
147 
148     private static boolean identStart( final int ch ) {
149         return ch == 'T' || ch == 'L';
150     }
151 
152 
153     private static void matchIdent( final MyByteArrayInputStream in, final StringBuilder buf ) {
154         int ch;
155         if ((ch = in.read()) == -1) {
156             throw new IllegalArgumentException("Illegal signature: " + in.getData()
157                     + " no ident, reaching EOF");
158         }
159         //System.out.println("return from ident:" + (char)ch);
160         if (!identStart(ch)) {
161             final StringBuilder buf2 = new StringBuilder();
162             int count = 1;
163             while (Character.isJavaIdentifierPart((char) ch)) {
164                 buf2.append((char) ch);
165                 count++;
166                 ch = in.read();
167             }
168             if (ch == ':') { // Ok, formal parameter
169                 in.skip("Ljava/lang/Object".length());
170                 buf.append(buf2);
171                 ch = in.read();
172                 in.unread();
173                 //System.out.println("so far:" + buf2 + ":next:" +(char)ch);
174             } else {
175                 for (int i = 0; i < count; i++) {
176                     in.unread();
177                 }
178             }
179             return;
180         }
181         final StringBuilder buf2 = new StringBuilder();
182         ch = in.read();
183         do {
184             buf2.append((char) ch);
185             ch = in.read();
186             //System.out.println("within ident:"+ (char)ch);
187         } while ((ch != -1) && (Character.isJavaIdentifierPart((char) ch) || (ch == '/')));
188         buf.append(buf2.toString().replace('/', '.'));
189         //System.out.println("regular return ident:"+ (char)ch + ":" + buf2);
190         if (ch != -1) {
191             in.unread();
192         }
193     }
194 
195 
196     private static void matchGJIdent( final MyByteArrayInputStream in, final StringBuilder buf ) {
197         int ch;
198         matchIdent(in, buf);
199         ch = in.read();
200         if ((ch == '<') || ch == '(') { // Parameterized or method
201             //System.out.println("Enter <");
202             buf.append((char) ch);
203             matchGJIdent(in, buf);
204             while (((ch = in.read()) != '>') && (ch != ')')) { // List of parameters
205                 if (ch == -1) {
206                     throw new IllegalArgumentException("Illegal signature: " + in.getData()
207                             + " reaching EOF");
208                 }
209                 //System.out.println("Still no >");
210                 buf.append(", ");
211                 in.unread();
212                 matchGJIdent(in, buf); // Recursive call
213             }
214             //System.out.println("Exit >");
215             buf.append((char) ch);
216         } else {
217             in.unread();
218         }
219         ch = in.read();
220         if (identStart(ch)) {
221             in.unread();
222             matchGJIdent(in, buf);
223         } else if (ch == ')') {
224             in.unread();
225             return;
226         } else if (ch != ';') {
227             throw new IllegalArgumentException("Illegal signature: " + in.getData() + " read " + (char) ch);
228         }
229     }
230 
231 
232     public static String translate( final String s ) {
233         //System.out.println("Sig:" + s);
234         final StringBuilder buf = new StringBuilder();
235         matchGJIdent(new MyByteArrayInputStream(s), buf);
236         return buf.toString();
237     }
238 
239 
240     // @since 6.0 is no longer final
241     public static boolean isFormalParameterList( final String s ) {
242         return s.startsWith("<") && (s.indexOf(':') > 0);
243     }
244 
245 
246     // @since 6.0 is no longer final
247     public static boolean isActualParameterList( final String s ) {
248         return s.startsWith("L") && s.endsWith(">;");
249     }
250 
251 
252     /**
253      * @return String representation
254      */
255     @Override
256     public String toString() {
257         final String s = getSignature();
258         return "Signature: " + s;
259     }
260 
261 
262     /**
263      * @return deep copy of this attribute
264      */
265     @Override
266     public Attribute copy( final ConstantPool _constant_pool ) {
267         return (Attribute) clone();
268     }
269 }