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