2005-01-16 Steven G. Kargl <kargls@comcast.net>
[official-gcc.git] / gcc / java / jcf-io.c
blobe0ab03e14cf6d4dbd9ea5cb6f92cd09d1106eaaf
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004
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 fd = open (zipfile, O_RDONLY | O_BINARY);
124 zipf->fd = fd;
125 if (fd < 0)
127 /* A missing zip file is not considered an error.
128 We may want to re-consider that. FIXME. */
129 zipf->count = 0;
130 zipf->dir_size = 0;
131 zipf->central_directory = NULL;
133 else
135 jcf_dependency_add_file (zipfile, is_system);
136 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
137 return NULL;
138 lseek (fd, 0L, SEEK_SET);
139 if (read_zip_archive (zipf) != 0)
140 return NULL;
143 SeenZipFiles = zipf;
144 return zipf;
147 /* Returns:
148 0: OK - zipmember found.
149 -1: Not found.
150 -2: Malformed archive.
154 open_in_zip (JCF *jcf, const char *zipfile, const char *zipmember,
155 int is_system)
157 ZipDirectory *zipd;
158 int i, len;
159 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
161 if (zipf == NULL)
162 return -2;
164 if (!zipmember)
165 return 0;
167 len = strlen (zipmember);
169 zipd = (struct ZipDirectory*) zipf->central_directory;
170 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
172 if (len == zipd->filename_length &&
173 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
175 JCF_ZERO (jcf);
177 jcf->filename = xstrdup (zipfile);
178 jcf->classname = xstrdup (zipmember);
179 return read_zip_member(jcf, zipd, zipf);
182 return -1;
185 /* Read data from zip archive member. */
188 read_zip_member (JCF *jcf, ZipDirectory *zipd, ZipFile *zipf)
190 jcf->filbuf = jcf_unexpected_eof;
191 jcf->zipd = (void *)zipd;
193 if (zipd->compression_method == Z_NO_COMPRESSION)
195 jcf->buffer = ALLOC (zipd->size);
196 jcf->buffer_end = jcf->buffer + zipd->size;
197 jcf->read_ptr = jcf->buffer;
198 jcf->read_end = jcf->buffer_end;
199 if (lseek (zipf->fd, zipd->filestart, 0) < 0
200 || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
201 return -2;
203 else
205 char *buffer;
206 z_stream d_stream; /* decompression stream */
207 d_stream.zalloc = (alloc_func) 0;
208 d_stream.zfree = (free_func) 0;
209 d_stream.opaque = (voidpf) 0;
211 jcf->buffer = ALLOC (zipd->uncompressed_size);
212 d_stream.next_out = jcf->buffer;
213 d_stream.avail_out = zipd->uncompressed_size;
214 jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
215 jcf->read_ptr = jcf->buffer;
216 jcf->read_end = jcf->buffer_end;
217 buffer = ALLOC (zipd->size);
218 d_stream.next_in = (unsigned char *) buffer;
219 d_stream.avail_in = zipd->size;
220 if (lseek (zipf->fd, zipd->filestart, 0) < 0
221 || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
222 return -2;
223 /* Handle NO_HEADER using undocumented zlib feature.
224 This is a very common hack. */
225 inflateInit2 (&d_stream, -MAX_WBITS);
226 inflate (&d_stream, Z_NO_FLUSH);
227 inflateEnd (&d_stream);
228 FREE (buffer);
231 return 0;
234 const char *
235 open_class (const char *filename, JCF *jcf, int fd, const char *dep_name)
237 if (jcf)
239 struct stat stat_buf;
240 if (fstat (fd, &stat_buf) != 0
241 || ! S_ISREG (stat_buf.st_mode))
243 perror ("Could not figure length of .class file");
244 return NULL;
246 if (dep_name != NULL)
247 jcf_dependency_add_file (dep_name, 0);
248 JCF_ZERO (jcf);
249 jcf->buffer = ALLOC (stat_buf.st_size);
250 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
251 jcf->read_ptr = jcf->buffer;
252 jcf->read_end = jcf->buffer_end;
253 jcf->read_state = NULL;
254 jcf->filename = filename;
255 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
257 perror ("Failed to read .class file");
258 return NULL;
260 close (fd);
261 jcf->filbuf = jcf_unexpected_eof;
263 else
264 close (fd);
265 return filename;
269 const char *
270 find_classfile (char *filename, JCF *jcf, const char *dep_name)
272 int fd = open (filename, O_RDONLY | O_BINARY);
273 if (fd < 0)
274 return NULL;
275 return open_class (filename, jcf, fd, dep_name);
278 #if JCF_USE_SCANDIR
280 /* A comparison function (as for qsort) that compares KEY (a char *
281 giving the basename of a file) with the name stored in ENTRY (a
282 dirent **). */
284 static int
285 compare_path (const void *key, const void *entry)
287 return strcmp ((const char *) key,
288 (*((const struct dirent **) entry))->d_name);
291 /* Returns nonzero if ENTRY names a .java or .class file. */
293 static int
294 java_or_class_file (const struct dirent *entry)
296 const char *base = lbasename (entry->d_name);
297 return (fnmatch ("*.java", base, 0) == 0 ||
298 fnmatch ("*.class", base, 0) == 0);
301 /* Information about the files present in a particular directory. */
302 typedef struct memoized_dirlist_entry
304 /* The name of the directory. */
305 const char *dir;
306 /* The number of .java and .class files present, or -1 if we could
307 not, for some reason, obtain the list. */
308 int num_files;
309 /* The .java and .class files in the directory, in alphabetical
310 order. */
311 struct dirent **files;
312 } memoized_dirlist_entry;
314 /* Returns true if ENTRY (a memoized_dirlist_entry *) corresponds to
315 the directory given by KEY (a char *) giving the directory
316 name. */
318 static int
319 memoized_dirlist_lookup_eq (const void *entry, const void *key)
321 return strcmp ((const char *) key,
322 ((const memoized_dirlist_entry *) entry)->dir) == 0;
325 /* A hash table mapping directory names to the lists of .java and
326 .class files in that directory. */
328 static htab_t memoized_dirlists;
330 #endif
332 /* Like stat, but avoids actually making the stat system call if we
333 know that it cannot succeed. FILENAME and BUF are as for stat. */
335 static int
336 caching_stat (char *filename, struct stat *buf)
338 #if JCF_USE_SCANDIR
339 char *sep;
340 char origsep = 0;
341 char *base;
342 memoized_dirlist_entry *dent;
343 void **slot;
345 /* If the hashtable has not already been created, create it now. */
346 if (!memoized_dirlists)
347 memoized_dirlists = htab_create (37,
348 htab_hash_string,
349 memoized_dirlist_lookup_eq,
350 NULL);
352 /* Get the name of the directory. */
353 sep = strrchr (filename, DIR_SEPARATOR);
354 #ifdef DIR_SEPARATOR_2
355 if (! sep)
356 sep = strrchr (filename, DIR_SEPARATOR_2);
357 #endif
358 if (sep)
360 origsep = *sep;
361 *sep = '\0';
362 base = sep + 1;
364 else
365 base = filename;
367 /* Obtain the entry for this directory from the hash table. */
368 slot = htab_find_slot (memoized_dirlists, filename, INSERT);
369 if (!*slot)
371 /* We have not already scanned this directory; scan it now. */
372 dent = ((memoized_dirlist_entry *)
373 ALLOC (sizeof (memoized_dirlist_entry)));
374 dent->dir = xstrdup (filename);
375 /* Unfortunately, scandir is not fully standardized. In
376 particular, the type of the function pointer passed as the
377 third argument sometimes takes a "const struct dirent *"
378 parameter, and sometimes just a "struct dirent *". We cast
379 to (void *) so that either way it is quietly accepted.
380 FIXME: scandir is not in POSIX. */
381 dent->num_files = scandir (filename, &dent->files,
382 (void *) java_or_class_file,
383 alphasort);
384 *slot = dent;
386 else
387 dent = *((memoized_dirlist_entry **) slot);
389 /* Put the separator back. */
390 if (sep)
391 *sep = origsep;
393 /* If the file is not in the list, there is no need to stat it; it
394 does not exist. */
395 if (dent->num_files != -1
396 && !bsearch (base, dent->files, dent->num_files,
397 sizeof (struct dirent *), compare_path))
398 return -1;
399 #endif
401 return stat (filename, buf);
404 /* Returns 1 if the CLASSNAME (really a char *) matches the name
405 stored in TABLE_ENTRY (also a char *). */
407 static int
408 memoized_class_lookup_eq (const void *table_entry, const void *classname)
410 return strcmp ((const char *)classname, (const char *)table_entry) == 0;
413 /* A hash table keeping track of class names that were not found
414 during class lookup. (There is no need to cache the values
415 associated with names that were found; they are saved in
416 IDENTIFIER_CLASS_VALUE.) */
417 static htab_t memoized_class_lookups;
419 /* Returns a freshly malloc'd string with the fully qualified pathname
420 of the .class file for the class CLASSNAME. CLASSNAME must be
421 allocated in permanent storage; this function may retain a pointer
422 to it. Returns NULL on failure. If JCF != NULL, it is suitably
423 initialized. SOURCE_OK is true if we should also look for .java
424 file. */
426 const char *
427 find_class (const char *classname, int classname_length, JCF *jcf,
428 int source_ok)
430 int fd;
431 int i, k, java = -1, class = -1;
432 struct stat java_buf, class_buf;
433 char *dep_file;
434 void *entry;
435 char *java_buffer;
436 int buflen;
437 char *buffer;
438 hashval_t hash;
440 /* Create the hash table, if it does not already exist. */
441 if (!memoized_class_lookups)
442 memoized_class_lookups = htab_create (37,
443 htab_hash_string,
444 memoized_class_lookup_eq,
445 NULL);
447 /* Loop for this class in the hashtable. If it is present, we've
448 already looked for this class and failed to find it. */
449 hash = htab_hash_string (classname);
450 if (htab_find_with_hash (memoized_class_lookups, classname, hash))
451 return NULL;
453 /* Allocate and zero out the buffer, since we don't explicitly put a
454 null pointer when we're copying it below. */
455 buflen = jcf_path_max_len () + classname_length + 10;
456 buffer = ALLOC (buflen);
457 memset (buffer, 0, buflen);
459 java_buffer = alloca (buflen);
461 jcf->java_source = 0;
463 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
465 const char *path_name = jcf_path_name (entry);
466 if (class != 0)
468 int dir_len;
470 strcpy (buffer, path_name);
471 i = strlen (buffer);
473 /* This is right because we know that `.zip' entries will have a
474 trailing slash. See jcf-path.c. */
475 dir_len = i - 1;
477 for (k = 0; k < classname_length; k++, i++)
479 char ch = classname[k];
480 buffer[i] = ch == '.' ? '/' : ch;
482 strcpy (buffer+i, ".class");
484 if (jcf_path_is_zipfile (entry))
486 int err_code;
487 JCF _jcf;
488 buffer[dir_len] = '\0';
489 SOURCE_FRONTEND_DEBUG
490 (("Trying [...%s]:%s",
491 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
492 buffer+dir_len+1));
493 if (jcf == NULL)
494 jcf = &_jcf;
495 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
496 jcf_path_is_system (entry));
497 if (err_code == 0)
499 /* Should we check if .zip is out-of-date wrt .java? */
500 buffer[dir_len] = '(';
501 strcpy (buffer+i, ".class)");
502 if (jcf == &_jcf)
503 JCF_FINISH (jcf);
504 return buffer;
506 else
507 continue;
509 class = caching_stat(buffer, &class_buf);
512 if (source_ok)
514 /* Compute name of .java file. */
515 int l, m;
516 strcpy (java_buffer, path_name);
517 l = strlen (java_buffer);
518 for (m = 0; m < classname_length; ++m)
519 java_buffer[m + l] = (classname[m] == '.'
520 ? DIR_SEPARATOR : classname[m]);
521 strcpy (java_buffer + m + l, ".java");
522 java = caching_stat (java_buffer, &java_buf);
523 if (java == 0)
524 break;
528 /* We preferably pick a class file if we have a chance. If the source
529 file is newer than the class file, we issue a warning and parse the
530 source file instead.
531 There should be a flag to allow people have the class file picked
532 up no matter what. FIXME. */
533 if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
535 if (flag_newer)
536 warning ("source file for class %qs is newer than its matching class file. Source file %qs used instead", classname, java_buffer);
537 class = -1;
540 if (! java)
541 dep_file = java_buffer;
542 else
543 dep_file = buffer;
544 if (!class)
546 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
547 classname+classname_length-
548 (classname_length <= 30 ?
549 classname_length : 30)));
550 fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY | O_BINARY);
551 if (fd >= 0)
552 goto found;
554 /* Give .java a try, if necessary */
555 if (!java)
557 strcpy (buffer, java_buffer);
558 SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
559 classname+classname_length-
560 (classname_length <= 30 ?
561 classname_length : 30)));
562 fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY);
563 if (fd >= 0)
565 jcf->java_source = 1;
566 goto found;
570 free (buffer);
572 /* Remember that this class could not be found so that we do not
573 have to look again. */
574 *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT)
575 = (void *) classname;
577 return NULL;
578 found:
579 if (jcf->java_source)
581 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
582 jcf->java_source = 1;
583 jcf->filename = xstrdup (buffer);
584 close (fd); /* We use STDIO for source file */
586 else
587 buffer = (char *) open_class (buffer, jcf, fd, dep_file);
588 jcf->classname = xstrdup (classname);
589 return buffer;
592 void
593 jcf_print_char (FILE *stream, int ch)
595 switch (ch)
597 case '\'':
598 case '\\':
599 case '\"':
600 fprintf (stream, "\\%c", ch);
601 break;
602 case '\n':
603 fprintf (stream, "\\n");
604 break;
605 case '\t':
606 fprintf (stream, "\\t");
607 break;
608 case '\r':
609 fprintf (stream, "\\r");
610 break;
611 default:
612 if (ch >= ' ' && ch < 127)
613 putc (ch, stream);
614 else if (ch < 256)
615 fprintf (stream, "\\%03x", ch);
616 else
617 fprintf (stream, "\\u%04x", ch);
621 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
623 void
624 jcf_print_utf8 (FILE *stream, const unsigned char *str, int length)
626 const unsigned char * limit = str + length;
627 while (str < limit)
629 int ch = UTF8_GET (str, limit);
630 if (ch < 0)
632 fprintf (stream, "\\<invalid>");
633 return;
635 jcf_print_char (stream, ch);
639 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
641 void
642 jcf_print_utf8_replace (FILE *stream, const unsigned char *str, int length,
643 int in_char, int out_char)
645 const unsigned char *limit = str + length;
646 while (str < limit)
648 int ch = UTF8_GET (str, limit);
649 if (ch < 0)
651 fprintf (stream, "\\<invalid>");
652 return;
654 jcf_print_char (stream, ch == in_char ? out_char : ch);
658 /* Check that all the cross-references in the constant pool are
659 valid. Returns 0 on success.
660 Otherwise, returns the index of the (first) invalid entry.
661 Only checks internal consistency, but does not check that
662 any classes, fields, or methods are valid.*/
665 verify_constant_pool (JCF *jcf)
667 int i, n;
668 for (i = 1; i < JPOOL_SIZE (jcf); i++)
670 switch (JPOOL_TAG (jcf, i))
672 case CONSTANT_NameAndType:
673 n = JPOOL_USHORT2 (jcf, i);
674 if (n <= 0 || n >= JPOOL_SIZE(jcf)
675 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
676 return i;
677 /* ... fall through ... */
678 case CONSTANT_Class:
679 case CONSTANT_String:
680 n = JPOOL_USHORT1 (jcf, i);
681 if (n <= 0 || n >= JPOOL_SIZE(jcf)
682 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
683 return i;
684 break;
685 case CONSTANT_Fieldref:
686 case CONSTANT_Methodref:
687 case CONSTANT_InterfaceMethodref:
688 n = JPOOL_USHORT1 (jcf, i);
689 if (n <= 0 || n >= JPOOL_SIZE(jcf)
690 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
691 return i;
692 n = JPOOL_USHORT2 (jcf, i);
693 if (n <= 0 || n >= JPOOL_SIZE(jcf)
694 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
695 return i;
696 break;
697 case CONSTANT_Long:
698 case CONSTANT_Double:
699 i++;
700 break;
701 case CONSTANT_Float:
702 case CONSTANT_Integer:
703 case CONSTANT_Utf8:
704 case CONSTANT_Unicode:
705 break;
706 default:
707 return i;
710 return 0;
713 void
714 format_uint (char *buffer, uint64 value, int base)
716 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
717 char buf[WRITE_BUF_SIZE];
718 char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
719 int chars_written;
720 int i;
722 /* Now do the actual conversion, placing the result at the *end* of buf. */
723 /* Note this code does not pretend to be optimized. */
724 do {
725 int digit = value % base;
726 static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
727 *--buf_ptr = digit_chars[digit];
728 value /= base;
729 } while (value != 0);
731 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
732 for (i = 0; i < chars_written; i++)
733 buffer[i] = *buf_ptr++;
734 buffer[i] = 0;
737 void
738 format_int (char *buffer, jlong value, int base)
740 uint64 abs_value;
741 if (value < 0)
743 abs_value = -(uint64)value;
744 *buffer++ = '-';
746 else
747 abs_value = (uint64) value;
748 format_uint (buffer, abs_value, base);