diff options
author | green <green@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-09-06 15:36:06 +0000 |
---|---|---|
committer | green <green@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-09-06 15:36:06 +0000 |
commit | 377029eb64eb54a4d6aa7fbfe06230ae65cb086b (patch) | |
tree | b78f906318225a5e7bd3471f008be772727bdcea /gcc/java/jcf-io.c | |
parent | b13f7168a0f35f0d6cc011a7dda0aea51c3d2780 (diff) | |
download | gcc-377029eb64eb54a4d6aa7fbfe06230ae65cb086b.tar.gz |
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@22299 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/java/jcf-io.c')
-rw-r--r-- | gcc/java/jcf-io.c | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/gcc/java/jcf-io.c b/gcc/java/jcf-io.c new file mode 100644 index 00000000000..931f34eaec5 --- /dev/null +++ b/gcc/java/jcf-io.c @@ -0,0 +1,574 @@ +/* Utility routines for finding and reading Java(TM) .class files. + Copyright (C) 1996 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */ + +#include <stdio.h> + +#define ENABLE_UNZIP 1 + +#include "jcf.h" +#ifdef __STDC__ +#include <stdlib.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> + +/* DOS brain-damage */ +#ifndef O_BINARY +#define O_BINARY 0 /* MS-DOS brain-damage */ +#endif + +char *classpath; + +int +DEFUN(jcf_unexpected_eof, (jcf, count), + JCF *jcf AND int count) +{ + if (jcf->filename) + fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename); + else + fprintf (stderr, "Premature end of .class file <stdin>.\n"); + exit (-1); +} + +void +DEFUN(jcf_trim_old_input, (jcf), + JCF *jcf) +{ + int count = jcf->read_ptr - jcf->buffer; + if (count > 0) + { + memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr); + jcf->read_ptr -= count; + jcf->read_end -= count; + } +} + +int +DEFUN(jcf_filbuf_from_stdio, (jcf, count), + JCF *jcf AND int count) +{ + FILE *file = (FILE*) (jcf->read_state); + if (count > jcf->buffer_end - jcf->read_ptr) + { + JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer; + JCF_u4 old_read_end = jcf->read_end - jcf->buffer; + JCF_u4 old_size = jcf->buffer_end - jcf->buffer; + JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count; + unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size) + : REALLOC (jcf->buffer, new_size); + jcf->buffer = new_buffer; + jcf->buffer_end = new_buffer + new_size; + jcf->read_ptr = new_buffer + old_read_ptr; + jcf->read_end = new_buffer + old_read_end; + } + count -= jcf->read_end - jcf->read_ptr; + if (count <= 0) + return 0; + if (fread (jcf->read_end, 1, count, file) != count) + jcf_unexpected_eof (jcf, count); + jcf->read_end += count; + return 0; +} + +#if ENABLE_UNZIP +#include "zipfile.h" + +struct ZipFileCache *SeenZipFiles = NULL; + +int +DEFUN(open_in_zip, (jcf, +zipfile, zipmember), + JCF *jcf AND const char *zipfile AND const char *zipmember) +{ + struct ZipFileCache* zipf; + ZipDirectory *zipd; + int i, len; + for (zipf = SeenZipFiles; ; zipf = zipf->next) + { + if (zipf == NULL) + { + char magic [4]; + int fd = open (zipfile, O_RDONLY | O_BINARY); + if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC) + return -1; + lseek (fd, 0L, SEEK_SET); + zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1); + zipf->next = SeenZipFiles; + zipf->name = (char*)(zipf+1); + strcpy (zipf->name, zipfile); + SeenZipFiles = zipf; + zipf->z.fd = fd; + if (fd == -1) + { + /* A missing zip file is not considered an error. */ + zipf->z.count = 0; + zipf->z.dir_size = 0; + zipf->z.central_directory = NULL; + return -1; + } + else + { + if (read_zip_archive (&zipf->z) != 0) + return -2; /* This however should be an error - FIXME */ + } + break; + } + if (strcmp (zipf->name, zipfile) == 0) + break; + } + + if (!zipmember) + return 0; + + len = strlen (zipmember); + + zipd = (struct ZipDirectory*) zipf->z.central_directory; + for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd)) + { + if (len == zipd->filename_length && + strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0) + { + JCF_ZERO (jcf); + jcf->buffer = ALLOC (zipd->size); + jcf->buffer_end = jcf->buffer + zipd->size; + jcf->read_ptr = jcf->buffer; + jcf->read_end = jcf->buffer_end; + jcf->filbuf = jcf_unexpected_eof; + jcf->filename = (char *) strdup (zipfile); + jcf->classname = (char *) strdup (zipmember); + jcf->zipd = (void *)zipd; + if (lseek (zipf->z.fd, zipd->filestart, 0) < 0 + || read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size) + return -2; + return 0; + } + } + return -1; +} +#endif /* ENABLE_UNZIP */ + +#if JCF_USE_STDIO +char* +DEFUN(open_class, (filename, jcf, stream), + char *filename AND JCF *jcf AND FILE* stream) +{ + if (jcf) + { + JCF_ZERO (jcf); + jcf->buffer = NULL; + jcf->buffer_end = NULL; + jcf->read_ptr = NULL; + jcf->read_end = NULL; + jcf->read_state = stream; + jcf->filbuf = jcf_filbuf_from_stdio; + } + else + fclose (stream); + return filename; +} +#else +char* +DEFUN(open_class, (filename, jcf, fd), + char *filename AND JCF *jcf AND int fd) +{ + if (jcf) + { + struct stat stat_buf; + if (fstat (fd, &stat_buf) != 0 + || ! S_ISREG (stat_buf.st_mode)) + { + perror ("Could not figure length of .class file"); + return NULL; + } + JCF_ZERO (jcf); + jcf->buffer = ALLOC (stat_buf.st_size); + jcf->buffer_end = jcf->buffer + stat_buf.st_size; + jcf->read_ptr = jcf->buffer; + jcf->read_end = jcf->buffer_end; + jcf->read_state = NULL; + jcf->filename = filename; + if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size) + { + perror ("Failed to read .class file"); + return NULL; + } + close (fd); + jcf->filbuf = jcf_unexpected_eof; + } + else + close (fd); + return filename; +} +#endif + + +char * +DEFUN(find_classfile, (filename_length, jcf), + char *filename AND JCF *jcf) +{ +#if JCF_USE_STDIO + FILE *stream = fopen (filename, "rb"); + if (stream == NULL) + return NULL; + return open_class (arg, jcf, stream); +#else + int fd = open (filename, O_RDONLY | O_BINARY); + if (fd < 0) + return NULL; + return open_class (filename, jcf, fd); +#endif +} + +/* Returns a freshly malloc'd string with the fully qualified pathname + of the .class file for the class CLASSNAME. Returns NULL on + failure. If JCF != NULL, it is suitably initialized. With + DO_CLASS_FILE set to 1, search a .class/.java file named after + CLASSNAME, otherwise, search a ZIP directory entry named after + CLASSNAME. */ + +char * +DEFUN(find_class, (classname, classname_length, jcf, do_class_file), + const char *classname AND int classname_length AND JCF *jcf AND int do_class_file) + +{ +#if JCF_USE_STDIO + FILE *stream; +#else + int fd; +#endif + int i, j, k, java, class; + struct stat java_buf, class_buf; + + /* Allocate and zero out the buffer, since we don't explicitly put a + null pointer when we're copying it below. */ + int buflen = strlen (classpath) + classname_length + 10; + char *buffer = (char *) ALLOC (buflen); + bzero (buffer, buflen); + + jcf->java_source = jcf->outofsynch = 0; + for (j = 0; classpath[j] != '\0'; ) + { + for (i = 0; classpath[j] != ':' && classpath[j] != '\0'; i++, j++) + buffer[i] = classpath[j]; + if (classpath[j] == ':') + j++; + if (i > 0) /* Empty directory is redundant */ + { + int dir_len; + if (buffer[i-1] != '/') + buffer[i++] = '/'; + dir_len = i-1; + for (k = 0; k < classname_length; k++, i++) + { + char ch = classname[k]; + buffer[i] = ch == '.' ? '/' : ch; + } + if (do_class_file) + strcpy (buffer+i, ".class"); +#if ENABLE_UNZIP + if (dir_len > 4 + && buffer[dir_len-4] == '.' && buffer[dir_len-3] == 'z' + && buffer[dir_len-2] == 'i' && buffer[dir_len-1] == 'p') + { + int err_code; + JCF _jcf; + if (!do_class_file) + strcpy (buffer+i, "/"); + buffer[dir_len] = '\0'; + if (do_class_file) + SOURCE_FRONTEND_DEBUG + (("Trying [...%s]:%s", + &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], + buffer+dir_len+1)); + if (jcf == NULL) + jcf = &_jcf; + err_code = open_in_zip (jcf, buffer, buffer+dir_len+1); + if (err_code == 0) + { + if (!do_class_file) + jcf->seen_in_zip = 1; + else + { + buffer[dir_len] = '('; + strcpy (buffer+i, ".class)"); + } + if (jcf == &_jcf) + JCF_FINISH (jcf); + return buffer; + } + else + continue; + } +#endif + /* If we do directories, do them here */ + if (!do_class_file) + { + struct stat dir_buff; + int dir; + buffer[i] = '\0'; /* Was previously unterminated here. */ + if (!(dir = stat (buffer, &dir_buff))) + { + jcf->seen_in_zip = 0; + goto found; + } + } + + /* Check for out of synch .class/.java files */ + class = stat (buffer, &class_buf); + strcpy (buffer+i, ".java"); + java = stat (buffer, &java_buf); + if ((!java && !class) && java_buf.st_mtime >= class_buf.st_mtime) + jcf->outofsynch = 1; +#if JCF_USE_STDIO + if (!class) + { + strcpy (buffer+i, ".class"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + stream = fopen (buffer, "rb"); + if (stream) + goto found; + } + /* Give .java a try, if necessary */ + if (!java) + { + strcpy (buffer+i, ".java"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + stream = fopen (buffer, "r"); + if (stream) + { + jcf->java_source = 1; + goto found; + } + } +#else + if (!class) + { + strcpy (buffer+i, ".class"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + fd = open (buffer, O_RDONLY | O_BINARY); + if (fd >= 0) + goto found; + } + /* Give .java a try, if necessary */ + if (!java) + { + if (do_class_file) + strcpy (buffer+i, ".java"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + fd = open (buffer, O_RDONLY | O_BINARY); + if (fd >= 0) + { + jcf->java_source = 1; + goto found; + } + } +#endif + } + } + free (buffer); + return NULL; + found: +#if JCF_USE_STDIO + if (jcf->java_source) + return NULL; /* FIXME */ + else + return open_class (buffer, jcf, stream); +#else + if (jcf->java_source) + { + JCF_ZERO (jcf); /* JCF_FINISH relies on this */ + jcf->java_source = 1; + jcf->filename = (char *) strdup (buffer); + close (fd); /* We use STDIO for source file */ + } + else if (do_class_file) + buffer = open_class (buffer, jcf, fd); + jcf->classname = (char *) ALLOC (classname_length + 1); + strncpy (jcf->classname, classname, classname_length + 1); + jcf->classname = (char *) strdup (classname); + return buffer; +#endif +} + +void +DEFUN(jcf_print_char, (stream, ch), + FILE *stream AND int ch) +{ + switch (ch) + { + case '\'': + case '\\': + case '\"': + fprintf (stream, "\\%c", ch); + break; + case '\n': + fprintf (stream, "\\n"); + break; + case '\t': + fprintf (stream, "\\t"); + break; + case '\r': + fprintf (stream, "\\r"); + break; + default: + if (ch >= ' ' && ch < 127) + putc (ch, stream); + else if (ch < 256) + fprintf (stream, "\\%03x", ch); + else + fprintf (stream, "\\u%04x", ch); + } +} + +/* Print UTF8 string at STR of length LENGTH bytes to STREAM. */ + +void +DEFUN(jcf_print_utf8, (stream, str, length), + FILE *stream AND register unsigned char *str AND int length) +{ + unsigned char* limit = str + length; + while (str < limit) + { + int ch = UTF8_GET (str, limit); + if (ch < 0) + { + fprintf (stream, "\\<invalid>"); + return; + } + jcf_print_char (stream, ch); + } +} + +/* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */ + +void +DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char), + FILE *stream AND unsigned char *str AND int length + AND int in_char AND int out_char) +{ + + int i;/* FIXME - actually handle Unicode! */ + for (i = 0; i < length; i++) + { + int ch = str[i]; + jcf_print_char (stream, ch == in_char ? out_char : ch); + } +} + +/* Check that all the cross-references in the constant pool are + valid. Returns 0 on success. + Otherwise, returns the index of the (first) invalid entry. */ + +int +DEFUN(verify_constant_pool, (jcf), + JCF *jcf) +{ + int i, n; + for (i = 1; i < JPOOL_SIZE (jcf); i++) + { + switch (JPOOL_TAG (jcf, i)) + { + case CONSTANT_NameAndType: + n = JPOOL_USHORT2 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) + return i; + /* ... fall through ... */ + case CONSTANT_Class: + case CONSTANT_String: + n = JPOOL_USHORT1 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) + return i; + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + n = JPOOL_USHORT1 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Class) + return i; + n = JPOOL_USHORT2 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) + return i; + break; + case CONSTANT_Long: + case CONSTANT_Double: + i++; + break; + case CONSTANT_Float: + case CONSTANT_Integer: + case CONSTANT_Utf8: + case CONSTANT_Unicode: + break; + default: + return i; + } + } + return 0; +} + +void +DEFUN(format_uint, (buffer, value, base), + char *buffer AND uint64 value AND int base) +{ +#define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8) + char buf[WRITE_BUF_SIZE]; + register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */ + int chars_written; + int i; + + /* Now do the actual conversion, placing the result at the *end* of buf. */ + /* Note this code does not pretend to be optimized. */ + do { + int digit = value % base; + static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + *--buf_ptr = digit_chars[digit]; + value /= base; + } while (value != 0); + + chars_written = buf+WRITE_BUF_SIZE - buf_ptr; + for (i = 0; i < chars_written; i++) + buffer[i] = *buf_ptr++; + buffer[i] = 0; +} + +void +DEFUN(format_int, (buffer, value, base), + char *buffer AND jlong value AND int base) +{ + uint64 abs_value; + if (value < 0) + { + abs_value = -(uint64)value; + *buffer++ = '-'; + } + else + abs_value = (uint64) value; + format_uint (buffer, abs_value, base); +} |