1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.bytecode;
17
18import java.io.DataInputStream;
19import java.io.DataOutputStream;
20import java.io.IOException;
21import java.util.Map;
22import java.util.ArrayList;
23import java.util.ListIterator;
24import java.util.List;
25import java.util.Iterator;
26
27// Note: if you define a new subclass of AttributeInfo, then
28//       update AttributeInfo.read(), .copy(), and (maybe) write().
29
30/**
31 * <code>attribute_info</code> structure.
32 */
33public class AttributeInfo {
34    protected ConstPool constPool;
35    int name;
36    byte[] info;
37
38    protected AttributeInfo(ConstPool cp, int attrname, byte[] attrinfo) {
39        constPool = cp;
40        name = attrname;
41        info = attrinfo;
42    }
43
44    protected AttributeInfo(ConstPool cp, String attrname) {
45        this(cp, attrname, (byte[])null);
46    }
47
48    /**
49     * Constructs an <code>attribute_info</code> structure.
50     *
51     * @param cp                constant pool table
52     * @param attrname          attribute name
53     * @param attrinfo          <code>info</code> field
54     *                          of <code>attribute_info</code> structure.
55     */
56    public AttributeInfo(ConstPool cp, String attrname, byte[] attrinfo) {
57        this(cp, cp.addUtf8Info(attrname), attrinfo);
58    }
59
60    protected AttributeInfo(ConstPool cp, int n, DataInputStream in)
61        throws IOException
62    {
63        constPool = cp;
64        name = n;
65        int len = in.readInt();
66        info = new byte[len];
67        if (len > 0)
68            in.readFully(info);
69    }
70
71    static AttributeInfo read(ConstPool cp, DataInputStream in)
72        throws IOException
73    {
74        int name = in.readUnsignedShort();
75        String nameStr = cp.getUtf8Info(name);
76        if (nameStr.charAt(0) < 'L') {
77            if (nameStr.equals(AnnotationDefaultAttribute.tag))
78                return new AnnotationDefaultAttribute(cp, name, in);
79            else if (nameStr.equals(CodeAttribute.tag))
80                return new CodeAttribute(cp, name, in);
81            else if (nameStr.equals(ConstantAttribute.tag))
82                return new ConstantAttribute(cp, name, in);
83            else if (nameStr.equals(DeprecatedAttribute.tag))
84                return new DeprecatedAttribute(cp, name, in);
85            else if (nameStr.equals(EnclosingMethodAttribute.tag))
86                return new EnclosingMethodAttribute(cp, name, in);
87            else if (nameStr.equals(ExceptionsAttribute.tag))
88                return new ExceptionsAttribute(cp, name, in);
89            else if (nameStr.equals(InnerClassesAttribute.tag))
90                return new InnerClassesAttribute(cp, name, in);
91        }
92        else {
93            /* Note that the names of Annotations attributes begin with 'R'.
94             */
95            if (nameStr.equals(LineNumberAttribute.tag))
96                return new LineNumberAttribute(cp, name, in);
97            else if (nameStr.equals(LocalVariableAttribute.tag))
98                return new LocalVariableAttribute(cp, name, in);
99            else if (nameStr.equals(LocalVariableTypeAttribute.tag))
100                return new LocalVariableTypeAttribute(cp, name, in);
101            else if (nameStr.equals(AnnotationsAttribute.visibleTag)
102                     || nameStr.equals(AnnotationsAttribute.invisibleTag)) {
103                // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
104                return new AnnotationsAttribute(cp, name, in);
105            }
106            else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag)
107                || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag))
108                return new ParameterAnnotationsAttribute(cp, name, in);
109            else if (nameStr.equals(SignatureAttribute.tag))
110                return new SignatureAttribute(cp, name, in);
111            else if (nameStr.equals(SourceFileAttribute.tag))
112                return new SourceFileAttribute(cp, name, in);
113            else if (nameStr.equals(SyntheticAttribute.tag))
114                return new SyntheticAttribute(cp, name, in);
115            else if (nameStr.equals(StackMap.tag))
116                return new StackMap(cp, name, in);
117            else if (nameStr.equals(StackMapTable.tag))
118                return new StackMapTable(cp, name, in);
119        }
120
121        return new AttributeInfo(cp, name, in);
122    }
123
124    /**
125     * Returns an attribute name.
126     */
127    public String getName() {
128        return constPool.getUtf8Info(name);
129    }
130
131    /**
132     * Returns a constant pool table.
133     */
134    public ConstPool getConstPool() { return constPool; }
135
136    /**
137     * Returns the length of this <code>attribute_info</code>
138     * structure.
139     * The returned value is <code>attribute_length + 6</code>.
140     */
141    public int length() {
142        return info.length + 6;
143    }
144
145    /**
146     * Returns the <code>info</code> field
147     * of this <code>attribute_info</code> structure.
148     *
149     * <p>This method is not available if the object is an instance
150     * of <code>CodeAttribute</code>.
151     */
152    public byte[] get() { return info; }
153
154    /**
155     * Sets the <code>info</code> field
156     * of this <code>attribute_info</code> structure.
157     *
158     * <p>This method is not available if the object is an instance
159     * of <code>CodeAttribute</code>.
160     */
161    public void set(byte[] newinfo) { info = newinfo; }
162
163    /**
164     * Makes a copy.  Class names are replaced according to the
165     * given <code>Map</code> object.
166     *
167     * @param newCp     the constant pool table used by the new copy.
168     * @param classnames        pairs of replaced and substituted
169     *                          class names.
170     */
171    public AttributeInfo copy(ConstPool newCp, Map classnames) {
172        int s = info.length;
173        byte[] srcInfo = info;
174        byte[] newInfo = new byte[s];
175        for (int i = 0; i < s; ++i)
176            newInfo[i] = srcInfo[i];
177
178        return new AttributeInfo(newCp, getName(), newInfo);
179    }
180
181    void write(DataOutputStream out) throws IOException {
182        out.writeShort(name);
183        out.writeInt(info.length);
184        if (info.length > 0)
185            out.write(info);
186    }
187
188    static int getLength(ArrayList list) {
189        int size = 0;
190        int n = list.size();
191        for (int i = 0; i < n; ++i) {
192            AttributeInfo attr = (AttributeInfo)list.get(i);
193            size += attr.length();
194        }
195
196        return size;
197    }
198
199    static AttributeInfo lookup(ArrayList list, String name) {
200        if (list == null)
201            return null;
202
203        ListIterator iterator = list.listIterator();
204        while (iterator.hasNext()) {
205            AttributeInfo ai = (AttributeInfo)iterator.next();
206            if (ai.getName().equals(name))
207                return ai;
208        }
209
210        return null;            // no such attribute
211    }
212
213    static synchronized void remove(ArrayList list, String name) {
214        if (list == null)
215            return;
216
217        ListIterator iterator = list.listIterator();
218        while (iterator.hasNext()) {
219            AttributeInfo ai = (AttributeInfo)iterator.next();
220            if (ai.getName().equals(name))
221                iterator.remove();
222        }
223    }
224
225    static void writeAll(ArrayList list, DataOutputStream out)
226        throws IOException
227    {
228        if (list == null)
229            return;
230
231        int n = list.size();
232        for (int i = 0; i < n; ++i) {
233            AttributeInfo attr = (AttributeInfo)list.get(i);
234            attr.write(out);
235        }
236    }
237
238    static ArrayList copyAll(ArrayList list, ConstPool cp) {
239        if (list == null)
240            return null;
241
242        ArrayList newList = new ArrayList();
243        int n = list.size();
244        for (int i = 0; i < n; ++i) {
245            AttributeInfo attr = (AttributeInfo)list.get(i);
246            newList.add(attr.copy(cp, null));
247        }
248
249        return newList;
250    }
251
252    /* The following two methods are used to implement
253     * ClassFile.renameClass().
254     * Only CodeAttribute, LocalVariableAttribute,
255     * AnnotationsAttribute, and SignatureAttribute
256     * override these methods.
257     */
258    void renameClass(String oldname, String newname) {}
259    void renameClass(Map classnames) {}
260
261    static void renameClass(List attributes, String oldname, String newname) {
262        Iterator iterator = attributes.iterator();
263        while (iterator.hasNext()) {
264            AttributeInfo ai = (AttributeInfo)iterator.next();
265            ai.renameClass(oldname, newname);
266        }
267    }
268
269    static void renameClass(List attributes, Map classnames) {
270        Iterator iterator = attributes.iterator();
271        while (iterator.hasNext()) {
272            AttributeInfo ai = (AttributeInfo)iterator.next();
273            ai.renameClass(classnames);
274        }
275    }
276
277    void getRefClasses(Map classnames) {}
278
279    static void getRefClasses(List attributes, Map classnames) {
280        Iterator iterator = attributes.iterator();
281        while (iterator.hasNext()) {
282            AttributeInfo ai = (AttributeInfo)iterator.next();
283            ai.getRefClasses(classnames);
284        }
285    }
286}
287