• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- 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  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.bytecode;
18 
19 import java.io.DataInputStream;
20 import java.io.IOException;
21 import java.util.Map;
22 
23 /**
24  * <code>InnerClasses_attribute</code>.
25  */
26 public class InnerClassesAttribute extends AttributeInfo {
27     /**
28      * The name of this attribute <code>"InnerClasses"</code>.
29      */
30     public static final String tag = "InnerClasses";
31 
InnerClassesAttribute(ConstPool cp, int n, DataInputStream in)32     InnerClassesAttribute(ConstPool cp, int n, DataInputStream in)
33         throws IOException
34     {
35         super(cp, n, in);
36     }
37 
InnerClassesAttribute(ConstPool cp, byte[] info)38     private InnerClassesAttribute(ConstPool cp, byte[] info) {
39         super(cp, tag, info);
40     }
41 
42     /**
43      * Constructs an empty InnerClasses attribute.
44      *
45      * @see #append(String, String, String, int)
46      */
InnerClassesAttribute(ConstPool cp)47     public InnerClassesAttribute(ConstPool cp) {
48         super(cp, tag, new byte[2]);
49         ByteArray.write16bit(0, get(), 0);
50     }
51 
52     /**
53      * Returns <code>number_of_classes</code>.
54      */
tableLength()55     public int tableLength() { return ByteArray.readU16bit(get(), 0); }
56 
57     /**
58      * Returns <code>classes[nth].inner_class_info_index</code>.
59      */
innerClassIndex(int nth)60     public int innerClassIndex(int nth) {
61         return ByteArray.readU16bit(get(), nth * 8 + 2);
62     }
63 
64     /**
65      * Returns the class name indicated
66      * by <code>classes[nth].inner_class_info_index</code>.
67      * The class name is fully-qualified and separated by dot.
68      *
69      * @return null or the class name.
70      * @see ConstPool#getClassInfo(int)
71      */
innerClass(int nth)72     public String innerClass(int nth) {
73         int i = innerClassIndex(nth);
74         if (i == 0)
75             return null;
76         return constPool.getClassInfo(i);
77     }
78 
79     /**
80      * Sets <code>classes[nth].inner_class_info_index</code> to
81      * the given index.
82      */
setInnerClassIndex(int nth, int index)83     public void setInnerClassIndex(int nth, int index) {
84         ByteArray.write16bit(index, get(), nth * 8 + 2);
85     }
86 
87     /**
88      * Returns <code>classes[nth].outer_class_info_index</code>.
89      */
outerClassIndex(int nth)90     public int outerClassIndex(int nth) {
91         return ByteArray.readU16bit(get(), nth * 8 + 4);
92     }
93 
94     /**
95      * Returns the class name indicated
96      * by <code>classes[nth].outer_class_info_index</code>.
97      *
98      * @return null or the class name.
99      */
outerClass(int nth)100     public String outerClass(int nth) {
101         int i = outerClassIndex(nth);
102         if (i == 0)
103             return null;
104         return constPool.getClassInfo(i);
105     }
106 
107     /**
108      * Sets <code>classes[nth].outer_class_info_index</code> to
109      * the given index.
110      */
setOuterClassIndex(int nth, int index)111     public void setOuterClassIndex(int nth, int index) {
112         ByteArray.write16bit(index, get(), nth * 8 + 4);
113     }
114 
115     /**
116      * Returns <code>classes[nth].inner_name_index</code>.
117      */
innerNameIndex(int nth)118     public int innerNameIndex(int nth) {
119         return ByteArray.readU16bit(get(), nth * 8 + 6);
120     }
121 
122     /**
123      * Returns the simple class name indicated
124      * by <code>classes[nth].inner_name_index</code>.
125      *
126      * @return null or the class name.
127      */
innerName(int nth)128     public String innerName(int nth) {
129         int i = innerNameIndex(nth);
130         if (i == 0)
131             return null;
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      * Finds the entry for the given inner class.
160      *
161      * @param name      the fully-qualified class name separated by dot and $.
162      * @return the index or -1 if not found.
163      * @since 3.22
164      */
find(String name)165     public int find(String name) {
166         int n = tableLength();
167         for (int i = 0; i < n; i++)
168             if (name.equals(innerClass(i)))
169                 return i;
170 
171         return -1;
172     }
173 
174     /**
175      * Appends a new entry.
176      *
177      * @param inner     <code>inner_class_info_index</code>
178      * @param outer     <code>outer_class_info_index</code>
179      * @param name      <code>inner_name_index</code>
180      * @param flags     <code>inner_class_access_flags</code>
181      */
append(String inner, String outer, String name, int flags)182     public void append(String inner, String outer, String name, int flags) {
183         int i = constPool.addClassInfo(inner);
184         int o = constPool.addClassInfo(outer);
185         int n = constPool.addUtf8Info(name);
186         append(i, o, n, flags);
187     }
188 
189     /**
190      * Appends a new entry.
191      *
192      * @param inner     <code>inner_class_info_index</code>
193      * @param outer     <code>outer_class_info_index</code>
194      * @param name      <code>inner_name_index</code>
195      * @param flags     <code>inner_class_access_flags</code>
196      */
append(int inner, int outer, int name, int flags)197     public void append(int inner, int outer, int name, int flags) {
198         byte[] data = get();
199         int len = data.length;
200         byte[] newData = new byte[len + 8];
201         for (int i = 2; i < len; ++i)
202             newData[i] = data[i];
203 
204         int n = ByteArray.readU16bit(data, 0);
205         ByteArray.write16bit(n + 1, newData, 0);
206 
207         ByteArray.write16bit(inner, newData, len);
208         ByteArray.write16bit(outer, newData, len + 2);
209         ByteArray.write16bit(name, newData, len + 4);
210         ByteArray.write16bit(flags, newData, len + 6);
211 
212         set(newData);
213     }
214 
215     /**
216      * Removes the {@code nth} entry.  It does not eliminate
217      * constant pool items that the removed entry refers to.
218      * {@link ClassFile#compact()} should be executed to remove
219      * these unnecessary items.
220      *
221      * @param nth       0, 1, 2, ...
222      * @return  the number of items after the removal.
223      * @see ClassFile#compact()
224      */
remove(int nth)225     public int remove(int nth) {
226         byte[] data = get();
227         int len = data.length;
228         if (len < 10)
229             return 0;
230 
231         int n = ByteArray.readU16bit(data, 0);
232         int nthPos = 2 + nth * 8;
233         if (n <= nth)
234             return n;
235 
236         byte[] newData = new byte[len - 8];
237         ByteArray.write16bit(n - 1, newData, 0);
238         int i = 2, j = 2;
239         while (i < len)
240             if (i == nthPos)
241                 i += 8;
242             else
243                 newData[j++] = data[i++];
244 
245         set(newData);
246         return n - 1;
247     }
248 
249     /**
250      * Makes a copy.  Class names are replaced according to the
251      * given <code>Map</code> object.
252      *
253      * @param newCp     the constant pool table used by the new copy.
254      * @param classnames        pairs of replaced and substituted
255      *                          class names.
256      */
257     @Override
copy(ConstPool newCp, Map<String,String> classnames)258     public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames) {
259         byte[] src = get();
260         byte[] dest = new byte[src.length];
261         ConstPool cp = getConstPool();
262         InnerClassesAttribute attr = new InnerClassesAttribute(newCp, dest);
263         int n = ByteArray.readU16bit(src, 0);
264         ByteArray.write16bit(n, dest, 0);
265         int j = 2;
266         for (int i = 0; i < n; ++i) {
267             int innerClass = ByteArray.readU16bit(src, j);
268             int outerClass = ByteArray.readU16bit(src, j + 2);
269             int innerName = ByteArray.readU16bit(src, j + 4);
270             int innerAccess = ByteArray.readU16bit(src, j + 6);
271 
272             if (innerClass != 0)
273                 innerClass = cp.copy(innerClass, newCp, classnames);
274 
275             ByteArray.write16bit(innerClass, dest, j);
276 
277             if (outerClass != 0)
278                 outerClass = cp.copy(outerClass, newCp, classnames);
279 
280             ByteArray.write16bit(outerClass, dest, j + 2);
281 
282             if (innerName != 0)
283                 innerName = cp.copy(innerName, newCp, classnames);
284 
285             ByteArray.write16bit(innerName, dest, j + 4);
286             ByteArray.write16bit(innerAccess, dest, j + 6);
287             j += 8;
288         }
289 
290         return attr;
291     }
292 }
293