1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package com.generationjava.lang;
34
35 import org.apache.commons.lang.StringUtils;
36
37 import java.util.*;
38 import java.io.*;
39
40 /***
41 * A cut down copy of org.cyberiantiger's class object model.
42 * It provides a List of all the classes that a class file immediately
43 * depends on.
44 */
45 public class ClassConstantsReflector {
46
47 static public void main(String[] args) throws Throwable {
48 ClassConstantsReflector c = new ClassConstantsReflector();
49 for(int i=0; i<args.length; i++) {
50 System.err.println("Class=" +c.getFullyQualifiedDottedName(args[i]));
51 System.err.println("Name=" + c.getName() + "; super=" + c.getSuperName());
52 System.err.println(c.getClassConstants(args[i]));
53 System.err.println("\n");
54 }
55 }
56
57 static final public int MAGIC = 0xCAFEBABE;
58
59 static final public byte CLASS = 7;
60 static final public byte FIELD_REF = 9;
61 static final public byte METHOD_REF = 10;
62 static final public byte INTERFACE_METHOD_REF = 11;
63 static final public byte STRING = 8;
64 static final public byte INTEGER = 3;
65 static final public byte FLOAT = 4;
66 static final public byte LONG = 5;
67 static final public byte DOUBLE = 6;
68 static final public byte NAME_AND_TYPE = 12;
69 static final public byte UTF8 = 1;
70
71 private String name = null;
72
73 public String getName() {
74 return this.name;
75 }
76
77 public String getSuperName() {
78 return ""+this.superClass;
79 }
80
81 public String getFullyQualifiedDottedName(String filename) throws IOException {
82 String name = getFullyQualifiedName(filename);
83 return StringUtils.replace(name, "/", ".");
84 }
85 public String getFullyQualifiedName(String filename) throws IOException {
86 String name = null;
87
88 try {
89 DataInputStream in = new DataInputStream(new FileInputStream(filename));
90 if(in.readInt() != MAGIC) {
91
92 throw new IOException("Not a class file");
93 }
94
95 in.readUnsignedShort();
96 in.readUnsignedShort();
97 int length = in.readUnsignedShort();
98 in.readByte();
99 in.readUnsignedShort();
100 in.readByte();
101 name = in.readUTF();
102 in.close();
103 } catch(IOException ioe) {
104 ioe.printStackTrace();
105 }
106
107 return name;
108 }
109 public List getClassConstants(String classname) {
110 this.name = classname.substring(0, classname.length()-6);
111 this.name = this.name.replace('/','.');
112 try {
113 DataInputStream in = new DataInputStream(new FileInputStream(classname));
114 readFrom(in);
115 resolve();
116 return getDependencies();
117 } catch(IOException ioe) {
118 ioe.printStackTrace();
119 }
120 return new ArrayList();
121 }
122
123 List getDependencies() {
124 ArrayList list = new ArrayList();
125 Iterator iterator = constantPool.iterator();
126 while(iterator.hasNext()) {
127 Object obj = iterator.next();
128 if(obj instanceof C7) {
129 list.add(obj.toString());
130 }
131 }
132 return list;
133 }
134
135
136 int minorVersion;
137 int majorVersion;
138 ArrayList constantPool;
139 int accessFlags;
140 int this_class;
141 Object thisClass;
142 int super_class;
143 Object superClass;
144
145
146 public void readFrom(DataInputStream in) throws IOException {
147 if(in.readInt() != MAGIC) throw new IOException("Bad Magic Number");
148 minorVersion = in.readUnsignedShort();
149 majorVersion = in.readUnsignedShort();
150
151 if(!(majorVersion == 45 || (majorVersion == 46 && minorVersion == 0))){
152 throw new IOException("Unsupported version number");
153 }
154 int length = in.readUnsignedShort();
155 constantPool = new ArrayList(length);
156
157 constantPool.add(null);
158
159 for(int i=1; i<length; i++) {
160 int readByte = in.readByte();
161 switch(readByte) {
162 case CLASS:
163 C7 c7 = new C7();
164 c7.readFrom(in);
165 constantPool.add(c7);
166 break;
167 case UTF8:
168 C1 c1 = new C1();
169 c1.readFrom(in);
170 constantPool.add(c1);
171 break;
172
173
174
175 case FIELD_REF:
176 in.readUnsignedShort();
177 in.readUnsignedShort();
178 constantPool.add(null);
179 break;
180 case METHOD_REF:
181 in.readUnsignedShort();
182 in.readUnsignedShort();
183 constantPool.add(null);
184 break;
185 case INTERFACE_METHOD_REF:
186 in.readUnsignedShort();
187 in.readUnsignedShort();
188 constantPool.add(null);
189 break;
190 case STRING:
191 in.readUnsignedShort();
192 constantPool.add(null);
193 break;
194 case INTEGER:
195 in.readInt();
196 constantPool.add(null);
197 break;
198 case FLOAT:
199 in.readFloat();
200 constantPool.add(null);
201 break;
202 case LONG:
203 i++;
204 in.readLong();
205 constantPool.add(null);
206 constantPool.add(null);
207 break;
208 case DOUBLE:
209 i++;
210 in.readDouble();
211 constantPool.add(null);
212 constantPool.add(null);
213 break;
214 case NAME_AND_TYPE:
215 in.readUnsignedShort();
216 in.readUnsignedShort();
217 constantPool.add(null);
218 break;
219 default:
220 throw new IOException("Invalid Constant Found " + readByte +
221 " at " + i + " of " + length);
222 }
223 }
224
225 accessFlags = in.readUnsignedShort();
226 this_class = in.readUnsignedShort();
227 super_class = in.readUnsignedShort();
228
229
230 in.close();
231 }
232
233 public void resolve() {
234 Iterator i = constantPool.iterator();
235
236 i.next();
237
238 Object obj;
239 while(i.hasNext()) {
240 obj = i.next();
241 if(obj instanceof C7) {
242 ((C7)obj).resolve();
243 }
244 }
245
246 if(this_class == 0 || this_class >= constantPool.size() ||
247 super_class == 0 || super_class >= constantPool.size() ) {
248 throw new RuntimeException("Invalid Constant Pool Reference");
249 }
250
251 Object ob = constantPool.get(this_class);
252 if(!(ob instanceof C7) ) {
253 throw new RuntimeException("Wrong type of object at reference in constant pool");
254 }
255 thisClass = (C7) ob;
256 ob = constantPool.get(super_class);
257 if(!(ob instanceof C7) ) {
258 throw new RuntimeException("Wrong type of object at reference in constant pool");
259 }
260 superClass = (C7) ob;
261 }
262
263 class C1 {
264 String value;
265 C1() {}
266 C1(String value) {
267 this.value = value;
268 }
269 public byte getType() { return UTF8; }
270 public String getValue() { return value; }
271 public void readFrom(DataInputStream in) throws IOException {
272 value = in.readUTF();
273 }
274 public boolean equals(Object obj) {
275 return (obj instanceof C1) && ((C1)obj).value.equals(value);
276 }
277 public int hashCode() { return value.hashCode(); }
278 public String toString() { return value; }
279 }
280
281 class C7 {
282 int index;
283 C1 name;
284 public byte getType() { return CLASS; }
285 public C1 getClassName() { return name; }
286 public void readFrom(DataInputStream in) throws IOException {
287 index = in.readUnsignedShort();
288 }
289 public void resolve() {
290 if(index == 0) {
291 throw new RuntimeException("Invalid Constant Pool Reference: "+index);
292 }
293 if(index >= constantPool.size()) {
294 throw new RuntimeException("Invalid Constant Pool Reference: "+index+"/"+constantPool.size());
295 }
296 Object ob = constantPool.get(index);
297 if( !(ob instanceof C1) ) {
298 throw new RuntimeException("Wrong type of object at reference in constant pool");
299 }
300 name = (C1) ob;
301 }
302 public boolean equals(Object obj) {
303 return (obj instanceof C7) && ((C7)obj).name.equals(name);
304 }
305 public int hashCode() { return name.hashCode(); }
306 public String toString() { return name.toString().replace('/','.');}
307 }
308
309 }