]> gcc.gnu.org Git - gcc.git/blame - gcc/java/jcf-io.c
[multiple changes]
[gcc.git] / gcc / java / jcf-io.c
CommitLineData
e04a16fb 1/* Utility routines for finding and reading Java(TM) .class files.
fc45c7ef 2 Copyright (C) 1996, 1998 Free Software Foundation, Inc.
e04a16fb
AG
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2, or (at your option)
7any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with GNU CC; see the file COPYING. If not, write to
16the Free Software Foundation, 59 Temple Place - Suite 330,
17Boston, MA 02111-1307, USA.
18
19Java and all Java-based marks are trademarks or registered trademarks
20of Sun Microsystems, Inc. in the United States and other countries.
21The Free Software Foundation is independent of Sun Microsystems, Inc. */
22
23/* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
24
1f43f4b4
JL
25#include "config.h"
26#include "system.h"
e04a16fb 27
e04a16fb 28#include "jcf.h"
e04a16fb
AG
29#include <sys/stat.h>
30#include <sys/wait.h>
e04a16fb 31
257fafbb
TT
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. */
35int saw_java_source = 0;
36
e04a16fb
AG
37/* DOS brain-damage */
38#ifndef O_BINARY
39#define O_BINARY 0 /* MS-DOS brain-damage */
40#endif
41
e04a16fb
AG
42int
43DEFUN(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
53void
54DEFUN(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
66int
67DEFUN(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
e04a16fb
AG
93#include "zipfile.h"
94
95struct ZipFileCache *SeenZipFiles = NULL;
96
97int
8603f9c5
TT
98DEFUN(open_in_zip, (jcf, zipfile, zipmember),
99 JCF *jcf AND const char *zipfile AND const char *zipmember
100 AND int is_system)
e04a16fb
AG
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);
8603f9c5 111 jcf_dependency_add_file (zipfile, is_system);
e04a16fb
AG
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;
1f43f4b4
JL
157 jcf->filename = strdup (zipfile);
158 jcf->classname = strdup (zipmember);
e04a16fb
AG
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}
e04a16fb
AG
168
169#if JCF_USE_STDIO
170char*
fc45c7ef
TT
171DEFUN(open_class, (filename, jcf, stream, dep_name),
172 char *filename AND JCF *jcf AND FILE* stream AND char *dep_name)
e04a16fb
AG
173{
174 if (jcf)
175 {
fc45c7ef
TT
176 if (dep_name != NULL)
177 jcf_dependency_add_file (dep_name, 0);
e04a16fb
AG
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
191char*
fc45c7ef
TT
192DEFUN(open_class, (filename, jcf, fd, dep_name),
193 char *filename AND JCF *jcf AND int fd AND char *dep_name)
e04a16fb
AG
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 }
fc45c7ef
TT
204 if (dep_name != NULL)
205 jcf_dependency_add_file (dep_name, 0);
e04a16fb
AG
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
228char *
fc45c7ef
TT
229DEFUN(find_classfile, (filename, jcf, dep_name),
230 char *filename AND JCF *jcf AND char *dep_name)
e04a16fb
AG
231{
232#if JCF_USE_STDIO
233 FILE *stream = fopen (filename, "rb");
234 if (stream == NULL)
235 return NULL;
fc45c7ef 236 return open_class (arg, jcf, stream, dep_name);
e04a16fb
AG
237#else
238 int fd = open (filename, O_RDONLY | O_BINARY);
239 if (fd < 0)
240 return NULL;
fc45c7ef 241 return open_class (filename, jcf, fd, dep_name);
e04a16fb
AG
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
252char *
253DEFUN(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
8603f9c5 262 int i, k, java, class;
e04a16fb 263 struct stat java_buf, class_buf;
fc45c7ef 264 char *dep_file;
8603f9c5
TT
265 void *entry, *java_entry;
266 char *java_buffer;
e04a16fb
AG
267
268 /* Allocate and zero out the buffer, since we don't explicitly put a
269 null pointer when we're copying it below. */
8603f9c5 270 int buflen = jcf_path_max_len () + classname_length + 10;
e04a16fb
AG
271 char *buffer = (char *) ALLOC (buflen);
272 bzero (buffer, buflen);
273
8603f9c5 274 java_buffer = (char *) alloca (buflen);
fc45c7ef 275
e04a16fb 276 jcf->java_source = jcf->outofsynch = 0;
8603f9c5
TT
277
278 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
e04a16fb 279 {
8603f9c5
TT
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++)
e04a16fb 288 {
8603f9c5
TT
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';
e04a16fb 302 if (do_class_file)
8603f9c5
TT
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)
e04a16fb 312 {
e04a16fb 313 if (!do_class_file)
8603f9c5 314 jcf->seen_in_zip = 1;
e04a16fb 315 else
e04a16fb 316 {
8603f9c5
TT
317 buffer[dir_len] = '(';
318 strcpy (buffer+i, ".class)");
e04a16fb 319 }
8603f9c5
TT
320 if (jcf == &_jcf)
321 JCF_FINISH (jcf);
322 return buffer;
e04a16fb 323 }
fc45c7ef 324 else
8603f9c5
TT
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)))
e04a16fb 335 {
8603f9c5
TT
336 jcf->seen_in_zip = 0;
337 goto found;
e04a16fb 338 }
8603f9c5
TT
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;
8603f9c5
TT
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)
e04a16fb 366 {
8603f9c5
TT
367 java_buffer[m + l] = (classname[m] == '.'
368 ? '/'
369 : classname[m]);
e04a16fb 370 }
8603f9c5
TT
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)
e04a16fb 404 {
8603f9c5
TT
405 jcf->java_source = 1;
406 goto found;
e04a16fb 407 }
8603f9c5
TT
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)
e04a16fb 424 {
8603f9c5
TT
425 jcf->java_source = 1;
426 goto found;
e04a16fb 427 }
e04a16fb 428 }
8603f9c5 429#endif
e04a16fb
AG
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
fc45c7ef 438 return open_class (buffer, jcf, stream, dep_file);
e04a16fb
AG
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)
fc45c7ef 448 buffer = open_class (buffer, jcf, fd, dep_file);
e04a16fb
AG
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
456void
457DEFUN(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
488void
489DEFUN(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
507void
508DEFUN(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
525int
526DEFUN(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
575void
576DEFUN(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
600void
601DEFUN(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.118932 seconds and 5 git commands to generate.