1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Engrampa
5 *
6 * Copyright (C) 2006 The Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02110-1301, USA.
21 */
22
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <glib.h>
28 #include "java-utils.h"
29
30
31 /*
32 * The following code conforms to the JVM specification.(Java 2 Platform)
33 * For further changes to the classfile structure, please update the
34 * following macros.
35 */
36
37
38 /* Tags that identify structures */
39
40 #define CONST_CLASS 7
41 #define CONST_FIELDREF 9
42 #define CONST_METHODREF 10
43 #define CONST_INTERFACEMETHODREF 11
44 #define CONST_STRING 8
45 #define CONST_INTEGER 3
46 #define CONST_FLOAT 4
47 #define CONST_LONG 5
48 #define CONST_DOUBLE 6
49 #define CONST_NAMEANDTYPE 12
50 #define CONST_UTF8 1
51
52 /* Sizes of structures */
53
54 #define CONST_CLASS_INFO 2
55 #define CONST_FIELDREF_INFO 4
56 #define CONST_METHODREF_INFO 4
57 #define CONST_INTERFACEMETHODREF_INFO 4
58 #define CONST_STRING_INFO 2
59 #define CONST_INTEGER_INFO 4
60 #define CONST_FLOAT_INFO 4
61 #define CONST_LONG_INFO 8
62 #define CONST_DOUBLE_INFO 8
63 #define CONST_NAMEANDTYPE_INFO 4
64
65
66 /* represents the utf8 strings in class file */
67 struct utf_string
68 {
69 guint16 index;
70 guint16 length;
71 char *str;
72 };
73
74 /* structure that holds class information in a class file */
75 struct class_info
76 {
77 guint16 index;
78 guint16 name_index; /* index into the utf_strings */
79 };
80
81 typedef struct {
82 int fd;
83
84 guint32 magic_no; /* 0xCAFEBABE (JVM Specification) :) */
85
86 guint16 major; /* versions */
87 guint16 minor;
88
89 guint16 const_pool_count;
90 GSList *const_pool_class; /* (const_pool_count - 1) elements of tye 'CONST_class_info' */
91 GSList *const_pool_utf; /* (const_pool_count - 1) elements of type 'utf_strings' */
92
93 guint16 access_flags;
94 guint16 this_class; /* the index of the class the file is named after. */
95
96 #if 0 /* not needed */
97 guint16 super_class;
98 guint16 interfaces_count;
99 guint16 *interfaces;
100 guint16 fields_count;
101 field_info *fields;
102 guint16 methods_count;
103 method_info *methods;
104 guint16 attributes_count;
105 attribute_info *attributes;
106 #endif
107 } JavaClassFile;
108
109
110 static JavaClassFile*
java_class_file_new(void)111 java_class_file_new (void)
112 {
113 JavaClassFile *cfile;
114
115 cfile = g_new0 (JavaClassFile, 1);
116 cfile->fd = -1;
117
118 return cfile;
119 }
120
121
122 static void
java_class_file_free(JavaClassFile * cfile)123 java_class_file_free (JavaClassFile *cfile)
124 {
125 GSList *scan;
126
127 if (cfile->const_pool_class != NULL) {
128 g_slist_foreach (cfile->const_pool_class, (GFunc)g_free, NULL);
129 g_slist_free (cfile->const_pool_class);
130 }
131
132 for (scan = cfile->const_pool_utf; scan ; scan = scan->next) {
133 struct utf_string *string = scan->data;
134 g_free (string->str);
135 }
136
137 if (cfile->const_pool_utf != NULL) {
138 g_slist_foreach (cfile->const_pool_utf, (GFunc)g_free, NULL);
139 g_slist_free (cfile->const_pool_utf);
140 }
141
142 if (cfile->fd != -1)
143 close (cfile->fd);
144
145 g_free (cfile);
146 }
147
148
149 /* The following function loads the utf8 strings and class structures from the
150 * class file. */
151 static void
load_constant_pool_utfs(JavaClassFile * cfile)152 load_constant_pool_utfs (JavaClassFile *cfile)
153 {
154 guint8 tag;
155 guint16 i = 0; /* should be comparable with const_pool_count */
156
157 while ((i < cfile->const_pool_count - 1) && (read (cfile->fd, &tag, 1) != -1)) {
158 struct utf_string *txt = NULL;
159 struct class_info *class = NULL;
160
161 switch (tag) {
162 case CONST_CLASS:
163 class = g_new0 (struct class_info, 1);
164 class->index = i + 1;
165 if (read (cfile->fd, &class->name_index, 2) != 2) {
166 g_free (class);
167 return; /* error reading */
168 }
169 class->name_index = GUINT16_FROM_BE (class->name_index);
170 cfile->const_pool_class = g_slist_append (cfile->const_pool_class, class);
171 break;
172
173 case CONST_FIELDREF:
174 lseek (cfile->fd, CONST_FIELDREF_INFO, SEEK_CUR);
175 break;
176
177 case CONST_METHODREF:
178 lseek (cfile->fd, CONST_METHODREF_INFO, SEEK_CUR);
179 break;
180
181 case CONST_INTERFACEMETHODREF:
182 lseek (cfile->fd, CONST_INTERFACEMETHODREF_INFO, SEEK_CUR);
183 break;
184
185 case CONST_STRING:
186 lseek (cfile->fd, CONST_STRING_INFO, SEEK_CUR);
187 break;
188
189 case CONST_INTEGER:
190 lseek (cfile->fd, CONST_INTEGER_INFO, SEEK_CUR);
191 break;
192
193 case CONST_FLOAT:
194 lseek (cfile->fd, CONST_FLOAT_INFO, SEEK_CUR);
195 break;
196
197 case CONST_LONG:
198 lseek (cfile->fd, CONST_LONG_INFO, SEEK_CUR);
199 break;
200
201 case CONST_DOUBLE:
202 lseek (cfile->fd, CONST_DOUBLE_INFO, SEEK_CUR);
203 break;
204
205 case CONST_NAMEANDTYPE:
206 lseek (cfile->fd, CONST_NAMEANDTYPE_INFO, SEEK_CUR);
207 break;
208
209 case CONST_UTF8:
210 txt = g_new0 (struct utf_string, 1);
211 txt->index = i + 1;
212 if (read (cfile->fd, &(txt->length), 2) == -1) {
213 g_free (txt);
214 return; /* error while reading */
215 }
216 txt->length = GUINT16_FROM_BE (txt->length);
217 txt->str = g_new0 (char, txt->length);
218 if (read (cfile->fd, txt->str, txt->length) == -1) {
219 g_free (txt);
220 return; /* error while reading */
221 }
222 cfile->const_pool_utf = g_slist_append (cfile->const_pool_utf, txt);
223 break;
224
225 default:
226 return; /* error - unknown tag in class file */
227 break;
228 }
229 i++;
230 }
231
232 #ifdef DEBUG
233 g_print( "Number of Entries: %d\n", i );
234 #endif
235 }
236
237
238 static char*
close_and_exit(JavaClassFile * cfile)239 close_and_exit (JavaClassFile *cfile)
240 {
241 java_class_file_free (cfile);
242 return NULL;
243 }
244
245
246 /* This function extracts the package name from a class file */
247 char*
get_package_name_from_class_file(char * fname)248 get_package_name_from_class_file (char *fname)
249 {
250 char *package = NULL;
251 JavaClassFile *cfile;
252 guint16 length = 0, end = 0, utf_index = 0;
253 guint32 magic;
254 guint16 major, minor, count;
255 int i = 0;
256
257 if (! g_file_test (fname, G_FILE_TEST_EXISTS))
258 return NULL;
259
260 cfile = java_class_file_new ();
261 cfile->fd = open (fname, O_RDONLY);
262 if (cfile->fd == -1)
263 return close_and_exit (cfile);
264
265 if ((i = read (cfile->fd, &magic, 4)) != 4)
266 return close_and_exit (cfile);
267 cfile->magic_no = GUINT32_FROM_BE (magic);
268
269 if (read (cfile->fd, &major, 2 ) != 2)
270 return close_and_exit (cfile);
271 cfile->major = GUINT16_FROM_BE (major);
272
273 if (read (cfile->fd, &minor, 2) != 2)
274 return close_and_exit (cfile);
275 cfile->minor = GUINT16_FROM_BE (minor);
276
277 if (read (cfile->fd, &count, 2) != 2)
278 return close_and_exit (cfile);
279 cfile->const_pool_count = GUINT16_FROM_BE(count);
280 load_constant_pool_utfs (cfile);
281
282 if (read (cfile->fd, &cfile->access_flags, 2) != 2)
283 return close_and_exit (cfile);
284 cfile->access_flags = GUINT16_FROM_BE (cfile->access_flags);
285
286 if (read (cfile->fd, &cfile->this_class, 2) != 2)
287 return close_and_exit (cfile);
288 cfile->this_class = GUINT16_FROM_BE(cfile->this_class);
289
290 /* now search for the class structure with index = cfile->this_class */
291
292 for (i = 0; (i < g_slist_length (cfile->const_pool_class)) && (utf_index == 0); i++ ) {
293 struct class_info *class = g_slist_nth_data (cfile->const_pool_class, i);
294 if (class->index == cfile->this_class)
295 utf_index = class->name_index; /* terminates loop */
296 }
297
298 /* now search for the utf8 string with index = utf_index */
299
300 for (i = 0; i < g_slist_length (cfile->const_pool_utf); i++) {
301 struct utf_string *data = g_slist_nth_data (cfile->const_pool_utf, i);
302 if (data->index == utf_index) {
303 package = g_strndup (data->str, data->length);
304 length = data->length;
305 break;
306 }
307 }
308
309 if (package != NULL) {
310 for (i = length; (i >= 0) && (end == 0); i-- )
311 if (package[i] == '/')
312 end = i;
313 char *package_padded = g_strndup (package, end);
314 g_free(package);
315 package = package_padded;
316 }
317
318 java_class_file_free (cfile);
319
320 return package;
321 }
322
323
324 /* This function consumes a comment from the java file
325 * multiline = TRUE implies that comment is multiline */
326 static void
consume_comment(int fdesc,gboolean multiline)327 consume_comment (int fdesc,
328 gboolean multiline)
329 {
330 gboolean escaped = FALSE;
331 gboolean star = FALSE;
332 char ch;
333
334 while (read (fdesc, &ch, 1) == 1) {
335 switch (ch) {
336 case '/':
337 if (escaped)
338 break;
339 else if (star)
340 return;
341 break;
342
343 case '\n':
344 if (! multiline)
345 return;
346 break;
347
348 case '*':
349 escaped = FALSE;
350 star = TRUE;
351 break;
352
353 case '\\':
354 escaped = ! escaped;
355 break;
356
357 default:
358 escaped = FALSE;
359 star = FALSE;
360 break;
361 }
362 }
363 }
364
365
366 /* This function extracts package name from a java file */
367 char*
get_package_name_from_java_file(char * fname)368 get_package_name_from_java_file (char *fname)
369 {
370 char *package = NULL;
371 JavaClassFile *cfile;
372 gboolean prev_char_is_bslash = FALSE;
373 gboolean valid_char_found = FALSE;
374 char ch;
375
376 if (! g_file_test (fname, G_FILE_TEST_EXISTS))
377 return NULL;
378
379 cfile = java_class_file_new ();
380 cfile->fd = open (fname, O_RDONLY);
381 if (cfile->fd == -1)
382 return close_and_exit (cfile);
383
384 while (! valid_char_found && (read (cfile->fd, &ch, 1) == 1)) {
385 switch (ch) {
386 case '/':
387 if (prev_char_is_bslash == TRUE) {
388 consume_comment (cfile->fd, FALSE);
389 prev_char_is_bslash = FALSE;
390 }
391 else
392 prev_char_is_bslash = TRUE;
393 break;
394
395 case '*':
396 if (prev_char_is_bslash == TRUE)
397 consume_comment (cfile->fd, TRUE);
398 prev_char_is_bslash = FALSE;
399 break;
400
401 case ' ':
402 case '\t':
403 case '\r':
404 case '\n':
405 prev_char_is_bslash = FALSE;
406 break;
407
408 default:
409 prev_char_is_bslash = FALSE;
410 valid_char_found = TRUE;
411 break;
412 }
413 }
414
415 if (ch == 'p') {
416 char first_valid_word[8] = "";
417
418 first_valid_word[0] = 'p';
419 if (read (cfile->fd, &first_valid_word[1], 6) != 6)
420 return close_and_exit (cfile);
421
422 first_valid_word[7] = 0;
423 if (g_ascii_strcasecmp (first_valid_word, "package") == 0) {
424 char buffer[500];
425 int index = 0;
426
427 while (read (cfile->fd, &ch, 1) == 1) {
428 if (ch == ';')
429 break;
430 if (ch == '.')
431 buffer[index++] = '/';
432 else
433 buffer[index++] = ch;
434 }
435 buffer[index] = 0;
436 package = g_strdup (buffer);
437 }
438 }
439
440 java_class_file_free (cfile);
441
442 return package;
443 }
444