1
+ /**
2
+ * A program to output the contents of constant_pool
3
+ * by parsing java .class files as that's made in javap tool.
4
+ *
5
+ * This code is written as an assignment to understand
6
+ * the structure of the class files.
7
+ *
8
+ * Author: Aleksandr Ushaev
9
+ * Created: 14.02.2020
10
+ *
11
+ */
12
+
13
+ #include "class_reader.h"
14
+
15
+ /**
16
+ * Attempts to open a file, on success checks
17
+ * if the file is a valid .class file.
18
+ *
19
+ * @param path of the file to open
20
+ * @return file if it is valid .class file
21
+ */
22
+ FILE * open_class_file (char * path )
23
+ {
24
+ FILE * file = fopen (path , "rb" );
25
+
26
+ if (!file )
27
+ {
28
+ perror ("Error " );
29
+ exit (EXIT_FAILURE );
30
+ }
31
+
32
+ if (!is_class_file (file ))
33
+ {
34
+ fprintf (stderr , "This file is not a .class file!\n" );
35
+ exit (0 );
36
+ }
37
+
38
+ return file ;
39
+ }
40
+
41
+ /**
42
+ * Checks the file for a magic value 0xcafebabe
43
+ *
44
+ * @param file to check
45
+ * @return true if file contatins magic value
46
+ */
47
+ bool is_class_file (FILE * file )
48
+ {
49
+ uint32_t magic_number ;
50
+ size_t read_cnt = fread (& magic_number , sizeof (uint32_t ), 1 , file );
51
+ magic_number = be32toh (magic_number );
52
+ return read_cnt == 1 && magic_number == MAGIC_NUMBER ;
53
+ }
54
+
55
+ /**
56
+ * Reads minor, major versions, constant pool size
57
+ * and constant pool from a file
58
+ *
59
+ * @param file to read from
60
+ * @return class struct filled with collected data
61
+ */
62
+ class * parse_class_file (FILE * class_file )
63
+ {
64
+ class * cls = (class * )malloc (sizeof (class ));
65
+
66
+ // Read header
67
+ parse_u2 (class_file , & cls -> minor_version );
68
+ parse_u2 (class_file , & cls -> major_version );
69
+ parse_u2 (class_file , & cls -> constant_pool_count );
70
+
71
+ parse_constant_pool (class_file , cls );
72
+ fclose (class_file );
73
+ return cls ;
74
+ }
75
+
76
+ /**
77
+ * Reads an "unsigned two-byte quantity" from a file
78
+ *
79
+ * @param file to read from
80
+ * @param variable to write
81
+ */
82
+ void parse_u2 (FILE * class_file , uint16_t * cls )
83
+ {
84
+ fread (cls , sizeof (uint16_t ), 1 , class_file );
85
+ (* cls ) = be16toh ((* cls ));
86
+ }
87
+
88
+ /**
89
+ * Parse symbolic information from the "constant_pool" table
90
+ * from a file
91
+ *
92
+ * @param file to read from
93
+ * @param class struct to write
94
+ */
95
+ void parse_constant_pool (FILE * class_file , class * cls )
96
+ {
97
+ const uint16_t total_constants_count = cls -> constant_pool_count - 1 ;
98
+ cls -> constant_pool = malloc (total_constants_count * sizeof (constant_info ));
99
+ uint8_t tag ;
100
+
101
+ CONSTANT_Class_info class_info ;
102
+ CONSTANT_Ref_info ref_info ;
103
+ CONSTANT_String_info string_info ;
104
+ CONSTANT_IntFloat_info int_float_info ;
105
+ CONSTANT_LongDouble_info long_double_info ;
106
+ CONSTANT_Utf8_info utf_info ;
107
+ CONSTANT_MethodHandle_info method_handle_info ;
108
+ CONSTANT_MethodType_info method_type_info ;
109
+ CONSTANT_InvokeDynamic_info invoke_info ;
110
+
111
+ for (int i = 1 ; i <= total_constants_count ; i ++ )
112
+ {
113
+ constant_info * cur_constant_info = cls -> constant_pool + (i - 1 );
114
+ fread (& tag , sizeof (uint8_t ), 1 , class_file );
115
+
116
+ switch (tag )
117
+ {
118
+ case CONSTANT_Class :
119
+ fread (& class_info .name_index , sizeof (class_info .name_index ), 1 , class_file );
120
+ class_info .tag = tag ;
121
+ class_info .name_index = be16toh (class_info .name_index );
122
+ cur_constant_info -> class_i = class_info ;
123
+ break ;
124
+
125
+ case CONSTANT_Fieldref :
126
+ case CONSTANT_InterfaceMethodref :
127
+ case CONSTANT_Methodref :
128
+ case CONSTANT_NameAndType :
129
+ fread (& ref_info .class_index , sizeof (ref_info .class_index ), 1 , class_file );
130
+ fread (& ref_info .name_and_type_index , sizeof (ref_info .name_and_type_index ), 1 , class_file );
131
+ ref_info .tag = tag ;
132
+ ref_info .class_index = be16toh (ref_info .class_index );
133
+ ref_info .name_and_type_index = be16toh (ref_info .name_and_type_index );
134
+ cur_constant_info -> ref_i = ref_info ;
135
+ break ;
136
+
137
+ case CONSTANT_String :
138
+ fread (& string_info .string_index , sizeof (string_info .string_index ), 1 , class_file );
139
+ string_info .tag = tag ;
140
+ string_info .string_index = be16toh (string_info .string_index );
141
+ cur_constant_info -> string_i = string_info ;
142
+ break ;
143
+
144
+ case CONSTANT_Integer :
145
+ case CONSTANT_Float :
146
+ fread (& int_float_info .bytes , sizeof (int_float_info .bytes ), 1 , class_file );
147
+ int_float_info .tag = tag ;
148
+ int_float_info .bytes = be32toh (int_float_info .bytes );
149
+ cur_constant_info -> int_float_i = int_float_info ;
150
+ break ;
151
+
152
+ case CONSTANT_Long :
153
+ case CONSTANT_Double :
154
+ fread (& long_double_info .high_bytes , sizeof (long_double_info .high_bytes ), 1 , class_file );
155
+ fread (& long_double_info .low_bytes , sizeof (long_double_info .low_bytes ), 1 , class_file );
156
+ long_double_info .tag = tag ;
157
+ long_double_info .high_bytes = be32toh (long_double_info .high_bytes );
158
+ long_double_info .low_bytes = be32toh (long_double_info .low_bytes );
159
+ cur_constant_info -> long_double_i = long_double_info ;
160
+ i ++ ; // Takes two entries
161
+ break ;
162
+
163
+ case CONSTANT_Utf8 :
164
+ fread (& utf_info .length , sizeof (utf_info .length ), 1 , class_file );
165
+ utf_info .length = be16toh (utf_info .length );
166
+ utf_info .bytes = malloc (sizeof (char ) * (utf_info .length + 1 ));
167
+ fread (utf_info .bytes , sizeof (char ), utf_info .length , class_file );
168
+ utf_info .bytes [utf_info .length ] = '0円' ;
169
+ utf_info .tag = tag ;
170
+ cur_constant_info -> utf_i = utf_info ;
171
+ break ;
172
+
173
+ case CONSTANT_MethodHandle :
174
+ fread (& method_handle_info .reference_kind , sizeof (method_handle_info .reference_kind ), 1 , class_file );
175
+ fread (& method_handle_info .reference_index , sizeof (method_handle_info .reference_index ), 1 , class_file );
176
+ method_handle_info .reference_index = be16toh (method_handle_info .reference_index );
177
+ method_handle_info .tag = tag ;
178
+ cur_constant_info -> method_handle_i = method_handle_info ;
179
+ break ;
180
+
181
+ case CONSTANT_MethodType :
182
+ fread (& method_type_info .descriptor_index , sizeof (method_type_info .descriptor_index ), 1 , class_file );
183
+ method_type_info .descriptor_index = be16toh (method_type_info .descriptor_index );
184
+ method_type_info .tag = tag ;
185
+ cur_constant_info -> method_type_i = method_type_info ;
186
+ break ;
187
+
188
+ case CONSTANT_InvokeDynamic :
189
+ fread (& invoke_info .bootstrap_method_attr_index , sizeof (invoke_info .bootstrap_method_attr_index ), 1 , class_file );
190
+ fread (& invoke_info .name_and_type_index , sizeof (invoke_info .name_and_type_index ), 1 , class_file );
191
+ invoke_info .bootstrap_method_attr_index = be16toh (invoke_info .bootstrap_method_attr_index );
192
+ invoke_info .name_and_type_index = be16toh (invoke_info .name_and_type_index );
193
+ invoke_info .tag = tag ;
194
+ cur_constant_info -> invoke_dynamic_i = invoke_info ;
195
+ break ;
196
+
197
+ default :
198
+ fprintf (stderr , "Don't know what to do with %d tag byte :(\n" , tag );
199
+ cur_constant_info = NULL ;
200
+ break ;
201
+ }
202
+ }
203
+ }
0 commit comments