1eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin/**
2eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * Copyright 2006-2017 the original author or authors.
3eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin *
4eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
5eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * you may not use this file except in compliance with the License.
6eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * You may obtain a copy of the License at
7eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin *
8eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin *     http://www.apache.org/licenses/LICENSE-2.0
9eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin *
10eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * Unless required by applicable law or agreed to in writing, software
11eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
12eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * See the License for the specific language governing permissions and
14eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * limitations under the License.
15eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin */
16eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinpackage org.objenesis;
17eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
18eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport java.io.DataInputStream;
19eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport java.io.FileInputStream;
20eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport java.io.IOException;
21eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport java.io.InputStream;
22eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport java.util.Arrays;
23eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
24eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport static org.junit.Assert.*;
25eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport static org.objenesis.instantiator.basic.ClassDefinitionUtils.*;
26eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
27eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin/**
28eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * @author Henri Tremblay
29eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin */
30eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinpublic class ClassReader {
31eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
32eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   byte[] buffer = new byte[256];
33eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   Object[] constant_pool;
34eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
35eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   public static void main(String[] args) throws IOException {
36eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      if(args.length != 1) {
37eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.println("Usage: ClassReader (path_to_the_class_file|class:complete_class_name)");
38eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
39eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
40eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      ClassReader reader = new ClassReader();
41eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      reader.readClass(args[0]);
42eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
43eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
44eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   static class CONSTANT_Utf8_info {
45eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // int length; u2 is read by readUTF
46eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      String bytes;
47eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
48eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      CONSTANT_Utf8_info(DataInputStream in) throws IOException {
49eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         bytes = in.readUTF();
50eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
51eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
52eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
53eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
54eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "CONSTANT_Utf8_info{" +
55eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "bytes='" + bytes + '\'' +
56eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
57eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
58eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
59eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
60eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   static class CONSTANT_Methodref_info {
61eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int class_index; // u2
62eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int name_and_type_index; // u2
63eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
64eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      CONSTANT_Methodref_info(DataInputStream in) throws IOException {
65eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         class_index = in.readUnsignedShort();
66eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         name_and_type_index = in.readUnsignedShort();
67eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
68eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
69eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
70eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
71eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "CONSTANT_Methodref_info{" +
72eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "class_index=" + class_index +
73eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", name_and_type_index=" + name_and_type_index +
74eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
75eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
76eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
77eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
78eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   static class CONSTANT_Class_info {
79eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int name_index; // u2
80eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
81eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public CONSTANT_Class_info(DataInputStream in) throws IOException{
82eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         name_index = in.readUnsignedShort();
83eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
84eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
85eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
86eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
87eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "CONSTANT_Class_info{" +
88eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "name_index=" + name_index +
89eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
90eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
91eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
92eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
93eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   static class CONSTANT_NameAndType_info {
94eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int name_index; // u2
95eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int descriptor_index; // u2
96eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
97eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public CONSTANT_NameAndType_info(DataInputStream in) throws IOException{
98eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         name_index = in.readUnsignedShort();
99eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         descriptor_index = in.readUnsignedShort();
100eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
101eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
102eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
103eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
104eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "CONSTANT_NameAndType_info{" +
105eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "name_index=" + name_index +
106eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", descriptor_index=" + descriptor_index +
107eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
108eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
109eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
110eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
111eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   class method_info {
112eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int access_flags; // u2
113eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int name_index;
114eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int descriptor_index;
115eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int attributes_count;
116eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      attribute_info[] attributes;
117eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
118eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public method_info(DataInputStream in) throws IOException{
119eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         access_flags = in.readUnsignedShort();
120eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         name_index = in.readUnsignedShort();
121eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         descriptor_index = in.readUnsignedShort();
122eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attributes_count = in.readUnsignedShort();
123eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attributes = new attribute_info[attributes_count];
124eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
125eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         for (int i = 0; i < attributes_count; i++) {
126eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            attributes[i] = new attribute_info(in);
127eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
128eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
129eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
130eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
131eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
132eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "method_info{" +
133eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "access_flags=" + access_flags +
134eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", name_index=" + name_index +
135eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", descriptor_index=" + descriptor_index +
136eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", attributes_count=" + attributes_count +
137eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
138eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
139eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
140eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
141eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   class attribute_info {
142eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int attribute_name_index; // u2
143eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int attribute_length; // u4
144eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      Object info;
145eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
146eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public attribute_info(DataInputStream in) throws IOException{
147eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attribute_name_index = in.readUnsignedShort();
148eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attribute_length = in.readInt();
149eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
150eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         String attribute_name = ((CONSTANT_Utf8_info) constant_pool[attribute_name_index]).bytes;
151eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
152eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.println(this +  " " + attribute_name);
153eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
154eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         if("Code".equals(attribute_name)) {
155eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            info = new Code_attribute(in);
156eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
157eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         else if("SourceFile".equals(attribute_name)) {
158eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            assertEquals(2, attribute_length); // always 2
159eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            info = new SourceFile_attribute(in);
160eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
161eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         else if("LineNumberTable".equals(attribute_name)) {
162eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            // I don't care about that (only used for debugging) so I will skip
163eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            System.out.println("Attribute LineNumberTable skipped");
164eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            in.read(buffer, 0, attribute_length);
165eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
166eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         else if("LocalVariableTable".equals(attribute_name)) {
167eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            // I don't care about that (only used for debugging) so I will skip
168eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            System.out.println("Attribute LocalVariableTable skipped");
169eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            in.read(buffer, 0, attribute_length);
170eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
171eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         else {
172eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            fail("Unknown attribute: " + attribute_name);
173eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
174eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
175eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.println("\t" + info);
176eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
177eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
178eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
179eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
180eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "attribute_info{" +
181eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "attribute_name_index=" + attribute_name_index +
182eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", attribute_length=" + attribute_length +
183eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
184eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
185eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
186eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
187eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   class Code_attribute {
188eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int max_stack; // u2
189eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int max_locals; // u2
190eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int code_length; // u4
191eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      byte[] code; // length of code_length
192eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int exception_table_length; // u2 if will be 0, so we will skip the exception_table
193eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int attributes_count; // u2
194eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      attribute_info[] attributes;
195eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
196eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      Code_attribute(DataInputStream in) throws IOException {
197eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         max_stack = in.readUnsignedShort();
198eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         max_locals = in.readUnsignedShort();
199eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         code_length = in.readInt();
200eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         code = new byte[code_length];
201eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         in.read(code);
202eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         exception_table_length = in.readUnsignedShort();
203eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attributes_count = in.readUnsignedShort();
204eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attributes = new attribute_info[attributes_count];
205eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         for (int i = 0; i < attributes_count; i++) {
206eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            attributes[i] = new attribute_info(in);
207eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
208eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
209eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
210eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
211eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
212eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "Code_attribute{" +
213eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "max_stack=" + max_stack +
214eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", max_locals=" + max_locals +
215eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", code_length=" + code_length +
216eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", code=" + Arrays.toString(code) +
217eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", exception_table_length=" + exception_table_length +
218eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            ", attributes_count=" + attributes_count +
219eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
220eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
221eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
222eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
223eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   static class SourceFile_attribute {
224eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int sourcefile_index;
225eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
226eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      SourceFile_attribute(DataInputStream in) throws IOException {
227eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         sourcefile_index = in.readUnsignedShort();
228eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
229eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
230eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
231eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public String toString() {
232eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return "SourceFile_attribute{" +
233eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            "sourcefile_index=" + sourcefile_index +
234eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            '}';
235eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
236eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
237eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
238eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   public void readClass(String classPath) throws IOException {
239eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      InputStream iin;
240eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      if(classPath.startsWith("classpath:")) {
241eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         String className = classPath.substring("classpath:".length());
242eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         String resourceName = classNameToResource(className);
243eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         iin = getClass().getClassLoader().getResourceAsStream(resourceName);
244eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
245eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      else {
246eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         iin = new FileInputStream(classPath);
247eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
248eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
249eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      DataInputStream in = new DataInputStream(iin);
250eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
251eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // magic number
252eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      in.read(buffer, 0, MAGIC.length);
253eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      assertArrayEquals(MAGIC);
254eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
255eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // version
256eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      in.read(buffer, 0, VERSION.length);
257eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      assertArrayEquals(VERSION);
258eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
259eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // constant_pool_count
260eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int constant_pool_count = in.readUnsignedShort();
261eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("Constant pool count: " + constant_pool_count);
262eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
263eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // indexed from 1 (0 will be unused) to constant_pool_count-1
264eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      constant_pool = new Object[constant_pool_count];
265eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
266eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // constant pool
267eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      for (int i = 1; i < constant_pool_count; i++) {
268eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.print(i + ": ");
269eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         int type = in.readUnsignedByte();
270eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         switch(type) {
271eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         case CONSTANT_Utf8:
272eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            constant_pool[i] = new CONSTANT_Utf8_info(in);
273eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            break;
274eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         case CONSTANT_Class:
275eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            constant_pool[i] = new CONSTANT_Class_info(in);
276eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            break;
277eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         case CONSTANT_Methodref:
278eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            constant_pool[i] = new CONSTANT_Methodref_info(in);
279eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            break;
280eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         case CONSTANT_NameAndType:
281eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            constant_pool[i] = new CONSTANT_NameAndType_info(in);
282eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            break;
283eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         default:
284eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            fail("Unknown type: " + type);
285eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
286eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.println(constant_pool[i]);
287eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
288eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
289eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // access flags
290eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int access_flags = in.readUnsignedShort();
291eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("Access flags: " + access_flags); // see http://stackoverflow.com/questions/8949933/what-is-the-purpose-of-the-acc-super-access-flag-on-java-class-files
292eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
293eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // this class name
294eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int this_class = in.readUnsignedShort();
295eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("This class index: " + this_class);
296eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
297eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // super class name
298eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int super_class = in.readUnsignedShort();
299eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("This superclass index: " + super_class);
300eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
301eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // interfaces implemented count (we have none)
302eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int interfaces_count = in.readUnsignedShort();
303eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("Interfaces count: " + interfaces_count);
304eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      for (int i = 0; i < interfaces_count; i++) {
305eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         int index = in.readUnsignedShort();
306eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.println("Interface " + i + " index: " + index);
307eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
308eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
309eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // fields count (we have none)
310eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int fields_count = in.readUnsignedShort();
311eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("Fields count: " + fields_count);
312eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      assertEquals("Reading fields isn't yet supported", 0, fields_count);
313eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
314eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      //methods count (we have one)
315eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int methods_count = in.readUnsignedShort();
316eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("Methods count: " + methods_count);
317eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
318eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      for (int i = 0; i < methods_count; i++) {
319eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         method_info methodInfo = new method_info(in);
320eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         System.out.println("for " + methodInfo);
321eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
322eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
323eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      // reading final class attributes
324eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      int attributes_count = in.readUnsignedShort();
325eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      System.out.println("Class attributes count: " + attributes_count);
326eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      for (int i = 0; i < attributes_count ; i++) {
327eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         attribute_info attributeInfo = new attribute_info(in);
328eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
329eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
330eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      in.close();
331eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
332eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin
333eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   private void assertArrayEquals(byte[] expected) {
334eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      for (int i = 0; i < expected.length; i++) {
335eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         if(expected[i] != buffer[i]) {
336eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin            fail("Expected was " + Arrays.toString(expected) + " but actual is " + Arrays.toString(buffer));
337eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         }
338eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
339eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   }
340eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin}
341