FSF GCC merge 02/23/03
[official-gcc.git] / gcc / java / jcf-io.c
blob3b10f399b2cb4186c2f8f194f2402f0a713c124f
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2003
3 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc. */
26 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
28 #include "config.h"
29 #include "system.h"
30 #include "coretypes.h"
31 #include "tm.h"
33 #include "jcf.h"
34 #include "tree.h"
35 #include "toplev.h"
36 #include "java-tree.h"
37 #include "hashtab.h"
38 #if JCF_USE_SCANDIR
39 #include <dirent.h>
40 #include <fnmatch.h>
41 #endif
43 #include "zlib.h"
45 /* DOS brain-damage */
46 #ifndef O_BINARY
47 #define O_BINARY 0 /* MS-DOS brain-damage */
48 #endif
50 int
51 jcf_unexpected_eof (JCF *jcf, int count ATTRIBUTE_UNUSED)
53 if (jcf->filename)
54 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
55 else
56 fprintf (stderr, "Premature end of .class file <stdin>.\n");
57 exit (-1);
60 void
61 jcf_trim_old_input (JCF *jcf)
63 int count = jcf->read_ptr - jcf->buffer;
64 if (count > 0)
66 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
67 jcf->read_ptr -= count;
68 jcf->read_end -= count;
72 int
73 jcf_filbuf_from_stdio (JCF *jcf, int count)
75 FILE *file = (FILE*) (jcf->read_state);
76 if (count > jcf->buffer_end - jcf->read_ptr)
78 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
79 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
80 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
81 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
82 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
83 : REALLOC (jcf->buffer, new_size);
84 jcf->buffer = new_buffer;
85 jcf->buffer_end = new_buffer + new_size;
86 jcf->read_ptr = new_buffer + old_read_ptr;
87 jcf->read_end = new_buffer + old_read_end;
89 count -= jcf->read_end - jcf->read_ptr;
90 if (count <= 0)
91 return 0;
92 if ((int) fread (jcf->read_end, 1, count, file) != count)
93 jcf_unexpected_eof (jcf, count);
94 jcf->read_end += count;
95 return 0;
98 #include "zipfile.h"
100 struct ZipFile *SeenZipFiles = NULL;
102 /* Open a zip file with the given name, and cache directory and file
103 descriptor. If the file is missing, treat it as an empty archive.
104 Return NULL if the .zip file is malformed.
107 ZipFile *
108 opendir_in_zip (const char *zipfile, int is_system)
110 struct ZipFile* zipf;
111 char magic [4];
112 int fd;
113 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
115 if (strcmp (zipf->name, zipfile) == 0)
116 return zipf;
119 zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1);
120 zipf->next = SeenZipFiles;
121 zipf->name = (char*)(zipf+1);
122 strcpy (zipf->name, zipfile);
123 SeenZipFiles = zipf;
124 fd = open (zipfile, O_RDONLY | O_BINARY);
125 zipf->fd = fd;
126 if (fd < 0)
128 /* A missing zip file is not considered an error.
129 We may want to re-consider that. FIXME. */
130 zipf->count = 0;
131 zipf->dir_size = 0;
132 zipf->central_directory = NULL;
134 else
136 jcf_dependency_add_file (zipfile, is_system);
137 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
138 return NULL;
139 lseek (fd, 0L, SEEK_SET);
140 if (read_zip_archive (zipf) != 0)
141 return NULL;
143 return zipf;
146 /* Returns:
147 0: OK - zipmember found.
148 -1: Not found.
149 -2: Malformed archive.
153 open_in_zip (JCF *jcf, const char *zipfile, const char *zipmember,
154 int is_system)
156 ZipDirectory *zipd;
157 int i, len;
158 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
160 if (zipf == NULL)
161 return -2;
163 if (!zipmember)
164 return 0;
166 len = strlen (zipmember);
168 zipd = (struct ZipDirectory*) zipf->central_directory;
169 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
171 if (len == zipd->filename_length &&
172 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
174 JCF_ZERO (jcf);
176 jcf->filename = xstrdup (zipfile);
177 jcf->classname = xstrdup (zipmember);
178 return read_zip_member(jcf, zipd, zipf);
181 return -1;
184 /* Read data from zip archive member. */
187 read_zip_member (JCF *jcf, ZipDirectory *zipd, ZipFile *zipf)
189 jcf->filbuf = jcf_unexpected_eof;
190 jcf->zipd = (void *)zipd;
192 if (zipd->compression_method == Z_NO_COMPRESSION)
194 jcf->buffer = ALLOC (zipd->size);
195 jcf->buffer_end = jcf->buffer + zipd->size;
196 jcf->read_ptr = jcf->buffer;
197 jcf->read_end = jcf->buffer_end;
198 if (lseek (zipf->fd, zipd->filestart, 0) < 0
199 || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
200 return -2;
202 else
204 char *buffer;
205 z_stream d_stream; /* decompression stream */
206 d_stream.zalloc = (alloc_func) 0;
207 d_stream.zfree = (free_func) 0;
208 d_stream.opaque = (voidpf) 0;
210 jcf->buffer = ALLOC (zipd->uncompressed_size);
211 d_stream.next_out = jcf->buffer;
212 d_stream.avail_out = zipd->uncompressed_size;
213 jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
214 jcf->read_ptr = jcf->buffer;
215 jcf->read_end = jcf->buffer_end;
216 buffer = ALLOC (zipd->size);
217 d_stream.next_in = buffer;
218 d_stream.avail_in = zipd->size;
219 if (lseek (zipf->fd, zipd->filestart, 0) < 0
220 || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
221 return -2;
222 /* Handle NO_HEADER using undocumented zlib feature.
223 This is a very common hack. */
224 inflateInit2 (&d_stream, -MAX_WBITS);
225 inflate (&d_stream, Z_NO_FLUSH);
226 inflateEnd (&d_stream);
227 FREE (buffer);
230 return 0;
233 const char *
234 open_class (const char *filename, JCF *jcf, int fd, const char *dep_name)
236 if (jcf)
238 struct stat stat_buf;
239 if (fstat (fd, &stat_buf) != 0
240 || ! S_ISREG (stat_buf.st_mode))
242 perror ("Could not figure length of .class file");
243 return NULL;
245 if (dep_name != NULL)
246 jcf_dependency_add_file (dep_name, 0);
247 JCF_ZERO (jcf);
248 jcf->buffer = ALLOC (stat_buf.st_size);
249 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
250 jcf->read_ptr = jcf->buffer;
251 jcf->read_end = jcf->buffer_end;
252 jcf->read_state = NULL;
253 jcf->filename = filename;
254 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
256 perror ("Failed to read .class file");
257 return NULL;
259 close (fd);
260 jcf->filbuf = jcf_unexpected_eof;
262 else
263 close (fd);
264 return filename;
268 const char *
269 find_classfile (char *filename, JCF *jcf, const char *dep_name)
271 int fd = open (filename, O_RDONLY | O_BINARY);
272 if (fd < 0)
273 return NULL;
274 return open_class (filename, jcf, fd, dep_name);
277 #if JCF_USE_SCANDIR
279 /* A comparison function (as for qsort) that compares KEY (a char *
280 giving the basename of a file) with the name stored in ENTRY (a
281 dirent **). */
283 static int
284 compare_path (const void *key, const void *entry)
286 return strcmp ((const char *) key,
287 (*((const struct dirent **) entry))->d_name);
290 /* Returns nonzero if ENTRY names a .java or .class file. */
292 static int
293 java_or_class_file (const struct dirent *entry)
295 const char *base = lbasename (entry->d_name);
296 return (fnmatch ("*.java", base, 0) == 0 ||
297 fnmatch ("*.class", base, 0) == 0);
300 /* Information about the files present in a particular directory. */
301 typedef struct memoized_dirlist_entry
303 /* The name of the directory. */
304 const char *dir;
305 /* The number of .java and .class files present, or -1 if we could
306 not, for some reason, obtain the list. */
307 int num_files;
308 /* The .java and .class files in the directory, in alphabetical
309 order. */
310 struct dirent **files;
311 } memoized_dirlist_entry;
313 /* Returns true if ENTRY (a memoized_dirlist_entry *) corresponds to
314 the directory given by KEY (a char *) giving the directory
315 name. */
317 static int
318 memoized_dirlist_lookup_eq (const void *entry, const void *key)
320 return strcmp ((const char *) key,
321 ((const memoized_dirlist_entry *) entry)->dir) == 0;
324 /* A hash table mapping directory names to the lists of .java and
325 .class files in that directory. */
327 static htab_t memoized_dirlists;
329 #endif
331 /* Like stat, but avoids actually making the stat system call if we
332 know that it cannot succeed. FILENAME and BUF are as for stat. */
334 static int
335 caching_stat (char *filename, struct stat *buf)
337 #if JCF_USE_SCANDIR
338 char *sep;
339 char *base;
340 memoized_dirlist_entry *dent;
341 void **slot;
343 /* If the hashtable has not already been created, create it now. */
344 if (!memoized_dirlists)
345 memoized_dirlists = htab_create (37,
346 htab_hash_string,
347 memoized_dirlist_lookup_eq,
348 NULL);
350 /* Get the name of the directory. */
351 sep = strrchr (filename, DIR_SEPARATOR);
352 if (sep)
354 *sep = '\0';
355 base = sep + 1;
357 else
358 base = filename;
360 /* Obtain the entry for this directory form the hash table. */
361 slot = htab_find_slot (memoized_dirlists, filename, INSERT);
362 if (!*slot)
364 /* We have not already scanned this directory; scan it now. */
365 dent = ((memoized_dirlist_entry *)
366 ALLOC (sizeof (memoized_dirlist_entry)));
367 dent->dir = xstrdup (filename);
368 /* Unfortunately, scandir is not fully standardized. In
369 particular, the type of the function pointer passed as the
370 third argument sometimes takes a "const struct dirent *"
371 parameter, and sometimes just a "struct dirent *". We cast
372 to (void *) so that either way it is quietly accepted. */
373 dent->num_files = scandir (filename, &dent->files,
374 (void *) java_or_class_file,
375 alphasort);
376 *slot = dent;
378 else
379 dent = *((memoized_dirlist_entry **) slot);
381 /* Put the separator back. */
382 if (sep)
383 *sep = DIR_SEPARATOR;
385 /* If the file is not in the list, there is no need to stat it; it
386 does not exist. */
387 if (dent->num_files != -1
388 && !bsearch (base, dent->files, dent->num_files,
389 sizeof (struct dirent *), compare_path))
390 return -1;
391 #endif
393 return stat (filename, buf);
396 /* Returns 1 if the CLASSNAME (really a char *) matches the name
397 stored in TABLE_ENTRY (also a char *). */
399 static int
400 memoized_class_lookup_eq (const void *table_entry, const void *classname)
402 return strcmp ((const char *)classname, (const char *)table_entry) == 0;
405 /* A hash table keeping track of class names that were not found
406 during class lookup. (There is no need to cache the values
407 associated with names that were found; they are saved in
408 IDENTIFIER_CLASS_VALUE.) */
409 static htab_t memoized_class_lookups;
411 /* Returns a freshly malloc'd string with the fully qualified pathname
412 of the .class file for the class CLASSNAME. CLASSNAME must be
413 allocated in permanent storage; this function may retain a pointer
414 to it. Returns NULL on failure. If JCF != NULL, it is suitably
415 initialized. SOURCE_OK is true if we should also look for .java
416 file. */
418 const char *
419 find_class (const char *classname, int classname_length, JCF *jcf,
420 int source_ok)
422 int fd;
423 int i, k, java = -1, class = -1;
424 struct stat java_buf, class_buf;
425 char *dep_file;
426 void *entry;
427 char *java_buffer;
428 int buflen;
429 char *buffer;
430 hashval_t hash;
432 /* Create the hash table, if it does not already exist. */
433 if (!memoized_class_lookups)
434 memoized_class_lookups = htab_create (37,
435 htab_hash_string,
436 memoized_class_lookup_eq,
437 NULL);
439 /* Loop for this class in the hashtable. If it is present, we've
440 already looked for this class and failed to find it. */
441 hash = htab_hash_string (classname);
442 if (htab_find_with_hash (memoized_class_lookups, classname, hash))
443 return NULL;
445 /* Allocate and zero out the buffer, since we don't explicitly put a
446 null pointer when we're copying it below. */
447 buflen = jcf_path_max_len () + classname_length + 10;
448 buffer = ALLOC (buflen);
449 memset (buffer, 0, buflen);
451 java_buffer = alloca (buflen);
453 jcf->java_source = 0;
455 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
457 const char *path_name = jcf_path_name (entry);
458 if (class != 0)
460 int dir_len;
462 strcpy (buffer, path_name);
463 i = strlen (buffer);
465 /* This is right because we know that `.zip' entries will have a
466 trailing slash. See jcf-path.c. */
467 dir_len = i - 1;
469 for (k = 0; k < classname_length; k++, i++)
471 char ch = classname[k];
472 buffer[i] = ch == '.' ? '/' : ch;
474 strcpy (buffer+i, ".class");
476 if (jcf_path_is_zipfile (entry))
478 int err_code;
479 JCF _jcf;
480 buffer[dir_len] = '\0';
481 SOURCE_FRONTEND_DEBUG
482 (("Trying [...%s]:%s",
483 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
484 buffer+dir_len+1));
485 if (jcf == NULL)
486 jcf = &_jcf;
487 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
488 jcf_path_is_system (entry));
489 if (err_code == 0)
491 /* Should we check if .zip is out-of-date wrt .java? */
492 buffer[dir_len] = '(';
493 strcpy (buffer+i, ".class)");
494 if (jcf == &_jcf)
495 JCF_FINISH (jcf);
496 return buffer;
498 else
499 continue;
501 class = caching_stat(buffer, &class_buf);
504 if (source_ok)
506 /* Compute name of .java file. */
507 int l, m;
508 strcpy (java_buffer, path_name);
509 l = strlen (java_buffer);
510 for (m = 0; m < classname_length; ++m)
511 java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
512 strcpy (java_buffer + m + l, ".java");
513 java = caching_stat (java_buffer, &java_buf);
514 if (java == 0)
515 break;
519 /* We preferably pick a class file if we have a chance. If the source
520 file is newer than the class file, we issue a warning and parse the
521 source file instead.
522 There should be a flag to allow people have the class file picked
523 up no matter what. FIXME. */
524 if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
526 if (flag_newer)
527 warning ("source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer);
528 class = -1;
531 if (! java)
532 dep_file = java_buffer;
533 else
534 dep_file = buffer;
535 if (!class)
537 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
538 classname+classname_length-
539 (classname_length <= 30 ?
540 classname_length : 30)));
541 fd = open (buffer, O_RDONLY | O_BINARY);
542 if (fd >= 0)
543 goto found;
545 /* Give .java a try, if necessary */
546 if (!java)
548 strcpy (buffer, java_buffer);
549 SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
550 classname+classname_length-
551 (classname_length <= 30 ?
552 classname_length : 30)));
553 fd = open (buffer, O_RDONLY);
554 if (fd >= 0)
556 jcf->java_source = 1;
557 goto found;
561 free (buffer);
563 /* Remember that this class could not be found so that we do not
564 have to look again. */
565 *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT)
566 = (void *) classname;
568 return NULL;
569 found:
570 if (jcf->java_source)
572 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
573 jcf->java_source = 1;
574 jcf->filename = xstrdup (buffer);
575 close (fd); /* We use STDIO for source file */
577 else
578 buffer = (char *) open_class (buffer, jcf, fd, dep_file);
579 jcf->classname = xstrdup (classname);
580 return buffer;
583 void
584 jcf_print_char (FILE *stream, int ch)
586 switch (ch)
588 case '\'':
589 case '\\':
590 case '\"':
591 fprintf (stream, "\\%c", ch);
592 break;
593 case '\n':
594 fprintf (stream, "\\n");
595 break;
596 case '\t':
597 fprintf (stream, "\\t");
598 break;
599 case '\r':
600 fprintf (stream, "\\r");
601 break;
602 default:
603 if (ch >= ' ' && ch < 127)
604 putc (ch, stream);
605 else if (ch < 256)
606 fprintf (stream, "\\%03x", ch);
607 else
608 fprintf (stream, "\\u%04x", ch);
612 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
614 void
615 jcf_print_utf8 (FILE *stream, register const unsigned char *str, int length)
617 const unsigned char * limit = str + length;
618 while (str < limit)
620 int ch = UTF8_GET (str, limit);
621 if (ch < 0)
623 fprintf (stream, "\\<invalid>");
624 return;
626 jcf_print_char (stream, ch);
630 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
632 void
633 jcf_print_utf8_replace (FILE *stream, const unsigned char *str, int length,
634 int in_char, int out_char)
636 const unsigned char *limit = str + length;
637 while (str < limit)
639 int ch = UTF8_GET (str, limit);
640 if (ch < 0)
642 fprintf (stream, "\\<invalid>");
643 return;
645 jcf_print_char (stream, ch == in_char ? out_char : ch);
649 /* Check that all the cross-references in the constant pool are
650 valid. Returns 0 on success.
651 Otherwise, returns the index of the (first) invalid entry.
652 Only checks internal consistency, but does not check that
653 any classes, fields, or methods are valid.*/
656 verify_constant_pool (JCF *jcf)
658 int i, n;
659 for (i = 1; i < JPOOL_SIZE (jcf); i++)
661 switch (JPOOL_TAG (jcf, i))
663 case CONSTANT_NameAndType:
664 n = JPOOL_USHORT2 (jcf, i);
665 if (n <= 0 || n >= JPOOL_SIZE(jcf)
666 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
667 return i;
668 /* ... fall through ... */
669 case CONSTANT_Class:
670 case CONSTANT_String:
671 n = JPOOL_USHORT1 (jcf, i);
672 if (n <= 0 || n >= JPOOL_SIZE(jcf)
673 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
674 return i;
675 break;
676 case CONSTANT_Fieldref:
677 case CONSTANT_Methodref:
678 case CONSTANT_InterfaceMethodref:
679 n = JPOOL_USHORT1 (jcf, i);
680 if (n <= 0 || n >= JPOOL_SIZE(jcf)
681 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
682 return i;
683 n = JPOOL_USHORT2 (jcf, i);
684 if (n <= 0 || n >= JPOOL_SIZE(jcf)
685 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
686 return i;
687 break;
688 case CONSTANT_Long:
689 case CONSTANT_Double:
690 i++;
691 break;
692 case CONSTANT_Float:
693 case CONSTANT_Integer:
694 case CONSTANT_Utf8:
695 case CONSTANT_Unicode:
696 break;
697 default:
698 return i;
701 return 0;
704 void
705 format_uint (char *buffer, uint64 value, int base)
707 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
708 char buf[WRITE_BUF_SIZE];
709 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
710 int chars_written;
711 int i;
713 /* Now do the actual conversion, placing the result at the *end* of buf. */
714 /* Note this code does not pretend to be optimized. */
715 do {
716 int digit = value % base;
717 static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
718 *--buf_ptr = digit_chars[digit];
719 value /= base;
720 } while (value != 0);
722 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
723 for (i = 0; i < chars_written; i++)
724 buffer[i] = *buf_ptr++;
725 buffer[i] = 0;
728 void
729 format_int (char *buffer, jlong value, int base)
731 uint64 abs_value;
732 if (value < 0)
734 abs_value = -(uint64)value;
735 *buffer++ = '-';
737 else
738 abs_value = (uint64) value;
739 format_uint (buffer, abs_value, base);