]> gcc.gnu.org Git - gcc.git/blob - gcc/java/jcf-io.c
43e96cf94c022f2749b0cc41744633ae04f0e09e
[gcc.git] / gcc / java / jcf-io.c
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996, 1998 Free Software Foundation, Inc.
3
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.
8
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.
13
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.
18
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. */
22
23 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
24
25 #include "config.h"
26 #include "system.h"
27
28 #include "jcf.h"
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31
32 /* This is true if the user specified a `.java' file on the command
33 line. Otherwise it is 0. FIXME: this is temporary, until our
34 .java parser is fully working. */
35 int saw_java_source = 0;
36
37 /* DOS brain-damage */
38 #ifndef O_BINARY
39 #define O_BINARY 0 /* MS-DOS brain-damage */
40 #endif
41
42 int
43 DEFUN(jcf_unexpected_eof, (jcf, count),
44 JCF *jcf AND int count)
45 {
46 if (jcf->filename)
47 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
48 else
49 fprintf (stderr, "Premature end of .class file <stdin>.\n");
50 exit (-1);
51 }
52
53 void
54 DEFUN(jcf_trim_old_input, (jcf),
55 JCF *jcf)
56 {
57 int count = jcf->read_ptr - jcf->buffer;
58 if (count > 0)
59 {
60 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
61 jcf->read_ptr -= count;
62 jcf->read_end -= count;
63 }
64 }
65
66 int
67 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
68 JCF *jcf AND int count)
69 {
70 FILE *file = (FILE*) (jcf->read_state);
71 if (count > jcf->buffer_end - jcf->read_ptr)
72 {
73 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
74 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
75 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
76 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
77 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
78 : REALLOC (jcf->buffer, new_size);
79 jcf->buffer = new_buffer;
80 jcf->buffer_end = new_buffer + new_size;
81 jcf->read_ptr = new_buffer + old_read_ptr;
82 jcf->read_end = new_buffer + old_read_end;
83 }
84 count -= jcf->read_end - jcf->read_ptr;
85 if (count <= 0)
86 return 0;
87 if (fread (jcf->read_end, 1, count, file) != count)
88 jcf_unexpected_eof (jcf, count);
89 jcf->read_end += count;
90 return 0;
91 }
92
93 #include "zipfile.h"
94
95 struct ZipFileCache *SeenZipFiles = NULL;
96
97 int
98 DEFUN(open_in_zip, (jcf, zipfile, zipmember),
99 JCF *jcf AND const char *zipfile AND const char *zipmember
100 AND int is_system)
101 {
102 struct ZipFileCache* zipf;
103 ZipDirectory *zipd;
104 int i, len;
105 for (zipf = SeenZipFiles; ; zipf = zipf->next)
106 {
107 if (zipf == NULL)
108 {
109 char magic [4];
110 int fd = open (zipfile, O_RDONLY | O_BINARY);
111 jcf_dependency_add_file (zipfile, is_system);
112 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
113 return -1;
114 lseek (fd, 0L, SEEK_SET);
115 zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
116 zipf->next = SeenZipFiles;
117 zipf->name = (char*)(zipf+1);
118 strcpy (zipf->name, zipfile);
119 SeenZipFiles = zipf;
120 zipf->z.fd = fd;
121 if (fd == -1)
122 {
123 /* A missing zip file is not considered an error. */
124 zipf->z.count = 0;
125 zipf->z.dir_size = 0;
126 zipf->z.central_directory = NULL;
127 return -1;
128 }
129 else
130 {
131 if (read_zip_archive (&zipf->z) != 0)
132 return -2; /* This however should be an error - FIXME */
133 }
134 break;
135 }
136 if (strcmp (zipf->name, zipfile) == 0)
137 break;
138 }
139
140 if (!zipmember)
141 return 0;
142
143 len = strlen (zipmember);
144
145 zipd = (struct ZipDirectory*) zipf->z.central_directory;
146 for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd))
147 {
148 if (len == zipd->filename_length &&
149 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
150 {
151 JCF_ZERO (jcf);
152 jcf->buffer = ALLOC (zipd->size);
153 jcf->buffer_end = jcf->buffer + zipd->size;
154 jcf->read_ptr = jcf->buffer;
155 jcf->read_end = jcf->buffer_end;
156 jcf->filbuf = jcf_unexpected_eof;
157 jcf->filename = strdup (zipfile);
158 jcf->classname = strdup (zipmember);
159 jcf->zipd = (void *)zipd;
160 if (lseek (zipf->z.fd, zipd->filestart, 0) < 0
161 || read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size)
162 return -2;
163 return 0;
164 }
165 }
166 return -1;
167 }
168
169 #if JCF_USE_STDIO
170 char*
171 DEFUN(open_class, (filename, jcf, stream, dep_name),
172 char *filename AND JCF *jcf AND FILE* stream AND char *dep_name)
173 {
174 if (jcf)
175 {
176 if (dep_name != NULL)
177 jcf_dependency_add_file (dep_name, 0);
178 JCF_ZERO (jcf);
179 jcf->buffer = NULL;
180 jcf->buffer_end = NULL;
181 jcf->read_ptr = NULL;
182 jcf->read_end = NULL;
183 jcf->read_state = stream;
184 jcf->filbuf = jcf_filbuf_from_stdio;
185 }
186 else
187 fclose (stream);
188 return filename;
189 }
190 #else
191 char*
192 DEFUN(open_class, (filename, jcf, fd, dep_name),
193 char *filename AND JCF *jcf AND int fd AND char *dep_name)
194 {
195 if (jcf)
196 {
197 struct stat stat_buf;
198 if (fstat (fd, &stat_buf) != 0
199 || ! S_ISREG (stat_buf.st_mode))
200 {
201 perror ("Could not figure length of .class file");
202 return NULL;
203 }
204 if (dep_name != NULL)
205 jcf_dependency_add_file (dep_name, 0);
206 JCF_ZERO (jcf);
207 jcf->buffer = ALLOC (stat_buf.st_size);
208 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
209 jcf->read_ptr = jcf->buffer;
210 jcf->read_end = jcf->buffer_end;
211 jcf->read_state = NULL;
212 jcf->filename = filename;
213 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
214 {
215 perror ("Failed to read .class file");
216 return NULL;
217 }
218 close (fd);
219 jcf->filbuf = jcf_unexpected_eof;
220 }
221 else
222 close (fd);
223 return filename;
224 }
225 #endif
226
227
228 char *
229 DEFUN(find_classfile, (filename, jcf, dep_name),
230 char *filename AND JCF *jcf AND char *dep_name)
231 {
232 #if JCF_USE_STDIO
233 FILE *stream = fopen (filename, "rb");
234 if (stream == NULL)
235 return NULL;
236 return open_class (arg, jcf, stream, dep_name);
237 #else
238 int fd = open (filename, O_RDONLY | O_BINARY);
239 if (fd < 0)
240 return NULL;
241 return open_class (filename, jcf, fd, dep_name);
242 #endif
243 }
244
245 /* Returns a freshly malloc'd string with the fully qualified pathname
246 of the .class file for the class CLASSNAME. Returns NULL on
247 failure. If JCF != NULL, it is suitably initialized. With
248 DO_CLASS_FILE set to 1, search a .class/.java file named after
249 CLASSNAME, otherwise, search a ZIP directory entry named after
250 CLASSNAME. */
251
252 char *
253 DEFUN(find_class, (classname, classname_length, jcf, do_class_file),
254 const char *classname AND int classname_length AND JCF *jcf AND int do_class_file)
255
256 {
257 #if JCF_USE_STDIO
258 FILE *stream;
259 #else
260 int fd;
261 #endif
262 int i, k, java, class;
263 struct stat java_buf, class_buf;
264 char *dep_file;
265 void *entry, *java_entry;
266 char *java_buffer;
267
268 /* Allocate and zero out the buffer, since we don't explicitly put a
269 null pointer when we're copying it below. */
270 int buflen = jcf_path_max_len () + classname_length + 10;
271 char *buffer = (char *) ALLOC (buflen);
272 bzero (buffer, buflen);
273
274 java_buffer = (char *) alloca (buflen);
275
276 jcf->java_source = jcf->outofsynch = 0;
277
278 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
279 {
280 int dir_len;
281
282 strcpy (buffer, jcf_path_name (entry));
283 i = strlen (buffer);
284
285 dir_len = i - 1;
286
287 for (k = 0; k < classname_length; k++, i++)
288 {
289 char ch = classname[k];
290 buffer[i] = ch == '.' ? '/' : ch;
291 }
292 if (do_class_file)
293 strcpy (buffer+i, ".class");
294
295 if (jcf_path_is_zipfile (entry))
296 {
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 jcf_path_is_system (entry));
311 if (err_code == 0)
312 {
313 if (!do_class_file)
314 jcf->seen_in_zip = 1;
315 else
316 {
317 buffer[dir_len] = '(';
318 strcpy (buffer+i, ".class)");
319 }
320 if (jcf == &_jcf)
321 JCF_FINISH (jcf);
322 return buffer;
323 }
324 else
325 continue;
326 }
327
328 /* If we do directories, do them here */
329 if (!do_class_file)
330 {
331 struct stat dir_buff;
332 int dir;
333 buffer[i] = '\0'; /* Was previously unterminated here. */
334 if (!(dir = stat (buffer, &dir_buff)))
335 {
336 jcf->seen_in_zip = 0;
337 goto found;
338 }
339 }
340
341 class = stat (buffer, &class_buf);
342 /* This is a little odd: if we didn't find the class file, we
343 can just skip to the next iteration. However, if this is the
344 last iteration, then we want to search for the .java file as
345 well. It was a little easier to implement this with two
346 loops, as opposed to checking for each type of file each time
347 through the loop. */
348 if (class && jcf_path_next (entry))
349 continue;
350
351 /* Check for out of synch .class/.java files. */
352 java = 1;
353 for (java_entry = jcf_path_start ();
354 java && java_entry != NULL;
355 java_entry = jcf_path_next (java_entry))
356 {
357 int m, l;
358
359 if (jcf_path_is_zipfile (java_entry))
360 continue;
361
362 /* Compute name of .java file. */
363 strcpy (java_buffer, jcf_path_name (java_entry));
364 l = strlen (java_buffer);
365 for (m = 0; m < classname_length; ++m)
366 {
367 java_buffer[m + l] = (classname[m] == '.'
368 ? '/'
369 : classname[m]);
370 }
371 strcpy (java_buffer + m + l, ".java");
372
373 /* FIXME: until the `.java' parser is fully working, we only
374 look for a .java file when one was mentioned on the
375 command line. This lets us test the .java parser fairly
376 easily, without compromising our ability to use the
377 .class parser without fear. */
378 if (saw_java_source)
379 java = stat (java_buffer, &java_buf);
380 }
381
382 if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
383 jcf->outofsynch = 1;
384
385 if (! java)
386 dep_file = java_buffer;
387 else
388 dep_file = buffer;
389 #if JCF_USE_STDIO
390 if (!class)
391 {
392 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
393 stream = fopen (buffer, "rb");
394 if (stream)
395 goto found;
396 }
397 /* Give .java a try, if necessary */
398 if (!java)
399 {
400 strcpy (buffer, java_buffer);
401 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
402 stream = fopen (buffer, "r");
403 if (stream)
404 {
405 jcf->java_source = 1;
406 goto found;
407 }
408 }
409 #else
410 if (!class)
411 {
412 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
413 fd = open (buffer, O_RDONLY | O_BINARY);
414 if (fd >= 0)
415 goto found;
416 }
417 /* Give .java a try, if necessary */
418 if (!java)
419 {
420 strcpy (buffer, java_buffer);
421 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
422 fd = open (buffer, O_RDONLY);
423 if (fd >= 0)
424 {
425 jcf->java_source = 1;
426 goto found;
427 }
428 }
429 #endif
430 }
431 free (buffer);
432 return NULL;
433 found:
434 #if JCF_USE_STDIO
435 if (jcf->java_source)
436 return NULL; /* FIXME */
437 else
438 return open_class (buffer, jcf, stream, dep_file);
439 #else
440 if (jcf->java_source)
441 {
442 JCF_ZERO (jcf); /* JCF_FINISH relies on this */
443 jcf->java_source = 1;
444 jcf->filename = (char *) strdup (buffer);
445 close (fd); /* We use STDIO for source file */
446 }
447 else if (do_class_file)
448 buffer = open_class (buffer, jcf, fd, dep_file);
449 jcf->classname = (char *) ALLOC (classname_length + 1);
450 strncpy (jcf->classname, classname, classname_length + 1);
451 jcf->classname = (char *) strdup (classname);
452 return buffer;
453 #endif
454 }
455
456 void
457 DEFUN(jcf_print_char, (stream, ch),
458 FILE *stream AND int ch)
459 {
460 switch (ch)
461 {
462 case '\'':
463 case '\\':
464 case '\"':
465 fprintf (stream, "\\%c", ch);
466 break;
467 case '\n':
468 fprintf (stream, "\\n");
469 break;
470 case '\t':
471 fprintf (stream, "\\t");
472 break;
473 case '\r':
474 fprintf (stream, "\\r");
475 break;
476 default:
477 if (ch >= ' ' && ch < 127)
478 putc (ch, stream);
479 else if (ch < 256)
480 fprintf (stream, "\\%03x", ch);
481 else
482 fprintf (stream, "\\u%04x", ch);
483 }
484 }
485
486 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
487
488 void
489 DEFUN(jcf_print_utf8, (stream, str, length),
490 FILE *stream AND register unsigned char *str AND int length)
491 {
492 unsigned char* limit = str + length;
493 while (str < limit)
494 {
495 int ch = UTF8_GET (str, limit);
496 if (ch < 0)
497 {
498 fprintf (stream, "\\<invalid>");
499 return;
500 }
501 jcf_print_char (stream, ch);
502 }
503 }
504
505 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
506
507 void
508 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
509 FILE *stream AND unsigned char *str AND int length
510 AND int in_char AND int out_char)
511 {
512
513 int i;/* FIXME - actually handle Unicode! */
514 for (i = 0; i < length; i++)
515 {
516 int ch = str[i];
517 jcf_print_char (stream, ch == in_char ? out_char : ch);
518 }
519 }
520
521 /* Check that all the cross-references in the constant pool are
522 valid. Returns 0 on success.
523 Otherwise, returns the index of the (first) invalid entry. */
524
525 int
526 DEFUN(verify_constant_pool, (jcf),
527 JCF *jcf)
528 {
529 int i, n;
530 for (i = 1; i < JPOOL_SIZE (jcf); i++)
531 {
532 switch (JPOOL_TAG (jcf, i))
533 {
534 case CONSTANT_NameAndType:
535 n = JPOOL_USHORT2 (jcf, i);
536 if (n <= 0 || n >= JPOOL_SIZE(jcf)
537 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
538 return i;
539 /* ... fall through ... */
540 case CONSTANT_Class:
541 case CONSTANT_String:
542 n = JPOOL_USHORT1 (jcf, i);
543 if (n <= 0 || n >= JPOOL_SIZE(jcf)
544 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
545 return i;
546 break;
547 case CONSTANT_Fieldref:
548 case CONSTANT_Methodref:
549 case CONSTANT_InterfaceMethodref:
550 n = JPOOL_USHORT1 (jcf, i);
551 if (n <= 0 || n >= JPOOL_SIZE(jcf)
552 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
553 return i;
554 n = JPOOL_USHORT2 (jcf, i);
555 if (n <= 0 || n >= JPOOL_SIZE(jcf)
556 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
557 return i;
558 break;
559 case CONSTANT_Long:
560 case CONSTANT_Double:
561 i++;
562 break;
563 case CONSTANT_Float:
564 case CONSTANT_Integer:
565 case CONSTANT_Utf8:
566 case CONSTANT_Unicode:
567 break;
568 default:
569 return i;
570 }
571 }
572 return 0;
573 }
574
575 void
576 DEFUN(format_uint, (buffer, value, base),
577 char *buffer AND uint64 value AND int base)
578 {
579 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
580 char buf[WRITE_BUF_SIZE];
581 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
582 int chars_written;
583 int i;
584
585 /* Now do the actual conversion, placing the result at the *end* of buf. */
586 /* Note this code does not pretend to be optimized. */
587 do {
588 int digit = value % base;
589 static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
590 *--buf_ptr = digit_chars[digit];
591 value /= base;
592 } while (value != 0);
593
594 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
595 for (i = 0; i < chars_written; i++)
596 buffer[i] = *buf_ptr++;
597 buffer[i] = 0;
598 }
599
600 void
601 DEFUN(format_int, (buffer, value, base),
602 char *buffer AND jlong value AND int base)
603 {
604 uint64 abs_value;
605 if (value < 0)
606 {
607 abs_value = -(uint64)value;
608 *buffer++ = '-';
609 }
610 else
611 abs_value = (uint64) value;
612 format_uint (buffer, abs_value, base);
613 }
This page took 0.065642 seconds and 5 git commands to generate.