1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package separate;
25 
26 import java.io.*;
27 import java.util.*;
28 
29 class CfInputStream extends ByteArrayInputStream {
30     private int ct;
CfInputStream(byte[] input)31     public CfInputStream(byte[] input) {
32         super(input);
33     }
34 
u1()35     byte u1() { return (byte)read(); }
u2()36     short u2() {
37         int b0 = read() << 8;
38         int b1 = read();
39         return (short)(b0 | b1);
40     }
u4()41     int u4() {
42         int b0 = read() << 24;
43         int b1 = read() << 16;
44         int b2 = read() << 8;
45         int b3 = read();
46         return b0 | b1 | b2 | b3;
47     }
array(int count)48     byte[] array(int count) {
49         byte[] ret = new byte[count];
50         read(ret, 0, count);
51         return ret;
52     }
53 };
54 
55 class CfOutputStream extends ByteArrayOutputStream {
u1(byte b)56     void u1(byte b) { write((int)b); }
u2(short s)57     void u2(short s) {
58         write((s >> 8) & 0xff);
59         write(s & 0xff);
60     }
u4(int i)61     void u4(int i) {
62         write((i >> 24) & 0xff);
63         write((i >> 16) & 0xff);
64         write((i >> 8) & 0xff);
65         write(i & 0xff);
66     }
array(byte[] a)67     void array(byte[] a) {
68         write(a, 0, a.length);
69     }
70 
toByteArray()71     public byte[] toByteArray() { return super.toByteArray(); }
72 };
73 
74 // A quick and dirty class file parser and representation
75 public class ClassFile {
76 
77     int magic;
78     short minor_version;
79     short major_version;
80     ArrayList<CpEntry> constant_pool;
81     short access_flags;
82     short this_class;
83     short super_class;
84     ArrayList<Interface> interfaces;
85     ArrayList<Field> fields;
86     ArrayList<Method> methods;
87     ArrayList<Attribute> attributes;
88 
ClassFile(byte[] cf)89     ClassFile(byte[] cf) {
90         CfInputStream in = new CfInputStream(cf);
91 
92         magic = in.u4();
93         minor_version = in.u2();
94         major_version = in.u2();
95 
96         short cpCount = in.u2();
97         constant_pool = new ArrayList<>();
98         constant_pool.add(new CpNull());
99         for (int i = 1; i < cpCount; ++i) {
100             constant_pool.add(CpEntry.newCpEntry(in));
101         }
102 
103         access_flags = in.u2();
104         this_class = in.u2();
105         super_class = in.u2();
106 
107         short ifaceCount = in.u2();
108         interfaces = new ArrayList<>();
109         for (int i = 0; i < ifaceCount; ++i) {
110             interfaces.add(new Interface(in));
111         }
112 
113         short fieldCount = in.u2();
114         fields = new ArrayList<>();
115         for (int i = 0; i < fieldCount; ++i) {
116             fields.add(new Field(in));
117         }
118 
119         short methodCount = in.u2();
120         methods = new ArrayList<>();
121         for (int i = 0; i < methodCount; ++i) {
122             methods.add(new Method(in));
123         }
124 
125         short attributeCount = in.u2();
126         attributes = new ArrayList<>();
127         for (int i = 0; i < attributeCount; ++i) {
128             attributes.add(new Attribute(in));
129         }
130     }
131 
toByteArray()132     byte[] toByteArray() {
133         CfOutputStream out = new CfOutputStream();
134 
135         out.u4(magic);
136         out.u2(minor_version);
137         out.u2(major_version);
138 
139         out.u2((short)(constant_pool.size()));
140         for (CpEntry cp : constant_pool) {
141             cp.write(out);
142         }
143 
144         out.u2(access_flags);
145         out.u2(this_class);
146         out.u2(super_class);
147 
148         out.u2((short)interfaces.size());
149         for (Interface iface : interfaces) {
150             iface.write(out);
151         }
152 
153         out.u2((short)fields.size());
154         for (Field field : fields) {
155             field.write(out);
156         }
157 
158         out.u2((short)methods.size());
159         for (Method method : methods) {
160             method.write(out);
161         }
162 
163         out.u2((short)attributes.size());
164         for (Attribute attribute : attributes) {
165             attribute.write(out);
166         }
167 
168         return out.toByteArray();
169     }
170 
171     static abstract class CpEntry {
172         byte tag;
173 
CpEntry(byte t)174         CpEntry(byte t) { tag = t; }
write(CfOutputStream out)175         void write(CfOutputStream out) {
176             out.u1(tag);
177         }
178 
newCpEntry(CfInputStream in)179         static CpEntry newCpEntry(CfInputStream in) {
180             byte tag = in.u1();
181             switch (tag) {
182                 case CpUtf8.TAG: return new CpUtf8(in);
183                 case CpInteger.TAG: return new CpInteger(in);
184                 case CpFloat.TAG: return new CpFloat(in);
185                 case CpLong.TAG: return new CpLong(in);
186                 case CpDouble.TAG: return new CpDouble(in);
187                 case CpClass.TAG: return new CpClass(in);
188                 case CpString.TAG: return new CpString(in);
189                 case CpFieldRef.TAG: return new CpFieldRef(in);
190                 case CpMethodRef.TAG: return new CpMethodRef(in);
191                 case CpInterfaceMethodRef.TAG:
192                     return new CpInterfaceMethodRef(in);
193                 case CpNameAndType.TAG: return new CpNameAndType(in);
194                 case CpMethodHandle.TAG: return new CpMethodHandle(in);
195                 case CpMethodType.TAG: return new CpMethodType(in);
196                 case CpInvokeDynamic.TAG: return new CpInvokeDynamic(in);
197                 default: throw new RuntimeException("Bad cp entry tag: " + tag);
198             }
199         }
200     }
201 
202     static class CpNull extends CpEntry {
CpNull()203         CpNull() { super((byte)0); }
CpNull(CfInputStream in)204         CpNull(CfInputStream in) { super((byte)0); }
write(CfOutputStream out)205         void write(CfOutputStream out) {}
206     }
207 
208     static class CpUtf8 extends CpEntry {
209         static final byte TAG = 1;
210         byte[] bytes;
211 
CpUtf8()212         CpUtf8() { super(TAG); }
CpUtf8(CfInputStream in)213         CpUtf8(CfInputStream in) {
214             this();
215             short length = in.u2();
216             bytes = in.array(length);
217         }
write(CfOutputStream out)218         void write(CfOutputStream out) {
219             super.write(out);
220             out.u2((short)bytes.length);
221             out.array(bytes);
222         }
223     }
224 
225     static class CpU4Constant extends CpEntry {
226         byte[] bytes;
227 
CpU4Constant(byte tag)228         CpU4Constant(byte tag) { super(tag); }
CpU4Constant(byte tag, CfInputStream in)229         CpU4Constant(byte tag, CfInputStream in) {
230             this(tag);
231             bytes = in.array(4);
232         }
write(CfOutputStream out)233         void write(CfOutputStream out) { super.write(out); out.array(bytes); }
234     }
235     static class CpInteger extends CpU4Constant {
236         static final byte TAG = 3;
CpInteger()237         CpInteger() { super(TAG); }
CpInteger(CfInputStream in)238         CpInteger(CfInputStream in) { super(TAG, in); }
239     }
240     static class CpFloat extends CpU4Constant {
241         static final byte TAG = 4;
CpFloat()242         CpFloat() { super(TAG); }
CpFloat(CfInputStream in)243         CpFloat(CfInputStream in) { super(TAG, in); }
244     }
245 
246     static class CpU8Constant extends CpEntry {
247         byte[] bytes;
248 
CpU8Constant(byte tag)249         CpU8Constant(byte tag) { super(tag); }
CpU8Constant(byte tag, CfInputStream in)250         CpU8Constant(byte tag, CfInputStream in) {
251             this(tag);
252             bytes = in.array(8);
253         }
write(CfOutputStream out)254         void write(CfOutputStream out) { super.write(out); out.array(bytes); }
255     }
256     static class CpLong extends CpU8Constant {
257         static final byte TAG = 5;
CpLong()258         CpLong() { super(TAG); }
CpLong(CfInputStream in)259         CpLong(CfInputStream in) { super(TAG, in); }
260     }
261     static class CpDouble extends CpU8Constant {
262         static final byte TAG = 6;
CpDouble()263         CpDouble() { super(TAG); }
CpDouble(CfInputStream in)264         CpDouble(CfInputStream in) { super(TAG, in); }
265     }
266 
267     static class CpClass extends CpEntry {
268         static final byte TAG = 7;
269         short name_index;
270 
CpClass()271         CpClass() { super(TAG); }
CpClass(CfInputStream in)272         CpClass(CfInputStream in) { super(TAG); name_index = in.u2(); }
write(CfOutputStream out)273         void write(CfOutputStream out) {
274             super.write(out);
275             out.u2(name_index);
276         }
277     }
278 
279     static class CpString extends CpEntry {
280         static final byte TAG = 8;
281         short string_index;
282 
CpString()283         CpString() { super(TAG); }
CpString(CfInputStream in)284         CpString(CfInputStream in) { super(TAG); string_index = in.u2(); }
write(CfOutputStream out)285         void write(CfOutputStream out) {
286             super.write(out);
287             out.u2(string_index);
288         }
289     }
290 
291     static class CpRef extends CpEntry {
292         short class_index;
293         short name_and_type_index;
294 
CpRef(byte tag)295         CpRef(byte tag) { super(tag); }
CpRef(byte tag, CfInputStream in)296         CpRef(byte tag, CfInputStream in) {
297             this(tag);
298             class_index = in.u2();
299             name_and_type_index = in.u2();
300         }
write(CfOutputStream out)301         void write(CfOutputStream out) {
302             super.write(out);
303             out.u2(class_index);
304             out.u2(name_and_type_index);
305         }
306     }
307     static class CpFieldRef extends CpRef {
308         static final byte TAG = 9;
CpFieldRef()309         CpFieldRef() { super(TAG); }
CpFieldRef(CfInputStream in)310         CpFieldRef(CfInputStream in) { super(TAG, in); }
311     }
312     static class CpMethodRef extends CpRef {
313         static final byte TAG = 10;
CpMethodRef()314         CpMethodRef() { super(TAG); }
CpMethodRef(CfInputStream in)315         CpMethodRef(CfInputStream in) { super(TAG, in); }
316     }
317     static class CpInterfaceMethodRef extends CpRef {
318         static final byte TAG = 11;
CpInterfaceMethodRef()319         CpInterfaceMethodRef() { super(TAG); }
CpInterfaceMethodRef(CfInputStream in)320         CpInterfaceMethodRef(CfInputStream in) { super(TAG, in); }
321     }
322 
323     static class CpNameAndType extends CpEntry {
324         static final byte TAG = 12;
325         short name_index;
326         short descriptor_index;
327 
CpNameAndType()328         CpNameAndType() { super(TAG); }
CpNameAndType(CfInputStream in)329         CpNameAndType(CfInputStream in) {
330             this();
331             name_index = in.u2();
332             descriptor_index = in.u2();
333         }
write(CfOutputStream out)334         void write(CfOutputStream out) {
335             super.write(out);
336             out.u2(name_index);
337             out.u2(descriptor_index);
338         }
339     }
340 
341     static class CpMethodHandle extends CpEntry {
342         static final byte TAG = 15;
343         byte reference_kind;
344         short reference_index;
345 
CpMethodHandle()346         CpMethodHandle() { super(TAG); }
CpMethodHandle(CfInputStream in)347         CpMethodHandle(CfInputStream in) {
348             this();
349             reference_kind = in.u1();
350             reference_index = in.u2();
351         }
write(CfOutputStream out)352         void write(CfOutputStream out) {
353             super.write(out);
354             out.u1(reference_kind);
355             out.u2(reference_index);
356         }
357     }
358 
359     static class CpMethodType extends CpEntry {
360         static final byte TAG = 16;
361         short descriptor_index;
362 
CpMethodType()363         CpMethodType() { super(TAG); }
CpMethodType(CfInputStream in)364         CpMethodType(CfInputStream in) {
365             this();
366             descriptor_index = in.u2();
367         }
write(CfOutputStream out)368         void write(CfOutputStream out) {
369             super.write(out);
370             out.u2(descriptor_index);
371         }
372     }
373 
374     static class CpInvokeDynamic extends CpEntry {
375         static final byte TAG = 18;
376         short bootstrap_index;
377         short name_and_type_index;
378 
CpInvokeDynamic()379         CpInvokeDynamic() { super(TAG); }
CpInvokeDynamic(CfInputStream in)380         CpInvokeDynamic(CfInputStream in) {
381             this();
382             bootstrap_index = in.u2();
383             name_and_type_index = in.u2();
384         }
write(CfOutputStream out)385         void write(CfOutputStream out) {
386             super.write(out);
387             out.u2(bootstrap_index);
388             out.u2(name_and_type_index);
389         }
390     }
391 
392     static class Interface {
393         short index;
394 
Interface()395         Interface() {}
Interface(CfInputStream in)396         Interface(CfInputStream in) { index = in.u2(); }
write(CfOutputStream out)397         void write(CfOutputStream out) { out.u2(index); }
398     }
399 
400     static class FieldOrMethod {
401         short access_flags;
402         short name_index;
403         short descriptor_index;
404         ArrayList<Attribute> attributes;
405 
FieldOrMethod()406         FieldOrMethod() { attributes = new ArrayList<>(); }
FieldOrMethod(CfInputStream in)407         FieldOrMethod(CfInputStream in) {
408             access_flags = in.u2();
409             name_index = in.u2();
410             descriptor_index = in.u2();
411 
412             short attrCount = in.u2();
413             attributes = new ArrayList<>();
414             for (int i = 0; i < attrCount; ++i) {
415                 attributes.add(new Attribute(in));
416             }
417         }
write(CfOutputStream out)418         void write(CfOutputStream out) {
419             out.u2(access_flags);
420             out.u2(name_index);
421             out.u2(descriptor_index);
422             out.u2((short)attributes.size());
423             for (Attribute attribute : attributes) { attribute.write(out); }
424         }
425     }
426 
427     static class Field extends FieldOrMethod {
Field()428         Field() {}
Field(CfInputStream in)429         Field(CfInputStream in) { super(in); }
430     }
431     static class Method extends FieldOrMethod {
Method()432         Method() {}
Method(CfInputStream in)433         Method(CfInputStream in) { super(in); }
434     }
435 
436     static class Attribute {
437         short attribute_name_index;
438         byte[] info;
439 
Attribute()440         Attribute() { info = new byte[0]; }
Attribute(CfInputStream in)441         Attribute(CfInputStream in) {
442             attribute_name_index = in.u2();
443             int length = in.u4();
444             info = in.array(length);
445         }
write(CfOutputStream out)446         void write(CfOutputStream out) {
447             out.u2(attribute_name_index);
448             out.u4(info.length);
449             out.array(info);
450         }
451     }
452 }
453