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