summaryrefslogtreecommitdiff
path: root/gcc/java/jcf-io.c
diff options
context:
space:
mode:
authorgreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>1998-09-06 15:36:06 +0000
committergreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>1998-09-06 15:36:06 +0000
commit377029eb64eb54a4d6aa7fbfe06230ae65cb086b (patch)
treeb78f906318225a5e7bd3471f008be772727bdcea /gcc/java/jcf-io.c
parentb13f7168a0f35f0d6cc011a7dda0aea51c3d2780 (diff)
downloadgcc-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.c574
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);
+}