2001-11-06 Phil Edwards <pme@gcc.gnu.org>
[official-gcc.git] / gcc / java / jcf-io.c
blobba56b1806cd1492803c077a14bcb8a06ab7c1f34
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 1997, 1998, 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)
7 any later version.
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. */
25 #include "config.h"
26 #include "system.h"
28 #include "jcf.h"
29 #include "tree.h"
30 #include "toplev.h"
31 #include "java-tree.h"
33 #include "zlib.h"
35 /* DOS brain-damage */
36 #ifndef O_BINARY
37 #define O_BINARY 0 /* MS-DOS brain-damage */
38 #endif
40 int
41 DEFUN(jcf_unexpected_eof, (jcf, count),
42 JCF *jcf AND int count ATTRIBUTE_UNUSED)
44 if (jcf->filename)
45 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
46 else
47 fprintf (stderr, "Premature end of .class file <stdin>.\n");
48 exit (-1);
51 void
52 DEFUN(jcf_trim_old_input, (jcf),
53 JCF *jcf)
55 int count = jcf->read_ptr - jcf->buffer;
56 if (count > 0)
58 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
59 jcf->read_ptr -= count;
60 jcf->read_end -= count;
64 int
65 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
66 JCF *jcf AND int count)
68 FILE *file = (FILE*) (jcf->read_state);
69 if (count > jcf->buffer_end - jcf->read_ptr)
71 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
72 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
73 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
74 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
75 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
76 : REALLOC (jcf->buffer, new_size);
77 jcf->buffer = new_buffer;
78 jcf->buffer_end = new_buffer + new_size;
79 jcf->read_ptr = new_buffer + old_read_ptr;
80 jcf->read_end = new_buffer + old_read_end;
82 count -= jcf->read_end - jcf->read_ptr;
83 if (count <= 0)
84 return 0;
85 if ((int) fread (jcf->read_end, 1, count, file) != count)
86 jcf_unexpected_eof (jcf, count);
87 jcf->read_end += count;
88 return 0;
91 #include "zipfile.h"
93 struct ZipFile *SeenZipFiles = NULL;
95 /* Open a zip file with the given name, and cache directory and file
96 descriptor. If the file is missing, treat it as an empty archive.
97 Return NULL if the .zip file is malformed.
100 ZipFile *
101 DEFUN(opendir_in_zip, (zipfile, is_system),
102 const char *zipfile AND int is_system)
104 struct ZipFile* zipf;
105 char magic [4];
106 int fd;
107 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
109 if (strcmp (zipf->name, zipfile) == 0)
110 return zipf;
113 zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1);
114 zipf->next = SeenZipFiles;
115 zipf->name = (char*)(zipf+1);
116 strcpy (zipf->name, zipfile);
117 SeenZipFiles = zipf;
118 fd = open (zipfile, O_RDONLY | O_BINARY);
119 zipf->fd = fd;
120 if (fd < 0)
122 /* A missing zip file is not considered an error.
123 We may want to re-consider that. FIXME. */
124 zipf->count = 0;
125 zipf->dir_size = 0;
126 zipf->central_directory = NULL;
128 else
130 jcf_dependency_add_file (zipfile, is_system);
131 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
132 return NULL;
133 lseek (fd, 0L, SEEK_SET);
134 if (read_zip_archive (zipf) != 0)
135 return NULL;
137 return zipf;
140 /* Returns:
141 0: OK - zipmember found.
142 -1: Not found.
143 -2: Malformed archive.
147 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
148 JCF *jcf AND const char *zipfile AND const char *zipmember
149 AND int is_system)
151 ZipDirectory *zipd;
152 int i, len;
153 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
155 if (zipf == NULL)
156 return -2;
158 if (!zipmember)
159 return 0;
161 len = strlen (zipmember);
163 zipd = (struct ZipDirectory*) zipf->central_directory;
164 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
166 if (len == zipd->filename_length &&
167 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
169 JCF_ZERO (jcf);
171 jcf->filename = xstrdup (zipfile);
172 jcf->classname = xstrdup (zipmember);
173 return read_zip_member(jcf, zipd, zipf);
176 return -1;
179 /* Read data from zip archive member. */
182 DEFUN(read_zip_member, (jcf, zipd, zipf),
183 JCF *jcf AND ZipDirectory *zipd AND ZipFile *zipf)
185 jcf->filbuf = jcf_unexpected_eof;
186 jcf->zipd = (void *)zipd;
188 if (zipd->compression_method == Z_NO_COMPRESSION)
190 jcf->buffer = ALLOC (zipd->size);
191 jcf->buffer_end = jcf->buffer + zipd->size;
192 jcf->read_ptr = jcf->buffer;
193 jcf->read_end = jcf->buffer_end;
194 if (lseek (zipf->fd, zipd->filestart, 0) < 0
195 || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
196 return -2;
198 else
200 char *buffer;
201 z_stream d_stream; /* decompression stream */
202 d_stream.zalloc = (alloc_func) 0;
203 d_stream.zfree = (free_func) 0;
204 d_stream.opaque = (voidpf) 0;
206 jcf->buffer = ALLOC (zipd->uncompressed_size);
207 d_stream.next_out = jcf->buffer;
208 d_stream.avail_out = zipd->uncompressed_size;
209 jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
210 jcf->read_ptr = jcf->buffer;
211 jcf->read_end = jcf->buffer_end;
212 buffer = ALLOC (zipd->size);
213 d_stream.next_in = buffer;
214 d_stream.avail_in = zipd->size;
215 if (lseek (zipf->fd, zipd->filestart, 0) < 0
216 || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
217 return -2;
218 /* Handle NO_HEADER using undocumented zlib feature.
219 This is a very common hack. */
220 inflateInit2 (&d_stream, -MAX_WBITS);
221 inflate (&d_stream, Z_NO_FLUSH);
222 inflateEnd (&d_stream);
223 FREE (buffer);
226 return 0;
229 #if JCF_USE_STDIO
230 const char *
231 DEFUN(open_class, (filename, jcf, stream, dep_name),
232 const char *filename AND JCF *jcf AND FILE* stream
233 AND const char *dep_name)
235 if (jcf)
237 if (dep_name != NULL)
238 jcf_dependency_add_file (dep_name, 0);
239 JCF_ZERO (jcf);
240 jcf->buffer = NULL;
241 jcf->buffer_end = NULL;
242 jcf->read_ptr = NULL;
243 jcf->read_end = NULL;
244 jcf->read_state = stream;
245 jcf->filename = filename;
246 jcf->filbuf = jcf_filbuf_from_stdio;
248 else
249 fclose (stream);
250 return filename;
252 #else
253 const char *
254 DEFUN(open_class, (filename, jcf, fd, dep_name),
255 const char *filename AND JCF *jcf AND int fd AND const char *dep_name)
257 if (jcf)
259 struct stat stat_buf;
260 if (fstat (fd, &stat_buf) != 0
261 || ! S_ISREG (stat_buf.st_mode))
263 perror ("Could not figure length of .class file");
264 return NULL;
266 if (dep_name != NULL)
267 jcf_dependency_add_file (dep_name, 0);
268 JCF_ZERO (jcf);
269 jcf->buffer = ALLOC (stat_buf.st_size);
270 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
271 jcf->read_ptr = jcf->buffer;
272 jcf->read_end = jcf->buffer_end;
273 jcf->read_state = NULL;
274 jcf->filename = filename;
275 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
277 perror ("Failed to read .class file");
278 return NULL;
280 close (fd);
281 jcf->filbuf = jcf_unexpected_eof;
283 else
284 close (fd);
285 return filename;
287 #endif
290 const char *
291 DEFUN(find_classfile, (filename, jcf, dep_name),
292 char *filename AND JCF *jcf AND const char *dep_name)
294 #if JCF_USE_STDIO
295 FILE *stream = fopen (filename, "rb");
296 if (stream == NULL)
297 return NULL;
298 return open_class (arg, jcf, stream, dep_name);
299 #else
300 int fd = open (filename, O_RDONLY | O_BINARY);
301 if (fd < 0)
302 return NULL;
303 return open_class (filename, jcf, fd, dep_name);
304 #endif
307 /* Returns a freshly malloc'd string with the fully qualified pathname
308 of the .class file for the class CLASSNAME. Returns NULL on
309 failure. If JCF != NULL, it is suitably initialized.
310 SOURCE_OK is true if we should also look for .java file. */
312 const char *
313 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
314 const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
317 #if JCF_USE_STDIO
318 FILE *stream;
319 #else
320 int fd;
321 #endif
322 int i, k, java = -1, class = -1;
323 struct stat java_buf, class_buf;
324 char *dep_file;
325 void *entry;
326 char *java_buffer;
328 /* Allocate and zero out the buffer, since we don't explicitly put a
329 null pointer when we're copying it below. */
330 int buflen = jcf_path_max_len () + classname_length + 10;
331 char *buffer = (char *) ALLOC (buflen);
332 memset (buffer, 0, buflen);
334 java_buffer = (char *) alloca (buflen);
336 jcf->java_source = 0;
338 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
340 const char *path_name = jcf_path_name (entry);
341 if (class != 0)
343 int dir_len;
345 strcpy (buffer, path_name);
346 i = strlen (buffer);
348 /* This is right because we know that `.zip' entries will have a
349 trailing slash. See jcf-path.c. */
350 dir_len = i - 1;
352 for (k = 0; k < classname_length; k++, i++)
354 char ch = classname[k];
355 buffer[i] = ch == '.' ? '/' : ch;
357 strcpy (buffer+i, ".class");
359 if (jcf_path_is_zipfile (entry))
361 int err_code;
362 JCF _jcf;
363 buffer[dir_len] = '\0';
364 SOURCE_FRONTEND_DEBUG
365 (("Trying [...%s]:%s",
366 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
367 buffer+dir_len+1));
368 if (jcf == NULL)
369 jcf = &_jcf;
370 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
371 jcf_path_is_system (entry));
372 if (err_code == 0)
374 /* Should we check if .zip is out-of-date wrt .java? */
375 buffer[dir_len] = '(';
376 strcpy (buffer+i, ".class)");
377 if (jcf == &_jcf)
378 JCF_FINISH (jcf);
379 return buffer;
381 else
382 continue;
384 class = stat (buffer, &class_buf);
387 if (source_ok)
389 /* Compute name of .java file. */
390 int l, m;
391 strcpy (java_buffer, path_name);
392 l = strlen (java_buffer);
393 for (m = 0; m < classname_length; ++m)
394 java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
395 strcpy (java_buffer + m + l, ".java");
396 java = stat (java_buffer, &java_buf);
397 if (java == 0)
398 break;
402 /* We preferably pick a class file if we have a chance. If the source
403 file is newer than the class file, we issue a warning and parse the
404 source file instead.
405 There should be a flag to allow people have the class file picked
406 up no matter what. FIXME. */
407 if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
409 if (flag_newer)
410 warning ("Source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer);
411 class = -1;
414 if (! java)
415 dep_file = java_buffer;
416 else
417 dep_file = buffer;
418 #if JCF_USE_STDIO
419 if (!class)
421 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
422 stream = fopen (buffer, "rb");
423 if (stream)
424 goto found;
426 /* Give .java a try, if necessary */
427 if (!java)
429 strcpy (buffer, java_buffer);
430 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
431 stream = fopen (buffer, "r");
432 if (stream)
434 jcf->java_source = 1;
435 goto found;
438 #else
439 if (!class)
441 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
442 classname+classname_length-
443 (classname_length <= 30 ?
444 classname_length : 30)));
445 fd = open (buffer, O_RDONLY | O_BINARY);
446 if (fd >= 0)
447 goto found;
449 /* Give .java a try, if necessary */
450 if (!java)
452 strcpy (buffer, java_buffer);
453 SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
454 classname+classname_length-
455 (classname_length <= 30 ?
456 classname_length : 30)));
457 fd = open (buffer, O_RDONLY);
458 if (fd >= 0)
460 jcf->java_source = 1;
461 goto found;
464 #endif
466 free (buffer);
467 return NULL;
468 found:
469 #if JCF_USE_STDIO
470 if (jcf->java_source)
471 return NULL; /* FIXME */
472 else
473 return open_class (buffer, jcf, stream, dep_file);
474 #else
475 if (jcf->java_source)
477 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
478 jcf->java_source = 1;
479 jcf->filename = xstrdup (buffer);
480 close (fd); /* We use STDIO for source file */
482 else
483 buffer = (char *) open_class (buffer, jcf, fd, dep_file);
484 jcf->classname = xstrdup (classname);
485 return buffer;
486 #endif
489 void
490 DEFUN(jcf_print_char, (stream, ch),
491 FILE *stream AND int ch)
493 switch (ch)
495 case '\'':
496 case '\\':
497 case '\"':
498 fprintf (stream, "\\%c", ch);
499 break;
500 case '\n':
501 fprintf (stream, "\\n");
502 break;
503 case '\t':
504 fprintf (stream, "\\t");
505 break;
506 case '\r':
507 fprintf (stream, "\\r");
508 break;
509 default:
510 if (ch >= ' ' && ch < 127)
511 putc (ch, stream);
512 else if (ch < 256)
513 fprintf (stream, "\\%03x", ch);
514 else
515 fprintf (stream, "\\u%04x", ch);
519 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
521 void
522 DEFUN(jcf_print_utf8, (stream, str, length),
523 FILE *stream AND register const unsigned char *str AND int length)
525 const unsigned char * limit = str + length;
526 while (str < limit)
528 int ch = UTF8_GET (str, limit);
529 if (ch < 0)
531 fprintf (stream, "\\<invalid>");
532 return;
534 jcf_print_char (stream, ch);
538 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
540 void
541 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
542 FILE *stream AND const unsigned char *str AND int length
543 AND int in_char AND int out_char)
545 const unsigned char *limit = str + length;
546 while (str < limit)
548 int ch = UTF8_GET (str, limit);
549 if (ch < 0)
551 fprintf (stream, "\\<invalid>");
552 return;
554 jcf_print_char (stream, ch == in_char ? out_char : ch);
558 /* Check that all the cross-references in the constant pool are
559 valid. Returns 0 on success.
560 Otherwise, returns the index of the (first) invalid entry.
561 Only checks internal consistency, but does not check that
562 any classes, fields, or methods are valid.*/
565 DEFUN(verify_constant_pool, (jcf),
566 JCF *jcf)
568 int i, n;
569 for (i = 1; i < JPOOL_SIZE (jcf); i++)
571 switch (JPOOL_TAG (jcf, i))
573 case CONSTANT_NameAndType:
574 n = JPOOL_USHORT2 (jcf, i);
575 if (n <= 0 || n >= JPOOL_SIZE(jcf)
576 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
577 return i;
578 /* ... fall through ... */
579 case CONSTANT_Class:
580 case CONSTANT_String:
581 n = JPOOL_USHORT1 (jcf, i);
582 if (n <= 0 || n >= JPOOL_SIZE(jcf)
583 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
584 return i;
585 break;
586 case CONSTANT_Fieldref:
587 case CONSTANT_Methodref:
588 case CONSTANT_InterfaceMethodref:
589 n = JPOOL_USHORT1 (jcf, i);
590 if (n <= 0 || n >= JPOOL_SIZE(jcf)
591 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
592 return i;
593 n = JPOOL_USHORT2 (jcf, i);
594 if (n <= 0 || n >= JPOOL_SIZE(jcf)
595 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
596 return i;
597 break;
598 case CONSTANT_Long:
599 case CONSTANT_Double:
600 i++;
601 break;
602 case CONSTANT_Float:
603 case CONSTANT_Integer:
604 case CONSTANT_Utf8:
605 case CONSTANT_Unicode:
606 break;
607 default:
608 return i;
611 return 0;
614 void
615 DEFUN(format_uint, (buffer, value, base),
616 char *buffer AND uint64 value AND int base)
618 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
619 char buf[WRITE_BUF_SIZE];
620 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
621 int chars_written;
622 int i;
624 /* Now do the actual conversion, placing the result at the *end* of buf. */
625 /* Note this code does not pretend to be optimized. */
626 do {
627 int digit = value % base;
628 static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
629 *--buf_ptr = digit_chars[digit];
630 value /= base;
631 } while (value != 0);
633 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
634 for (i = 0; i < chars_written; i++)
635 buffer[i] = *buf_ptr++;
636 buffer[i] = 0;
639 void
640 DEFUN(format_int, (buffer, value, base),
641 char *buffer AND jlong value AND int base)
643 uint64 abs_value;
644 if (value < 0)
646 abs_value = -(uint64)value;
647 *buffer++ = '-';
649 else
650 abs_value = (uint64) value;
651 format_uint (buffer, abs_value, base);