1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.bcel.internal.classfile;
23
24
25import  com.sun.org.apache.bcel.internal.Constants;
26import  java.io.*;
27
28/**
29 * This class is derived from <em>Attribute</em> and represents a reference
30 * to a <href="http://wwwipd.ira.uka.de/~pizza/gj/">GJ</a> attribute.
31 *
32 * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
33 * @see     Attribute
34 */
35public final class Signature extends Attribute {
36  private int signature_index;
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   * Construct object from file stream.
48   * @param name_index Index in constant pool to CONSTANT_Utf8
49   * @param length Content length in bytes
50   * @param file Input stream
51   * @param constant_pool Array of constants
52   * @throws IOException
53   */
54  Signature(int name_index, int length, DataInputStream file,
55           ConstantPool constant_pool) throws IOException
56  {
57    this(name_index, length, file.readUnsignedShort(), constant_pool);
58  }
59
60  /**
61   * @param name_index Index in constant pool to CONSTANT_Utf8
62   * @param length Content length in bytes
63   * @param constant_pool Array of constants
64   * @param Signature_index Index in constant pool to CONSTANT_Utf8
65   */
66  public Signature(int name_index, int length, int signature_index,
67                  ConstantPool constant_pool)
68  {
69    super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool);
70    this.signature_index = signature_index;
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   * Dump source file attribute to file stream in binary format.
87   *
88   * @param file Output file stream
89   * @throws IOException
90   */
91  public final void dump(DataOutputStream file) throws IOException
92  {
93    super.dump(file);
94    file.writeShort(signature_index);
95  }
96
97  /**
98   * @return Index in constant pool of source file name.
99   */
100  public final int getSignatureIndex() { return signature_index; }
101
102  /**
103   * @param Signature_index.
104   */
105  public final void setSignatureIndex(int signature_index) {
106    this.signature_index = signature_index;
107  }
108
109  /**
110   * @return GJ signature.
111   */
112  public final String getSignature() {
113    ConstantUtf8 c = (ConstantUtf8)constant_pool.getConstant(signature_index,
114                                                             Constants.CONSTANT_Utf8);
115    return c.getBytes();
116  }
117
118  /**
119   * Extends ByteArrayInputStream to make 'unreading' chars possible.
120   */
121  private static final class MyByteArrayInputStream extends ByteArrayInputStream {
122    MyByteArrayInputStream(String data) { super(data.getBytes()); }
123    final int  mark()                   { return pos; }
124    final String getData()              { return new String(buf); }
125    final void reset(int p)             { pos = p; }
126    final void unread()                 { if(pos > 0) pos--; }
127  }
128
129  private static boolean identStart(int ch) {
130    return ch == 'T' || ch == 'L';
131  }
132
133  private static boolean identPart(int ch) {
134    return ch == '/' || ch == ';';
135  }
136
137  private static final void matchIdent(MyByteArrayInputStream in, StringBuffer buf) {
138    int ch;
139
140    if((ch = in.read()) == -1)
141      throw new RuntimeException("Illegal signature: " + in.getData() +
142                                 " no ident, reaching EOF");
143
144    //System.out.println("return from ident:" + (char)ch);
145
146    if(!identStart(ch)) {
147      StringBuffer buf2 = new StringBuffer();
148
149      int count = 1;
150      while(Character.isJavaIdentifierPart((char)ch)) {
151        buf2.append((char)ch);
152        count++;
153        ch = in.read();
154      }
155
156      if(ch == ':') { // Ok, formal parameter
157        in.skip("Ljava/lang/Object".length());
158        buf.append(buf2);
159
160        ch = in.read();
161        in.unread();
162        //System.out.println("so far:" + buf2 + ":next:" +(char)ch);
163      } else {
164        for(int i=0; i < count; i++)
165          in.unread();
166      }
167
168      return;
169    }
170
171    StringBuffer buf2 = new StringBuffer();
172    ch = in.read();
173
174    do {
175      buf2.append((char)ch);
176      ch = in.read();
177      //System.out.println("within ident:"+ (char)ch);
178
179    } while((ch != -1) && (Character.isJavaIdentifierPart((char)ch) || (ch == '/')));
180
181    buf.append(buf2.toString().replace('/', '.'));
182
183    //System.out.println("regular return ident:"+ (char)ch + ":" + buf2);
184
185    if(ch != -1)
186      in.unread();
187  }
188
189  private static final void matchGJIdent(MyByteArrayInputStream in,
190                                         StringBuffer buf)
191  {
192    int ch;
193
194    matchIdent(in, buf);
195
196    ch = in.read();
197    if((ch == '<') || ch == '(') { // Parameterized or method
198      //System.out.println("Enter <");
199      buf.append((char)ch);
200      matchGJIdent(in, buf);
201
202      while(((ch = in.read()) != '>') && (ch != ')')) { // List of parameters
203        if(ch == -1)
204          throw new RuntimeException("Illegal signature: " + in.getData() +
205                                     " reaching EOF");
206
207        //System.out.println("Still no >");
208        buf.append(", ");
209        in.unread();
210        matchGJIdent(in, buf); // Recursive call
211      }
212
213      //System.out.println("Exit >");
214
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 RuntimeException("Illegal signature: " + in.getData() + " read " +
228                                 (char)ch);
229  }
230
231  public static String translate(String s) {
232    //System.out.println("Sig:" + s);
233    StringBuffer buf = new StringBuffer();
234
235    matchGJIdent(new MyByteArrayInputStream(s), buf);
236
237    return buf.toString();
238  }
239
240  public static final boolean isFormalParameterList(String s) {
241    return s.startsWith("<") && (s.indexOf(':') > 0);
242  }
243
244  public static final boolean isActualParameterList(String s) {
245    return s.startsWith("L") && s.endsWith(">;");
246  }
247
248  /**
249   * @return String representation
250   */
251  public final String toString() {
252    String s = getSignature();
253
254    return "Signature(" + s + ")";
255  }
256
257  /**
258   * @return deep copy of this attribute
259   */
260  public Attribute copy(ConstantPool constant_pool) {
261    return (Signature)clone();
262  }
263}
264