1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 97-98, 1999, 2000 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. */
31 #include "java-tree.h"
33 /* DOS brain-damage */
35 #define O_BINARY 0 /* MS-DOS brain-damage */
39 DEFUN(jcf_unexpected_eof, (jcf, count),
40 JCF *jcf AND int count ATTRIBUTE_UNUSED)
43 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
45 fprintf (stderr, "Premature end of .class file <stdin>.\n");
50 DEFUN(jcf_trim_old_input, (jcf),
53 int count = jcf->read_ptr - jcf->buffer;
56 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
57 jcf->read_ptr -= count;
58 jcf->read_end -= count;
63 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
64 JCF *jcf AND int count)
66 FILE *file = (FILE*) (jcf->read_state);
67 if (count > jcf->buffer_end - jcf->read_ptr)
69 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
70 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
71 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
72 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
73 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
74 : REALLOC (jcf->buffer, new_size);
75 jcf->buffer = new_buffer;
76 jcf->buffer_end = new_buffer + new_size;
77 jcf->read_ptr = new_buffer + old_read_ptr;
78 jcf->read_end = new_buffer + old_read_end;
80 count -= jcf->read_end - jcf->read_ptr;
83 if ((int) fread (jcf->read_end, 1, count, file) != count)
84 jcf_unexpected_eof (jcf, count);
85 jcf->read_end += count;
91 struct ZipFileCache *SeenZipFiles = NULL;
93 /* Open a zip file with the given name, and cache directory and file
94 descriptor. If the file is missing, treat it as an empty archive.
95 Return NULL if the .zip file is malformed.
99 DEFUN(opendir_in_zip, (zipfile, is_system),
100 const char *zipfile AND int is_system)
102 struct ZipFileCache* zipf;
105 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
107 if (strcmp (zipf->name, zipfile) == 0)
111 zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
112 zipf->next = SeenZipFiles;
113 zipf->name = (char*)(zipf+1);
114 strcpy (zipf->name, zipfile);
116 fd = open (zipfile, O_RDONLY | O_BINARY);
120 /* A missing zip file is not considered an error.
121 We may want to re-consider that. FIXME. */
123 zipf->z.dir_size = 0;
124 zipf->z.central_directory = NULL;
128 jcf_dependency_add_file (zipfile, is_system);
129 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
131 lseek (fd, 0L, SEEK_SET);
132 if (read_zip_archive (&zipf->z) != 0)
139 0: OK - zipmember found.
141 -2: Malformed archive.
145 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
146 JCF *jcf AND const char *zipfile AND const char *zipmember
151 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
159 len = strlen (zipmember);
161 zipd = (struct ZipDirectory*) zipf->central_directory;
162 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
164 if (len == zipd->filename_length &&
165 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
168 jcf->buffer = ALLOC (zipd->size);
169 jcf->buffer_end = jcf->buffer + zipd->size;
170 jcf->read_ptr = jcf->buffer;
171 jcf->read_end = jcf->buffer_end;
172 jcf->filbuf = jcf_unexpected_eof;
173 jcf->filename = xstrdup (zipfile);
174 jcf->classname = xstrdup (zipmember);
175 jcf->zipd = (void *)zipd;
176 if (lseek (zipf->fd, zipd->filestart, 0) < 0
177 || read (zipf->fd, jcf->buffer, zipd->size) != zipd->size)
187 DEFUN(open_class, (filename, jcf, stream, dep_name),
188 char *filename AND JCF *jcf AND FILE* stream AND const char *dep_name)
192 if (dep_name != NULL)
193 jcf_dependency_add_file (dep_name, 0);
196 jcf->buffer_end = NULL;
197 jcf->read_ptr = NULL;
198 jcf->read_end = NULL;
199 jcf->read_state = stream;
200 jcf->filbuf = jcf_filbuf_from_stdio;
208 DEFUN(open_class, (filename, jcf, fd, dep_name),
209 char *filename AND JCF *jcf AND int fd AND const char *dep_name)
213 struct stat stat_buf;
214 if (fstat (fd, &stat_buf) != 0
215 || ! S_ISREG (stat_buf.st_mode))
217 perror ("Could not figure length of .class file");
220 if (dep_name != NULL)
221 jcf_dependency_add_file (dep_name, 0);
223 jcf->buffer = ALLOC (stat_buf.st_size);
224 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
225 jcf->read_ptr = jcf->buffer;
226 jcf->read_end = jcf->buffer_end;
227 jcf->read_state = NULL;
228 jcf->filename = filename;
229 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
231 perror ("Failed to read .class file");
235 jcf->filbuf = jcf_unexpected_eof;
245 DEFUN(find_classfile, (filename, jcf, dep_name),
246 char *filename AND JCF *jcf AND const char *dep_name)
249 FILE *stream = fopen (filename, "rb");
252 return open_class (arg, jcf, stream, dep_name);
254 int fd = open (filename, O_RDONLY | O_BINARY);
257 return open_class (filename, jcf, fd, dep_name);
261 /* Returns a freshly malloc'd string with the fully qualified pathname
262 of the .class file for the class CLASSNAME. Returns NULL on
263 failure. If JCF != NULL, it is suitably initialized.
264 SOURCE_OK is true if we should also look for .java file. */
267 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
268 const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
276 int i, k, java = -1, class = -1;
277 struct stat java_buf, class_buf;
282 /* Allocate and zero out the buffer, since we don't explicitly put a
283 null pointer when we're copying it below. */
284 int buflen = jcf_path_max_len () + classname_length + 10;
285 char *buffer = (char *) ALLOC (buflen);
286 bzero (buffer, buflen);
288 java_buffer = (char *) alloca (buflen);
290 jcf->java_source = 0;
292 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
294 const char *path_name = jcf_path_name (entry);
299 strcpy (buffer, path_name);
302 /* This is right because we know that `.zip' entries will have a
303 trailing slash. See jcf-path.c. */
306 for (k = 0; k < classname_length; k++, i++)
308 char ch = classname[k];
309 buffer[i] = ch == '.' ? '/' : ch;
311 strcpy (buffer+i, ".class");
313 if (jcf_path_is_zipfile (entry))
317 buffer[dir_len] = '\0';
318 SOURCE_FRONTEND_DEBUG
319 (("Trying [...%s]:%s",
320 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
324 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
325 jcf_path_is_system (entry));
328 /* Should we check if .zip is out-of-date wrt .java? */
329 buffer[dir_len] = '(';
330 strcpy (buffer+i, ".class)");
338 class = stat (buffer, &class_buf);
343 /* Compute name of .java file. */
345 strcpy (java_buffer, path_name);
346 l = strlen (java_buffer);
347 for (m = 0; m < classname_length; ++m)
348 java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
349 strcpy (java_buffer + m + l, ".java");
350 java = stat (java_buffer, &java_buf);
356 /* We preferably pick a class file if we have a chance. If the source
357 file is newer than the class file, we issue a warning and parse the
359 There should be a flag to allow people have the class file picked
360 up no matter what. FIXME. */
361 if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
363 char *stripped_class_name = xstrdup (classname);
364 int i = strlen (stripped_class_name);
366 while (stripped_class_name [i] != '.')
369 stripped_class_name [i] = '\0';
370 warning ("Source file for class `%s' is newer than its matching class file. Source file used instead", stripped_class_name);
371 free (stripped_class_name);
376 dep_file = java_buffer;
382 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
383 stream = fopen (buffer, "rb");
387 /* Give .java a try, if necessary */
390 strcpy (buffer, java_buffer);
391 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
392 stream = fopen (buffer, "r");
395 jcf->java_source = 1;
402 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
403 classname+classname_length-
404 (classname_length <= 30 ?
405 classname_length : 30)));
406 fd = open (buffer, O_RDONLY | O_BINARY);
410 /* Give .java a try, if necessary */
413 strcpy (buffer, java_buffer);
414 SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
415 classname+classname_length-
416 (classname_length <= 30 ?
417 classname_length : 30)));
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 = xstrdup (buffer);
441 close (fd); /* We use STDIO for source 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 = xstrdup (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 const unsigned char *str AND int length)
488 const 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 const unsigned char *str AND int length
506 AND int in_char AND int out_char)
508 const unsigned char *limit = str + length;
511 int ch = UTF8_GET (str, limit);
514 fprintf (stream, "\\<invalid>");
517 jcf_print_char (stream, ch == in_char ? out_char : ch);
521 /* Check that all the cross-references in the constant pool are
522 valid. Returns 0 on success.
523 Otherwise, returns the index of the (first) invalid entry. */
526 DEFUN(verify_constant_pool, (jcf),
530 for (i = 1; i < JPOOL_SIZE (jcf); i++)
532 switch (JPOOL_TAG (jcf, i))
534 case CONSTANT_NameAndType:
535 n = JPOOL_USHORT2 (jcf, i);
536 if (n <= 0 || n >= JPOOL_SIZE(jcf)
537 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
539 /* ... fall through ... */
541 case CONSTANT_String:
542 n = JPOOL_USHORT1 (jcf, i);
543 if (n <= 0 || n >= JPOOL_SIZE(jcf)
544 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
547 case CONSTANT_Fieldref:
548 case CONSTANT_Methodref:
549 case CONSTANT_InterfaceMethodref:
550 n = JPOOL_USHORT1 (jcf, i);
551 if (n <= 0 || n >= JPOOL_SIZE(jcf)
552 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
554 n = JPOOL_USHORT2 (jcf, i);
555 if (n <= 0 || n >= JPOOL_SIZE(jcf)
556 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
560 case CONSTANT_Double:
564 case CONSTANT_Integer:
566 case CONSTANT_Unicode:
576 DEFUN(format_uint, (buffer, value, base),
577 char *buffer AND uint64 value AND int base)
579 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
580 char buf[WRITE_BUF_SIZE];
581 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
585 /* Now do the actual conversion, placing the result at the *end* of buf. */
586 /* Note this code does not pretend to be optimized. */
588 int digit = value % base;
589 static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
590 *--buf_ptr = digit_chars[digit];
592 } while (value != 0);
594 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
595 for (i = 0; i < chars_written; i++)
596 buffer[i] = *buf_ptr++;
601 DEFUN(format_int, (buffer, value, base),
602 char *buffer AND jlong value AND int base)
607 abs_value = -(uint64)value;
611 abs_value = (uint64) value;
612 format_uint (buffer, abs_value, base);