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)
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. */
27 #define ENABLE_UNZIP 1
33 #include <sys/types.h>
39 /* DOS brain-damage */
41 #define O_BINARY 0 /* MS-DOS brain-damage */
47 DEFUN(jcf_unexpected_eof
, (jcf
, count
),
48 JCF
*jcf AND
int count
)
51 fprintf (stderr
, "Premature end of .class file %s.\n", jcf
->filename
);
53 fprintf (stderr
, "Premature end of .class file <stdin>.\n");
58 DEFUN(jcf_trim_old_input
, (jcf
),
61 int count
= jcf
->read_ptr
- jcf
->buffer
;
64 memmove (jcf
->buffer
, jcf
->read_ptr
, jcf
->read_end
- jcf
->read_ptr
);
65 jcf
->read_ptr
-= count
;
66 jcf
->read_end
-= count
;
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
;
91 if (fread (jcf
->read_end
, 1, count
, file
) != count
)
92 jcf_unexpected_eof (jcf
, count
);
93 jcf
->read_end
+= count
;
100 struct ZipFileCache
*SeenZipFiles
= NULL
;
103 DEFUN(open_in_zip
, (jcf
,
105 JCF
*jcf AND
const char *zipfile AND
const char *zipmember
)
107 struct ZipFileCache
* zipf
;
110 for (zipf
= SeenZipFiles
; ; zipf
= zipf
->next
)
115 int fd
= open (zipfile
, O_RDONLY
| O_BINARY
);
116 if (read (fd
, magic
, 4) != 4 || GET_u4 (magic
) != (JCF_u4
)ZIPMAGIC
)
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
);
127 /* A missing zip file is not considered an error. */
129 zipf
->z
.dir_size
= 0;
130 zipf
->z
.central_directory
= NULL
;
135 if (read_zip_archive (&zipf
->z
) != 0)
136 return -2; /* This however should be an error - FIXME */
140 if (strcmp (zipf
->name
, zipfile
) == 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)
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
)
172 #endif /* ENABLE_UNZIP */
176 DEFUN(open_class
, (filename
, jcf
, stream
),
177 char *filename AND JCF
*jcf AND
FILE* stream
)
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
;
195 DEFUN(open_class
, (filename
, jcf
, fd
),
196 char *filename AND JCF
*jcf AND
int fd
)
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");
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");
220 jcf
->filbuf
= jcf_unexpected_eof
;
230 DEFUN(find_classfile
, (filename_length
, jcf
),
231 char *filename AND JCF
*jcf
)
234 FILE *stream
= fopen (filename
, "rb");
237 return open_class (arg
, jcf
, stream
);
239 int fd
= open (filename
, O_RDONLY
| O_BINARY
);
242 return open_class (filename
, jcf
, fd
);
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
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
)
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
] == ':')
279 if (i
> 0) /* Empty directory is redundant */
282 if (buffer
[i
-1] != '/')
285 for (k
= 0; k
< classname_length
; k
++, i
++)
287 char ch
= classname
[k
];
288 buffer
[i
] = ch
== '.' ? '/' : ch
;
291 strcpy (buffer
+i
, ".class");
294 && buffer
[dir_len
-4] == '.' && buffer
[dir_len
-3] == 'z'
295 && buffer
[dir_len
-2] == 'i' && buffer
[dir_len
-1] == 'p')
300 strcpy (buffer
+i
, "/");
301 buffer
[dir_len
] = '\0';
303 SOURCE_FRONTEND_DEBUG
304 (("Trying [...%s]:%s",
305 &buffer
[dir_len
-(dir_len
> 15 ? 15 : dir_len
)],
309 err_code
= open_in_zip (jcf
, buffer
, buffer
+dir_len
+1);
313 jcf
->seen_in_zip
= 1;
316 buffer
[dir_len
] = '(';
317 strcpy (buffer
+i
, ".class)");
327 /* If we do directories, do them here */
330 struct stat dir_buff
;
332 buffer
[i
] = '\0'; /* Was previously unterminated here. */
333 if (!(dir
= stat (buffer
, &dir_buff
)))
335 jcf
->seen_in_zip
= 0;
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
)
349 strcpy (buffer
+i
, ".class");
350 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer
));
351 stream
= fopen (buffer
, "rb");
355 /* Give .java a try, if necessary */
358 strcpy (buffer
+i
, ".java");
359 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer
));
360 stream
= fopen (buffer
, "r");
363 jcf
->java_source
= 1;
370 strcpy (buffer
+i
, ".class");
371 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer
));
372 fd
= open (buffer
, O_RDONLY
| O_BINARY
);
376 /* Give .java a try, if necessary */
380 strcpy (buffer
+i
, ".java");
381 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer
));
382 fd
= open (buffer
, O_RDONLY
| O_BINARY
);
385 jcf
->java_source
= 1;
396 if (jcf
->java_source
)
397 return NULL
; /* FIXME */
399 return open_class (buffer
, jcf
, stream
);
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
);
418 DEFUN(jcf_print_char
, (stream
, ch
),
419 FILE *stream AND
int ch
)
426 fprintf (stream
, "\\%c", ch
);
429 fprintf (stream
, "\\n");
432 fprintf (stream
, "\\t");
435 fprintf (stream
, "\\r");
438 if (ch
>= ' ' && ch
< 127)
441 fprintf (stream
, "\\%03x", ch
);
443 fprintf (stream
, "\\u%04x", ch
);
447 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
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
;
456 int ch
= UTF8_GET (str
, limit
);
459 fprintf (stream
, "\\<invalid>");
462 jcf_print_char (stream
, ch
);
466 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
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
++)
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
),
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
)
500 /* ... fall through ... */
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
)
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
)
515 n
= JPOOL_USHORT2 (jcf
, i
);
516 if (n
<= 0 || n
>= JPOOL_SIZE(jcf
)
517 || JPOOL_TAG (jcf
, n
) != CONSTANT_NameAndType
)
521 case CONSTANT_Double
:
525 case CONSTANT_Integer
:
527 case CONSTANT_Unicode
:
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. */
546 /* Now do the actual conversion, placing the result at the *end* of buf. */
547 /* Note this code does not pretend to be optimized. */
549 int digit
= value
% base
;
550 static char digit_chars
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
551 *--buf_ptr
= digit_chars
[digit
];
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
++;
562 DEFUN(format_int
, (buffer
, value
, base
),
563 char *buffer AND jlong value AND
int base
)
568 abs_value
= -(uint64
)value
;
572 abs_value
= (uint64
) value
;
573 format_uint (buffer
, abs_value
, base
);