1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  File-Roller
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, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
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 		char *tmp;
311 
312 		for (i = length; (i >= 0) && (end == 0); i--)
313 			if (package[i] == '/')
314 				end = i;
315 		tmp = g_strndup (package, end);
316 		g_free (package);
317 		package = tmp;
318 	}
319 
320 	java_class_file_free (cfile);
321 
322 	return package;
323 }
324 
325 
326 /* This function consumes a comment from the java file
327  * multiline = TRUE implies that comment is multiline */
328 static void
consume_comment(int fdesc,gboolean multiline)329 consume_comment (int      fdesc,
330 		 gboolean multiline)
331 {
332 	gboolean escaped = FALSE;
333 	gboolean star = FALSE;
334 	char     ch;
335 
336 	while (read (fdesc, &ch, 1) == 1) {
337 		switch (ch) {
338 		case '/':
339 			if (escaped)
340 				break;
341 			else if (star)
342 				return;
343 			break;
344 
345 		case '\n':
346 			if (! multiline)
347 				return;
348 			break;
349 
350 		case '*':
351 			escaped = FALSE;
352 			star = TRUE;
353 			break;
354 
355 		case '\\':
356 			escaped = ! escaped;
357 			break;
358 
359 		default:
360 			escaped = FALSE;
361 			star = FALSE;
362 			break;
363 		}
364 	}
365 }
366 
367 
368 /* This function extracts package name from a java file */
369 char*
get_package_name_from_java_file(char * fname)370 get_package_name_from_java_file (char *fname)
371 {
372 	char          *package = NULL;
373 	JavaClassFile *cfile;
374 	gboolean       prev_char_is_bslash = FALSE;
375 	gboolean       valid_char_found = FALSE;
376 	char           ch;
377 
378 	if (! g_file_test (fname, G_FILE_TEST_EXISTS))
379 		return NULL;
380 
381 	cfile = java_class_file_new ();
382 	cfile->fd = open (fname, O_RDONLY);
383 	if (cfile->fd == -1)
384 		return close_and_exit (cfile);
385 
386 	while (! valid_char_found && (read (cfile->fd, &ch, 1) == 1)) {
387 		switch (ch) {
388 		case '/':
389 			if (prev_char_is_bslash == TRUE) {
390 				consume_comment (cfile->fd, FALSE);
391 				prev_char_is_bslash = FALSE;
392 			}
393 			else
394 				prev_char_is_bslash = TRUE;
395 			break;
396 
397 		case '*':
398 			if (prev_char_is_bslash == TRUE)
399 				consume_comment (cfile->fd, TRUE);
400 			prev_char_is_bslash = FALSE;
401 			break;
402 
403 		case ' ':
404 		case '\t':
405 		case '\r':
406 		case '\n':
407 			prev_char_is_bslash = FALSE;
408 			break;
409 
410 		default:
411 			prev_char_is_bslash = FALSE;
412 			valid_char_found = TRUE;
413 			break;
414 		}
415 	}
416 
417 	if (ch == 'p')	{
418 		char first_valid_word[8] = "";
419 
420 		first_valid_word[0] = 'p';
421 		if (read (cfile->fd, &first_valid_word[1], 6) != 6)
422 			return close_and_exit (cfile);
423 
424 		first_valid_word[7] = 0;
425 		if (g_ascii_strcasecmp (first_valid_word, "package") == 0) {
426 			char buffer[500];
427 			int  index = 0;
428 
429 			while (read (cfile->fd, &ch, 1) == 1) {
430 				if (ch == ';')
431 					break;
432 				if (ch == '.')
433 					buffer[index++] = '/';
434 				else
435 					buffer[index++] = ch;
436 			}
437 			buffer[index] = 0;
438 			package = g_strdup (buffer);
439 		}
440 	}
441 
442 	java_class_file_free (cfile);
443 
444 	return package;
445 }
446