This commit was manufactured by cvs2svn to create branch 'egcs'.
[official-gcc.git] / gcc / java / jcf-io.c
blob931f34eaec5afcc60201cc6ba40d8c82733b7823
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996 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 <stdio.h>
27 #define ENABLE_UNZIP 1
29 #include "jcf.h"
30 #ifdef __STDC__
31 #include <stdlib.h>
32 #endif
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/wait.h>
36 #include <errno.h>
37 #include <fcntl.h>
39 /* DOS brain-damage */
40 #ifndef O_BINARY
41 #define O_BINARY 0 /* MS-DOS brain-damage */
42 #endif
44 char *classpath;
46 int
47 DEFUN(jcf_unexpected_eof, (jcf, count),
48 JCF *jcf AND int count)
50 if (jcf->filename)
51 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
52 else
53 fprintf (stderr, "Premature end of .class file <stdin>.\n");
54 exit (-1);
57 void
58 DEFUN(jcf_trim_old_input, (jcf),
59 JCF *jcf)
61 int count = jcf->read_ptr - jcf->buffer;
62 if (count > 0)
64 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
65 jcf->read_ptr -= count;
66 jcf->read_end -= count;
70 int
71 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
72 JCF *jcf AND int count)
74 FILE *file = (FILE*) (jcf->read_state);
75 if (count > jcf->buffer_end - jcf->read_ptr)
77 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
78 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
79 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
80 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
81 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
82 : REALLOC (jcf->buffer, new_size);
83 jcf->buffer = new_buffer;
84 jcf->buffer_end = new_buffer + new_size;
85 jcf->read_ptr = new_buffer + old_read_ptr;
86 jcf->read_end = new_buffer + old_read_end;
88 count -= jcf->read_end - jcf->read_ptr;
89 if (count <= 0)
90 return 0;
91 if (fread (jcf->read_end, 1, count, file) != count)
92 jcf_unexpected_eof (jcf, count);
93 jcf->read_end += count;
94 return 0;
97 #if ENABLE_UNZIP
98 #include "zipfile.h"
100 struct ZipFileCache *SeenZipFiles = NULL;
103 DEFUN(open_in_zip, (jcf,
104 zipfile, zipmember),
105 JCF *jcf AND const char *zipfile AND const char *zipmember)
107 struct ZipFileCache* zipf;
108 ZipDirectory *zipd;
109 int i, len;
110 for (zipf = SeenZipFiles; ; zipf = zipf->next)
112 if (zipf == NULL)
114 char magic [4];
115 int fd = open (zipfile, O_RDONLY | O_BINARY);
116 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
117 return -1;
118 lseek (fd, 0L, SEEK_SET);
119 zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
120 zipf->next = SeenZipFiles;
121 zipf->name = (char*)(zipf+1);
122 strcpy (zipf->name, zipfile);
123 SeenZipFiles = zipf;
124 zipf->z.fd = fd;
125 if (fd == -1)
127 /* A missing zip file is not considered an error. */
128 zipf->z.count = 0;
129 zipf->z.dir_size = 0;
130 zipf->z.central_directory = NULL;
131 return -1;
133 else
135 if (read_zip_archive (&zipf->z) != 0)
136 return -2; /* This however should be an error - FIXME */
138 break;
140 if (strcmp (zipf->name, zipfile) == 0)
141 break;
144 if (!zipmember)
145 return 0;
147 len = strlen (zipmember);
149 zipd = (struct ZipDirectory*) zipf->z.central_directory;
150 for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd))
152 if (len == zipd->filename_length &&
153 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
155 JCF_ZERO (jcf);
156 jcf->buffer = ALLOC (zipd->size);
157 jcf->buffer_end = jcf->buffer + zipd->size;
158 jcf->read_ptr = jcf->buffer;
159 jcf->read_end = jcf->buffer_end;
160 jcf->filbuf = jcf_unexpected_eof;
161 jcf->filename = (char *) strdup (zipfile);
162 jcf->classname = (char *) strdup (zipmember);
163 jcf->zipd = (void *)zipd;
164 if (lseek (zipf->z.fd, zipd->filestart, 0) < 0
165 || read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size)
166 return -2;
167 return 0;
170 return -1;
172 #endif /* ENABLE_UNZIP */
174 #if JCF_USE_STDIO
175 char*
176 DEFUN(open_class, (filename, jcf, stream),
177 char *filename AND JCF *jcf AND FILE* stream)
179 if (jcf)
181 JCF_ZERO (jcf);
182 jcf->buffer = NULL;
183 jcf->buffer_end = NULL;
184 jcf->read_ptr = NULL;
185 jcf->read_end = NULL;
186 jcf->read_state = stream;
187 jcf->filbuf = jcf_filbuf_from_stdio;
189 else
190 fclose (stream);
191 return filename;
193 #else
194 char*
195 DEFUN(open_class, (filename, jcf, fd),
196 char *filename AND JCF *jcf AND int fd)
198 if (jcf)
200 struct stat stat_buf;
201 if (fstat (fd, &stat_buf) != 0
202 || ! S_ISREG (stat_buf.st_mode))
204 perror ("Could not figure length of .class file");
205 return NULL;
207 JCF_ZERO (jcf);
208 jcf->buffer = ALLOC (stat_buf.st_size);
209 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
210 jcf->read_ptr = jcf->buffer;
211 jcf->read_end = jcf->buffer_end;
212 jcf->read_state = NULL;
213 jcf->filename = filename;
214 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
216 perror ("Failed to read .class file");
217 return NULL;
219 close (fd);
220 jcf->filbuf = jcf_unexpected_eof;
222 else
223 close (fd);
224 return filename;
226 #endif
229 char *
230 DEFUN(find_classfile, (filename_length, jcf),
231 char *filename AND JCF *jcf)
233 #if JCF_USE_STDIO
234 FILE *stream = fopen (filename, "rb");
235 if (stream == NULL)
236 return NULL;
237 return open_class (arg, jcf, stream);
238 #else
239 int fd = open (filename, O_RDONLY | O_BINARY);
240 if (fd < 0)
241 return NULL;
242 return open_class (filename, jcf, fd);
243 #endif
246 /* Returns a freshly malloc'd string with the fully qualified pathname
247 of the .class file for the class CLASSNAME. Returns NULL on
248 failure. If JCF != NULL, it is suitably initialized. With
249 DO_CLASS_FILE set to 1, search a .class/.java file named after
250 CLASSNAME, otherwise, search a ZIP directory entry named after
251 CLASSNAME. */
253 char *
254 DEFUN(find_class, (classname, classname_length, jcf, do_class_file),
255 const char *classname AND int classname_length AND JCF *jcf AND int do_class_file)
258 #if JCF_USE_STDIO
259 FILE *stream;
260 #else
261 int fd;
262 #endif
263 int i, j, k, java, class;
264 struct stat java_buf, class_buf;
266 /* Allocate and zero out the buffer, since we don't explicitly put a
267 null pointer when we're copying it below. */
268 int buflen = strlen (classpath) + classname_length + 10;
269 char *buffer = (char *) ALLOC (buflen);
270 bzero (buffer, buflen);
272 jcf->java_source = jcf->outofsynch = 0;
273 for (j = 0; classpath[j] != '\0'; )
275 for (i = 0; classpath[j] != ':' && classpath[j] != '\0'; i++, j++)
276 buffer[i] = classpath[j];
277 if (classpath[j] == ':')
278 j++;
279 if (i > 0) /* Empty directory is redundant */
281 int dir_len;
282 if (buffer[i-1] != '/')
283 buffer[i++] = '/';
284 dir_len = i-1;
285 for (k = 0; k < classname_length; k++, i++)
287 char ch = classname[k];
288 buffer[i] = ch == '.' ? '/' : ch;
290 if (do_class_file)
291 strcpy (buffer+i, ".class");
292 #if ENABLE_UNZIP
293 if (dir_len > 4
294 && buffer[dir_len-4] == '.' && buffer[dir_len-3] == 'z'
295 && buffer[dir_len-2] == 'i' && buffer[dir_len-1] == 'p')
297 int err_code;
298 JCF _jcf;
299 if (!do_class_file)
300 strcpy (buffer+i, "/");
301 buffer[dir_len] = '\0';
302 if (do_class_file)
303 SOURCE_FRONTEND_DEBUG
304 (("Trying [...%s]:%s",
305 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
306 buffer+dir_len+1));
307 if (jcf == NULL)
308 jcf = &_jcf;
309 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1);
310 if (err_code == 0)
312 if (!do_class_file)
313 jcf->seen_in_zip = 1;
314 else
316 buffer[dir_len] = '(';
317 strcpy (buffer+i, ".class)");
319 if (jcf == &_jcf)
320 JCF_FINISH (jcf);
321 return buffer;
323 else
324 continue;
326 #endif
327 /* If we do directories, do them here */
328 if (!do_class_file)
330 struct stat dir_buff;
331 int dir;
332 buffer[i] = '\0'; /* Was previously unterminated here. */
333 if (!(dir = stat (buffer, &dir_buff)))
335 jcf->seen_in_zip = 0;
336 goto found;
340 /* Check for out of synch .class/.java files */
341 class = stat (buffer, &class_buf);
342 strcpy (buffer+i, ".java");
343 java = stat (buffer, &java_buf);
344 if ((!java && !class) && java_buf.st_mtime >= class_buf.st_mtime)
345 jcf->outofsynch = 1;
346 #if JCF_USE_STDIO
347 if (!class)
349 strcpy (buffer+i, ".class");
350 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
351 stream = fopen (buffer, "rb");
352 if (stream)
353 goto found;
355 /* Give .java a try, if necessary */
356 if (!java)
358 strcpy (buffer+i, ".java");
359 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
360 stream = fopen (buffer, "r");
361 if (stream)
363 jcf->java_source = 1;
364 goto found;
367 #else
368 if (!class)
370 strcpy (buffer+i, ".class");
371 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
372 fd = open (buffer, O_RDONLY | O_BINARY);
373 if (fd >= 0)
374 goto found;
376 /* Give .java a try, if necessary */
377 if (!java)
379 if (do_class_file)
380 strcpy (buffer+i, ".java");
381 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
382 fd = open (buffer, O_RDONLY | O_BINARY);
383 if (fd >= 0)
385 jcf->java_source = 1;
386 goto found;
389 #endif
392 free (buffer);
393 return NULL;
394 found:
395 #if JCF_USE_STDIO
396 if (jcf->java_source)
397 return NULL; /* FIXME */
398 else
399 return open_class (buffer, jcf, stream);
400 #else
401 if (jcf->java_source)
403 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
404 jcf->java_source = 1;
405 jcf->filename = (char *) strdup (buffer);
406 close (fd); /* We use STDIO for source file */
408 else if (do_class_file)
409 buffer = open_class (buffer, jcf, fd);
410 jcf->classname = (char *) ALLOC (classname_length + 1);
411 strncpy (jcf->classname, classname, classname_length + 1);
412 jcf->classname = (char *) strdup (classname);
413 return buffer;
414 #endif
417 void
418 DEFUN(jcf_print_char, (stream, ch),
419 FILE *stream AND int ch)
421 switch (ch)
423 case '\'':
424 case '\\':
425 case '\"':
426 fprintf (stream, "\\%c", ch);
427 break;
428 case '\n':
429 fprintf (stream, "\\n");
430 break;
431 case '\t':
432 fprintf (stream, "\\t");
433 break;
434 case '\r':
435 fprintf (stream, "\\r");
436 break;
437 default:
438 if (ch >= ' ' && ch < 127)
439 putc (ch, stream);
440 else if (ch < 256)
441 fprintf (stream, "\\%03x", ch);
442 else
443 fprintf (stream, "\\u%04x", ch);
447 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
449 void
450 DEFUN(jcf_print_utf8, (stream, str, length),
451 FILE *stream AND register unsigned char *str AND int length)
453 unsigned char* limit = str + length;
454 while (str < limit)
456 int ch = UTF8_GET (str, limit);
457 if (ch < 0)
459 fprintf (stream, "\\<invalid>");
460 return;
462 jcf_print_char (stream, ch);
466 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
468 void
469 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
470 FILE *stream AND unsigned char *str AND int length
471 AND int in_char AND int out_char)
474 int i;/* FIXME - actually handle Unicode! */
475 for (i = 0; i < length; i++)
477 int ch = str[i];
478 jcf_print_char (stream, ch == in_char ? out_char : ch);
482 /* Check that all the cross-references in the constant pool are
483 valid. Returns 0 on success.
484 Otherwise, returns the index of the (first) invalid entry. */
487 DEFUN(verify_constant_pool, (jcf),
488 JCF *jcf)
490 int i, n;
491 for (i = 1; i < JPOOL_SIZE (jcf); i++)
493 switch (JPOOL_TAG (jcf, i))
495 case CONSTANT_NameAndType:
496 n = JPOOL_USHORT2 (jcf, i);
497 if (n <= 0 || n >= JPOOL_SIZE(jcf)
498 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
499 return i;
500 /* ... fall through ... */
501 case CONSTANT_Class:
502 case CONSTANT_String:
503 n = JPOOL_USHORT1 (jcf, i);
504 if (n <= 0 || n >= JPOOL_SIZE(jcf)
505 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
506 return i;
507 break;
508 case CONSTANT_Fieldref:
509 case CONSTANT_Methodref:
510 case CONSTANT_InterfaceMethodref:
511 n = JPOOL_USHORT1 (jcf, i);
512 if (n <= 0 || n >= JPOOL_SIZE(jcf)
513 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
514 return i;
515 n = JPOOL_USHORT2 (jcf, i);
516 if (n <= 0 || n >= JPOOL_SIZE(jcf)
517 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
518 return i;
519 break;
520 case CONSTANT_Long:
521 case CONSTANT_Double:
522 i++;
523 break;
524 case CONSTANT_Float:
525 case CONSTANT_Integer:
526 case CONSTANT_Utf8:
527 case CONSTANT_Unicode:
528 break;
529 default:
530 return i;
533 return 0;
536 void
537 DEFUN(format_uint, (buffer, value, base),
538 char *buffer AND uint64 value AND int base)
540 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
541 char buf[WRITE_BUF_SIZE];
542 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
543 int chars_written;
544 int i;
546 /* Now do the actual conversion, placing the result at the *end* of buf. */
547 /* Note this code does not pretend to be optimized. */
548 do {
549 int digit = value % base;
550 static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
551 *--buf_ptr = digit_chars[digit];
552 value /= base;
553 } while (value != 0);
555 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
556 for (i = 0; i < chars_written; i++)
557 buffer[i] = *buf_ptr++;
558 buffer[i] = 0;
561 void
562 DEFUN(format_int, (buffer, value, base),
563 char *buffer AND jlong value AND int base)
565 uint64 abs_value;
566 if (value < 0)
568 abs_value = -(uint64)value;
569 *buffer++ = '-';
571 else
572 abs_value = (uint64) value;
573 format_uint (buffer, abs_value, base);