1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 1998 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with GNU CC; see the file COPYING. If not, write to
16 the Free Software Foundation, 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
19 Java and all Java-based marks are trademarks or registered trademarks
20 of Sun Microsystems, Inc. in the United States and other countries.
21 The Free Software Foundation is independent of Sun Microsystems, Inc. */
23 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
32 /* DOS brain-damage */
34 #define O_BINARY 0 /* MS-DOS brain-damage */
38 DEFUN(jcf_unexpected_eof, (jcf, count),
39 JCF *jcf AND int count)
42 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
44 fprintf (stderr, "Premature end of .class file <stdin>.\n");
49 DEFUN(jcf_trim_old_input, (jcf),
52 int count = jcf->read_ptr - jcf->buffer;
55 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
56 jcf->read_ptr -= count;
57 jcf->read_end -= count;
62 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
63 JCF *jcf AND int count)
65 FILE *file = (FILE*) (jcf->read_state);
66 if (count > jcf->buffer_end - jcf->read_ptr)
68 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
69 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
70 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
71 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
72 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
73 : REALLOC (jcf->buffer, new_size);
74 jcf->buffer = new_buffer;
75 jcf->buffer_end = new_buffer + new_size;
76 jcf->read_ptr = new_buffer + old_read_ptr;
77 jcf->read_end = new_buffer + old_read_end;
79 count -= jcf->read_end - jcf->read_ptr;
82 if (fread (jcf->read_end, 1, count, file) != count)
83 jcf_unexpected_eof (jcf, count);
84 jcf->read_end += count;
90 struct ZipFileCache *SeenZipFiles = NULL;
93 DEFUN(open_in_zip, (jcf, zipfile, zipmember),
94 JCF *jcf AND const char *zipfile AND const char *zipmember
97 struct ZipFileCache* zipf;
100 for (zipf = SeenZipFiles; ; zipf = zipf->next)
105 int fd = open (zipfile, O_RDONLY | O_BINARY);
106 jcf_dependency_add_file (zipfile, is_system);
107 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
109 lseek (fd, 0L, SEEK_SET);
110 zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
111 zipf->next = SeenZipFiles;
112 zipf->name = (char*)(zipf+1);
113 strcpy (zipf->name, zipfile);
118 /* A missing zip file is not considered an error. */
120 zipf->z.dir_size = 0;
121 zipf->z.central_directory = NULL;
126 if (read_zip_archive (&zipf->z) != 0)
127 return -2; /* This however should be an error - FIXME */
131 if (strcmp (zipf->name, zipfile) == 0)
138 len = strlen (zipmember);
140 zipd = (struct ZipDirectory*) zipf->z.central_directory;
141 for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd))
143 if (len == zipd->filename_length &&
144 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
147 jcf->buffer = ALLOC (zipd->size);
148 jcf->buffer_end = jcf->buffer + zipd->size;
149 jcf->read_ptr = jcf->buffer;
150 jcf->read_end = jcf->buffer_end;
151 jcf->filbuf = jcf_unexpected_eof;
152 jcf->filename = strdup (zipfile);
153 jcf->classname = strdup (zipmember);
154 jcf->zipd = (void *)zipd;
155 if (lseek (zipf->z.fd, zipd->filestart, 0) < 0
156 || read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size)
166 DEFUN(open_class, (filename, jcf, stream, dep_name),
167 char *filename AND JCF *jcf AND FILE* stream AND char *dep_name)
171 if (dep_name != NULL)
172 jcf_dependency_add_file (dep_name, 0);
175 jcf->buffer_end = NULL;
176 jcf->read_ptr = NULL;
177 jcf->read_end = NULL;
178 jcf->read_state = stream;
179 jcf->filbuf = jcf_filbuf_from_stdio;
187 DEFUN(open_class, (filename, jcf, fd, dep_name),
188 char *filename AND JCF *jcf AND int fd AND char *dep_name)
192 struct stat stat_buf;
193 if (fstat (fd, &stat_buf) != 0
194 || ! S_ISREG (stat_buf.st_mode))
196 perror ("Could not figure length of .class file");
199 if (dep_name != NULL)
200 jcf_dependency_add_file (dep_name, 0);
202 jcf->buffer = ALLOC (stat_buf.st_size);
203 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
204 jcf->read_ptr = jcf->buffer;
205 jcf->read_end = jcf->buffer_end;
206 jcf->read_state = NULL;
207 jcf->filename = filename;
208 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
210 perror ("Failed to read .class file");
214 jcf->filbuf = jcf_unexpected_eof;
224 DEFUN(find_classfile, (filename, jcf, dep_name),
225 char *filename AND JCF *jcf AND char *dep_name)
228 FILE *stream = fopen (filename, "rb");
231 return open_class (arg, jcf, stream, dep_name);
233 int fd = open (filename, O_RDONLY | O_BINARY);
236 return open_class (filename, jcf, fd, dep_name);
240 /* Returns a freshly malloc'd string with the fully qualified pathname
241 of the .class file for the class CLASSNAME. Returns NULL on
242 failure. If JCF != NULL, it is suitably initialized. With
243 DO_CLASS_FILE set to 1, search a .class/.java file named after
244 CLASSNAME, otherwise, search a ZIP directory entry named after
248 DEFUN(find_class, (classname, classname_length, jcf, do_class_file),
249 const char *classname AND int classname_length AND JCF *jcf AND int do_class_file)
257 int i, k, java, class;
258 struct stat java_buf, class_buf;
260 void *entry, *java_entry;
263 /* Allocate and zero out the buffer, since we don't explicitly put a
264 null pointer when we're copying it below. */
265 int buflen = jcf_path_max_len () + classname_length + 10;
266 char *buffer = (char *) ALLOC (buflen);
267 bzero (buffer, buflen);
269 java_buffer = (char *) alloca (buflen);
271 jcf->java_source = jcf->outofsynch = 0;
273 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
277 strcpy (buffer, jcf_path_name (entry));
282 for (k = 0; k < classname_length; k++, i++)
284 char ch = classname[k];
285 buffer[i] = ch == '.' ? '/' : ch;
288 strcpy (buffer+i, ".class");
290 if (jcf_path_is_zipfile (entry))
295 strcpy (buffer+i, "/");
296 buffer[dir_len] = '\0';
298 SOURCE_FRONTEND_DEBUG
299 (("Trying [...%s]:%s",
300 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
304 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
305 jcf_path_is_system (entry));
309 jcf->seen_in_zip = 1;
312 buffer[dir_len] = '(';
313 strcpy (buffer+i, ".class)");
323 /* If we do directories, do them here */
326 struct stat dir_buff;
328 buffer[i] = '\0'; /* Was previously unterminated here. */
329 if (!(dir = stat (buffer, &dir_buff)))
331 jcf->seen_in_zip = 0;
336 class = stat (buffer, &class_buf);
337 /* This is a little odd: if we didn't find the class file, we
338 can just skip to the next iteration. However, if this is the
339 last iteration, then we want to search for the .java file as
340 well. It was a little easier to implement this with two
341 loops, as opposed to checking for each type of file each time
343 if (class && jcf_path_next (entry))
346 /* Check for out of synch .class/.java files. */
348 for (java_entry = jcf_path_start ();
349 java && java_entry != NULL;
350 java_entry = jcf_path_next (java_entry))
353 extern int saw_java_source; /* FIXME: temporary. */
355 if (jcf_path_is_zipfile (java_entry))
358 /* Compute name of .java file. */
359 strcpy (java_buffer, jcf_path_name (java_entry));
360 l = strlen (java_buffer);
361 for (m = 0; m < classname_length; ++m)
363 java_buffer[m + l] = (classname[m] == '.'
367 strcpy (java_buffer + m + l, ".java");
369 /* FIXME: until the `.java' parser is fully working, we only
370 look for a .java file when one was mentioned on the
371 command line. This lets us test the .java parser fairly
372 easily, without compromising our ability to use the
373 .class parser without fear. */
375 java = stat (java_buffer, &java_buf);
378 if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
382 dep_file = java_buffer;
388 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
389 stream = fopen (buffer, "rb");
393 /* Give .java a try, if necessary */
396 strcpy (buffer, java_buffer);
397 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
398 stream = fopen (buffer, "r");
401 jcf->java_source = 1;
408 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
409 fd = open (buffer, O_RDONLY | O_BINARY);
413 /* Give .java a try, if necessary */
416 strcpy (buffer, java_buffer);
417 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
418 fd = open (buffer, O_RDONLY);
421 jcf->java_source = 1;
431 if (jcf->java_source)
432 return NULL; /* FIXME */
434 return open_class (buffer, jcf, stream, dep_file);
436 if (jcf->java_source)
438 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
439 jcf->java_source = 1;
440 jcf->filename = (char *) strdup (buffer);
441 close (fd); /* We use STDIO for source file */
443 else if (do_class_file)
444 buffer = open_class (buffer, jcf, fd, dep_file);
445 jcf->classname = (char *) ALLOC (classname_length + 1);
446 strncpy (jcf->classname, classname, classname_length + 1);
447 jcf->classname = (char *) strdup (classname);
453 DEFUN(jcf_print_char, (stream, ch),
454 FILE *stream AND int ch)
461 fprintf (stream, "\\%c", ch);
464 fprintf (stream, "\\n");
467 fprintf (stream, "\\t");
470 fprintf (stream, "\\r");
473 if (ch >= ' ' && ch < 127)
476 fprintf (stream, "\\%03x", ch);
478 fprintf (stream, "\\u%04x", ch);
482 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
485 DEFUN(jcf_print_utf8, (stream, str, length),
486 FILE *stream AND register unsigned char *str AND int length)
488 unsigned char* limit = str + length;
491 int ch = UTF8_GET (str, limit);
494 fprintf (stream, "\\<invalid>");
497 jcf_print_char (stream, ch);
501 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
504 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
505 FILE *stream AND unsigned char *str AND int length
506 AND int in_char AND int out_char)
509 int i;/* FIXME - actually handle Unicode! */
510 for (i = 0; i < length; i++)
513 jcf_print_char (stream, ch == in_char ? out_char : ch);
517 /* Check that all the cross-references in the constant pool are
518 valid. Returns 0 on success.
519 Otherwise, returns the index of the (first) invalid entry. */
522 DEFUN(verify_constant_pool, (jcf),
526 for (i = 1; i < JPOOL_SIZE (jcf); i++)
528 switch (JPOOL_TAG (jcf, i))
530 case CONSTANT_NameAndType:
531 n = JPOOL_USHORT2 (jcf, i);
532 if (n <= 0 || n >= JPOOL_SIZE(jcf)
533 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
535 /* ... fall through ... */
537 case CONSTANT_String:
538 n = JPOOL_USHORT1 (jcf, i);
539 if (n <= 0 || n >= JPOOL_SIZE(jcf)
540 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
543 case CONSTANT_Fieldref:
544 case CONSTANT_Methodref:
545 case CONSTANT_InterfaceMethodref:
546 n = JPOOL_USHORT1 (jcf, i);
547 if (n <= 0 || n >= JPOOL_SIZE(jcf)
548 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
550 n = JPOOL_USHORT2 (jcf, i);
551 if (n <= 0 || n >= JPOOL_SIZE(jcf)
552 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
556 case CONSTANT_Double:
560 case CONSTANT_Integer:
562 case CONSTANT_Unicode:
572 DEFUN(format_uint, (buffer, value, base),
573 char *buffer AND uint64 value AND int base)
575 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
576 char buf[WRITE_BUF_SIZE];
577 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
581 /* Now do the actual conversion, placing the result at the *end* of buf. */
582 /* Note this code does not pretend to be optimized. */
584 int digit = value % base;
585 static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
586 *--buf_ptr = digit_chars[digit];
588 } while (value != 0);
590 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
591 for (i = 0; i < chars_written; i++)
592 buffer[i] = *buf_ptr++;
597 DEFUN(format_int, (buffer, value, base),
598 char *buffer AND jlong value AND int base)
603 abs_value = -(uint64)value;
607 abs_value = (uint64) value;
608 format_uint (buffer, abs_value, base);