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.java 1152077 2011-07-29 02:29:42Z dbrosius $
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 (Signature) clone();
269 }
270 }