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 
16 package javassist.bytecode;
17 
18 import java.io.DataInputStream;
19 import java.util.Map;
20 import java.io.IOException;
21 
22 /**
23  * <code>InnerClasses_attribute</code>.
24  */
25 public class InnerClassesAttribute extends AttributeInfo {
26     /**
27      * The name of this attribute <code>"InnerClasses"</code>.
28      */
29     public static final String tag = "InnerClasses";
30 
InnerClassesAttribute(ConstPool cp, int n, DataInputStream in)31     InnerClassesAttribute(ConstPool cp, int n, DataInputStream in)
32         throws IOException
33     {
34         super(cp, n, in);
35     }
36 
InnerClassesAttribute(ConstPool cp, byte[] info)37     private InnerClassesAttribute(ConstPool cp, byte[] info) {
38         super(cp, tag, info);
39     }
40 
41     /**
42      * Constructs an empty InnerClasses attribute.
43      *
44      * @see #append(String, String, String, int)
45      */
InnerClassesAttribute(ConstPool cp)46     public InnerClassesAttribute(ConstPool cp) {
47         super(cp, tag, new byte[2]);
48         ByteArray.write16bit(0, get(), 0);
49     }
50 
51     /**
52      * Returns <code>number_of_classes</code>.
53      */
tableLength()54     public int tableLength() { return ByteArray.readU16bit(get(), 0); }
55 
56     /**
57      * Returns <code>classes[nth].inner_class_info_index</code>.
58      */
innerClassIndex(int nth)59     public int innerClassIndex(int nth) {
60         return ByteArray.readU16bit(get(), nth * 8 + 2);
61     }
62 
63     /**
64      * Returns the class name indicated
65      * by <code>classes[nth].inner_class_info_index</code>.
66      *
67      * @return null or the class name.
68      */
innerClass(int nth)69     public String innerClass(int nth) {
70         int i = innerClassIndex(nth);
71         if (i == 0)
72             return null;
73         else
74             return constPool.getClassInfo(i);
75     }
76 
77     /**
78      * Sets <code>classes[nth].inner_class_info_index</code> to
79      * the given index.
80      */
setInnerClassIndex(int nth, int index)81     public void setInnerClassIndex(int nth, int index) {
82         ByteArray.write16bit(index, get(), nth * 8 + 2);
83     }
84 
85     /**
86      * Returns <code>classes[nth].outer_class_info_index</code>.
87      */
outerClassIndex(int nth)88     public int outerClassIndex(int nth) {
89         return ByteArray.readU16bit(get(), nth * 8 + 4);
90     }
91 
92     /**
93      * Returns the class name indicated
94      * by <code>classes[nth].outer_class_info_index</code>.
95      *
96      * @return null or the class name.
97      */
outerClass(int nth)98     public String outerClass(int nth) {
99         int i = outerClassIndex(nth);
100         if (i == 0)
101             return null;
102         else
103             return constPool.getClassInfo(i);
104     }
105 
106     /**
107      * Sets <code>classes[nth].outer_class_info_index</code> to
108      * the given index.
109      */
setOuterClassIndex(int nth, int index)110     public void setOuterClassIndex(int nth, int index) {
111         ByteArray.write16bit(index, get(), nth * 8 + 4);
112     }
113 
114     /**
115      * Returns <code>classes[nth].inner_name_index</code>.
116      */
innerNameIndex(int nth)117     public int innerNameIndex(int nth) {
118         return ByteArray.readU16bit(get(), nth * 8 + 6);
119     }
120 
121     /**
122      * Returns the simple class name indicated
123      * by <code>classes[nth].inner_name_index</code>.
124      *
125      * @return null or the class name.
126      */
innerName(int nth)127     public String innerName(int nth) {
128         int i = innerNameIndex(nth);
129         if (i == 0)
130             return null;
131         else
132             return constPool.getUtf8Info(i);
133     }
134 
135     /**
136      * Sets <code>classes[nth].inner_name_index</code> to
137      * the given index.
138      */
setInnerNameIndex(int nth, int index)139     public void setInnerNameIndex(int nth, int index) {
140         ByteArray.write16bit(index, get(), nth * 8 + 6);
141     }
142 
143     /**
144      * Returns <code>classes[nth].inner_class_access_flags</code>.
145      */
accessFlags(int nth)146     public int accessFlags(int nth) {
147         return ByteArray.readU16bit(get(), nth * 8 + 8);
148     }
149 
150     /**
151      * Sets <code>classes[nth].inner_class_access_flags</code> to
152      * the given index.
153      */
setAccessFlags(int nth, int flags)154     public void setAccessFlags(int nth, int flags) {
155         ByteArray.write16bit(flags, get(), nth * 8 + 8);
156     }
157 
158     /**
159      * Appends a new entry.
160      *
161      * @param inner     <code>inner_class_info_index</code>
162      * @param outer     <code>outer_class_info_index</code>
163      * @param name      <code>inner_name_index</code>
164      * @param flags     <code>inner_class_access_flags</code>
165      */
append(String inner, String outer, String name, int flags)166     public void append(String inner, String outer, String name, int flags) {
167         int i = constPool.addClassInfo(inner);
168         int o = constPool.addClassInfo(outer);
169         int n = constPool.addUtf8Info(name);
170         append(i, o, n, flags);
171     }
172 
173     /**
174      * Appends a new entry.
175      *
176      * @param inner     <code>inner_class_info_index</code>
177      * @param outer     <code>outer_class_info_index</code>
178      * @param name      <code>inner_name_index</code>
179      * @param flags     <code>inner_class_access_flags</code>
180      */
append(int inner, int outer, int name, int flags)181     public void append(int inner, int outer, int name, int flags) {
182         byte[] data = get();
183         int len = data.length;
184         byte[] newData = new byte[len + 8];
185         for (int i = 2; i < len; ++i)
186             newData[i] = data[i];
187 
188         int n = ByteArray.readU16bit(data, 0);
189         ByteArray.write16bit(n + 1, newData, 0);
190 
191         ByteArray.write16bit(inner, newData, len);
192         ByteArray.write16bit(outer, newData, len + 2);
193         ByteArray.write16bit(name, newData, len + 4);
194         ByteArray.write16bit(flags, newData, len + 6);
195 
196         set(newData);
197     }
198 
199     /**
200      * Makes a copy.  Class names are replaced according to the
201      * given <code>Map</code> object.
202      *
203      * @param newCp     the constant pool table used by the new copy.
204      * @param classnames        pairs of replaced and substituted
205      *                          class names.
206      */
copy(ConstPool newCp, Map classnames)207     public AttributeInfo copy(ConstPool newCp, Map classnames) {
208         byte[] src = get();
209         byte[] dest = new byte[src.length];
210         ConstPool cp = getConstPool();
211         InnerClassesAttribute attr = new InnerClassesAttribute(newCp, dest);
212         int n = ByteArray.readU16bit(src, 0);
213         ByteArray.write16bit(n, dest, 0);
214         int j = 2;
215         for (int i = 0; i < n; ++i) {
216             int innerClass = ByteArray.readU16bit(src, j);
217             int outerClass = ByteArray.readU16bit(src, j + 2);
218             int innerName = ByteArray.readU16bit(src, j + 4);
219             int innerAccess = ByteArray.readU16bit(src, j + 6);
220 
221             if (innerClass != 0)
222                 innerClass = cp.copy(innerClass, newCp, classnames);
223 
224             ByteArray.write16bit(innerClass, dest, j);
225 
226             if (outerClass != 0)
227                 outerClass = cp.copy(outerClass, newCp, classnames);
228 
229             ByteArray.write16bit(outerClass, dest, j + 2);
230 
231             if (innerName != 0)
232                 innerName = cp.copy(innerName, newCp, classnames);
233 
234             ByteArray.write16bit(innerName, dest, j + 4);
235             ByteArray.write16bit(innerAccess, dest, j + 6);
236             j += 8;
237         }
238 
239         return attr;
240     }
241 }
242