OSDN Git Service

* builtins.c (expand_builtin_setjmp_receiver): Const-ify.
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-io.c
1 /* Utility routines for finding and reading Java(TM) .class files.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000  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 "tree.h"
30 #include "toplev.h"
31 #include "java-tree.h"
32
33 #include "zlib.h"
34
35 /* DOS brain-damage */
36 #ifndef O_BINARY
37 #define O_BINARY 0 /* MS-DOS brain-damage */
38 #endif
39
40 int
41 DEFUN(jcf_unexpected_eof, (jcf, count),
42       JCF *jcf AND int count ATTRIBUTE_UNUSED)
43 {
44   if (jcf->filename)
45     fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
46   else
47     fprintf (stderr, "Premature end of .class file <stdin>.\n");
48   exit (-1);
49 }
50
51 void
52 DEFUN(jcf_trim_old_input, (jcf),
53       JCF *jcf)
54 {
55   int count = jcf->read_ptr - jcf->buffer;
56   if (count > 0)
57     {
58       memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
59       jcf->read_ptr -= count;
60       jcf->read_end -= count;
61     }
62 }
63
64 int
65 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
66       JCF *jcf AND int count)
67 {
68   FILE *file = (FILE*) (jcf->read_state);
69   if (count > jcf->buffer_end - jcf->read_ptr)
70     {
71       JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
72       JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
73       JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
74       JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
75       unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
76         : REALLOC (jcf->buffer, new_size);
77       jcf->buffer = new_buffer;
78       jcf->buffer_end = new_buffer + new_size;
79       jcf->read_ptr = new_buffer + old_read_ptr;
80       jcf->read_end = new_buffer + old_read_end;
81     }
82   count -= jcf->read_end - jcf->read_ptr;
83   if (count <= 0)
84     return 0;
85   if ((int) fread (jcf->read_end, 1, count, file) != count)
86     jcf_unexpected_eof (jcf, count);
87   jcf->read_end += count;
88   return 0;
89 }
90
91 #include "zipfile.h"
92
93 struct ZipFile *SeenZipFiles = NULL;
94
95 /* Open a zip file with the given name, and cache directory and file
96    descriptor.  If the file is missing, treat it as an empty archive.
97    Return NULL if the .zip file is malformed.
98 */
99
100 ZipFile *
101 DEFUN(opendir_in_zip, (zipfile, is_system),
102       const char *zipfile AND int is_system)
103 {
104   struct ZipFile* zipf;
105   char magic [4];
106   int fd;
107   for (zipf = SeenZipFiles;  zipf != NULL;  zipf = zipf->next)
108     {
109       if (strcmp (zipf->name, zipfile) == 0)
110         return zipf;
111     }
112
113   zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1);
114   zipf->next = SeenZipFiles;
115   zipf->name = (char*)(zipf+1);
116   strcpy (zipf->name, zipfile);
117   SeenZipFiles = zipf;
118   fd = open (zipfile, O_RDONLY | O_BINARY);
119   zipf->fd = fd;
120   if (fd < 0)
121     {
122       /* A missing zip file is not considered an error.
123        We may want to re-consider that.  FIXME. */
124       zipf->count = 0;
125       zipf->dir_size = 0;
126       zipf->central_directory = NULL;
127     }
128   else
129     {
130       jcf_dependency_add_file (zipfile, is_system);
131       if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
132         return NULL;
133       lseek (fd, 0L, SEEK_SET);
134       if (read_zip_archive (zipf) != 0)
135         return NULL;
136     }
137   return zipf;
138 }
139
140 /* Returns:
141    0:  OK - zipmember found.
142    -1: Not found.
143    -2: Malformed archive.
144 */
145
146 int
147 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
148       JCF *jcf AND const char *zipfile AND const char *zipmember
149       AND int is_system)
150 {
151   ZipDirectory *zipd;
152   int i, len;
153   ZipFile *zipf = opendir_in_zip (zipfile, is_system);
154
155   if (zipf == NULL)
156     return -2;
157
158   if (!zipmember)
159     return 0;
160
161   len = strlen (zipmember);
162   
163   zipd = (struct ZipDirectory*) zipf->central_directory;
164   for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
165     {
166       if (len == zipd->filename_length &&
167           strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
168         {
169           JCF_ZERO (jcf);
170
171           jcf->filename = xstrdup (zipfile);
172           jcf->classname = xstrdup (zipmember);
173           return read_zip_member(jcf, zipd, zipf);
174         }
175     }
176   return -1;
177 }
178
179 /* Read data from zip archive member. */
180
181 int
182 DEFUN(read_zip_member, (jcf, zipd, zipf),
183       JCF *jcf AND  ZipDirectory *zipd AND ZipFile *zipf)
184 {
185           jcf->filbuf = jcf_unexpected_eof;
186           jcf->zipd = (void *)zipd;
187
188           if (zipd->compression_method == Z_NO_COMPRESSION)
189             {
190               jcf->buffer = ALLOC (zipd->size);
191               jcf->buffer_end = jcf->buffer + zipd->size;
192               jcf->read_ptr = jcf->buffer;
193               jcf->read_end = jcf->buffer_end;
194               if (lseek (zipf->fd, zipd->filestart, 0) < 0
195                   || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
196                 return -2;
197             }
198           else
199             {
200               char *buffer;
201               z_stream d_stream; /* decompression stream */
202               d_stream.zalloc = (alloc_func) 0;
203               d_stream.zfree = (free_func) 0;
204               d_stream.opaque = (voidpf) 0;
205
206               jcf->buffer = ALLOC (zipd->uncompressed_size);
207               d_stream.next_out = jcf->buffer;
208               d_stream.avail_out = zipd->uncompressed_size;
209               jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
210               jcf->read_ptr = jcf->buffer;
211               jcf->read_end = jcf->buffer_end;
212               buffer = ALLOC (zipd->size);
213               d_stream.next_in = buffer;
214               d_stream.avail_in = zipd->size;
215               if (lseek (zipf->fd, zipd->filestart, 0) < 0
216                   || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
217                 return -2;
218               /* Handle NO_HEADER using undocumented zlib feature.
219                  This is a very common hack.  */
220               inflateInit2 (&d_stream, -MAX_WBITS);
221               inflate (&d_stream, Z_NO_FLUSH);
222               inflateEnd (&d_stream);
223               FREE (buffer);
224             }
225
226           return 0;
227 }
228
229 #if JCF_USE_STDIO
230 const char *
231 DEFUN(open_class, (filename, jcf, stream, dep_name),
232       const char *filename AND JCF *jcf AND FILE* stream
233       AND const char *dep_name)
234 {
235   if (jcf)
236     {
237       if (dep_name != NULL)
238         jcf_dependency_add_file (dep_name, 0);
239       JCF_ZERO (jcf);
240       jcf->buffer = NULL;
241       jcf->buffer_end = NULL;
242       jcf->read_ptr = NULL;
243       jcf->read_end = NULL;
244       jcf->read_state = stream;
245       jcf->filename = filename;
246       jcf->filbuf = jcf_filbuf_from_stdio;
247     }
248   else
249     fclose (stream);
250   return filename;
251 }
252 #else
253 const char *
254 DEFUN(open_class, (filename, jcf, fd, dep_name),
255       const char *filename AND JCF *jcf AND int fd AND const char *dep_name)
256 {
257   if (jcf)
258     {
259       struct stat stat_buf;
260       if (fstat (fd, &stat_buf) != 0
261           || ! S_ISREG (stat_buf.st_mode))
262         {
263           perror ("Could not figure length of .class file");
264           return NULL;
265         }
266       if (dep_name != NULL)
267         jcf_dependency_add_file (dep_name, 0);
268       JCF_ZERO (jcf);
269       jcf->buffer = ALLOC (stat_buf.st_size);
270       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
271       jcf->read_ptr = jcf->buffer;
272       jcf->read_end = jcf->buffer_end;
273       jcf->read_state = NULL;
274       jcf->filename = filename;
275       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
276         {
277           perror ("Failed to read .class file");
278           return NULL;
279         }
280       close (fd);
281       jcf->filbuf = jcf_unexpected_eof;
282     }
283   else
284     close (fd);
285   return filename;
286 }
287 #endif
288
289
290 const char *
291 DEFUN(find_classfile, (filename, jcf, dep_name),
292       char *filename AND JCF *jcf AND const char *dep_name)
293 {
294 #if JCF_USE_STDIO
295   FILE *stream = fopen (filename, "rb");
296   if (stream == NULL)
297     return NULL;
298   return open_class (arg, jcf, stream, dep_name);
299 #else
300   int fd = open (filename, O_RDONLY | O_BINARY);
301   if (fd < 0)
302     return NULL;
303   return open_class (filename, jcf, fd, dep_name);
304 #endif
305 }
306
307 /* Returns a freshly malloc'd string with the fully qualified pathname
308    of the .class file for the class CLASSNAME.  Returns NULL on
309    failure.  If JCF != NULL, it is suitably initialized.
310    SOURCE_OK is true if we should also look for .java file. */
311
312 const char *
313 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
314       const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
315
316 {
317 #if JCF_USE_STDIO
318   FILE *stream;
319 #else
320   int fd;
321 #endif
322   int i, k, java = -1, class = -1;
323   struct stat java_buf, class_buf;
324   char *dep_file;
325   void *entry;
326   char *java_buffer;
327
328   /* Allocate and zero out the buffer, since we don't explicitly put a
329      null pointer when we're copying it below.  */
330   int buflen = jcf_path_max_len () + classname_length + 10;
331   char *buffer = (char *) ALLOC (buflen);
332   memset (buffer, 0, buflen);
333
334   java_buffer = (char *) alloca (buflen);
335
336   jcf->java_source = 0;
337
338   for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
339     {
340       const char *path_name = jcf_path_name (entry);
341       if (class != 0)
342         {
343           int dir_len;
344
345           strcpy (buffer, path_name);
346           i = strlen (buffer);
347
348           /* This is right because we know that `.zip' entries will have a
349              trailing slash.  See jcf-path.c.  */
350           dir_len = i - 1;
351
352           for (k = 0; k < classname_length; k++, i++)
353             {
354               char ch = classname[k];
355               buffer[i] = ch == '.' ? '/' : ch;
356             }
357           strcpy (buffer+i, ".class");
358
359           if (jcf_path_is_zipfile (entry))
360             {
361               int err_code;
362               JCF _jcf;
363               buffer[dir_len] = '\0';
364               SOURCE_FRONTEND_DEBUG 
365                 (("Trying [...%s]:%s", 
366                   &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 
367                   buffer+dir_len+1));
368               if (jcf == NULL)
369                 jcf = &_jcf;
370               err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
371                                       jcf_path_is_system (entry));
372               if (err_code == 0)
373                 {
374                   /* Should we check if .zip is out-of-date wrt .java? */
375                   buffer[dir_len] = '(';
376                   strcpy (buffer+i, ".class)");
377                   if (jcf == &_jcf)
378                     JCF_FINISH (jcf);
379                   return buffer;
380                 }
381               else
382                 continue;
383             }
384           class = stat (buffer, &class_buf);
385         }
386
387       if (source_ok)
388         {
389           /* Compute name of .java file.  */
390           int l, m;
391           strcpy (java_buffer, path_name);
392           l = strlen (java_buffer);
393           for (m = 0; m < classname_length; ++m)
394             java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
395           strcpy (java_buffer + m + l, ".java");
396           java = stat (java_buffer, &java_buf);
397           if (java == 0)
398             break;
399         }
400     }
401
402   /* We preferably pick a class file if we have a chance. If the source
403      file is newer than the class file, we issue a warning and parse the
404      source file instead.
405      There should be a flag to allow people have the class file picked
406      up no matter what. FIXME. */
407   if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
408     {
409       if (flag_newer)
410         warning ("Source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer);
411       class = -1;
412     }
413
414   if (! java)
415     dep_file = java_buffer;
416   else
417     dep_file = buffer;
418 #if JCF_USE_STDIO
419   if (!class)
420     {
421       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
422       stream = fopen (buffer, "rb");
423       if (stream)
424         goto found;
425     }
426   /* Give .java a try, if necessary */
427   if (!java)
428     {
429       strcpy (buffer, java_buffer);
430       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
431       stream = fopen (buffer, "r");
432       if (stream)
433         {
434           jcf->java_source = 1;
435           goto found;
436         }
437     }
438 #else
439   if (!class)
440     {
441       SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
442                               classname+classname_length-
443                               (classname_length <= 30 ? 
444                                classname_length : 30)));
445       fd = open (buffer, O_RDONLY | O_BINARY);
446       if (fd >= 0)
447         goto found;
448     }
449   /* Give .java a try, if necessary */
450   if (!java)
451     {
452       strcpy (buffer, java_buffer);
453       SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
454                               classname+classname_length-
455                               (classname_length <= 30 ? 
456                                classname_length : 30)));
457       fd = open (buffer, O_RDONLY);
458       if (fd >= 0)
459         {
460           jcf->java_source = 1;
461           goto found;
462         }
463     }
464 #endif
465
466   free (buffer);
467   return NULL;
468  found:
469 #if JCF_USE_STDIO
470   if (jcf->java_source)
471     return NULL;                /* FIXME */
472   else
473     return open_class (buffer, jcf, stream, dep_file);
474 #else
475   if (jcf->java_source)
476     {
477       JCF_ZERO (jcf);           /* JCF_FINISH relies on this */
478       jcf->java_source = 1;
479       jcf->filename = xstrdup (buffer);
480       close (fd);               /* We use STDIO for source file */
481     }
482   else
483     buffer = (char *) open_class (buffer, jcf, fd, dep_file);
484   jcf->classname = xstrdup (classname);
485   return buffer;
486 #endif
487 }
488
489 void
490 DEFUN(jcf_print_char, (stream, ch),
491       FILE *stream AND int ch)
492 {
493   switch (ch)
494     {
495     case '\'':
496     case '\\':
497     case '\"':
498       fprintf (stream, "\\%c", ch);
499       break;
500     case '\n':
501       fprintf (stream, "\\n");
502       break;
503     case '\t':
504       fprintf (stream, "\\t");
505       break;
506     case '\r':
507       fprintf (stream, "\\r");
508       break;
509     default:
510       if (ch >= ' ' && ch < 127)
511         putc (ch, stream);
512       else if (ch < 256)
513         fprintf (stream, "\\%03x", ch);
514       else
515         fprintf (stream, "\\u%04x", ch);
516     }
517 }
518
519 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
520
521 void
522 DEFUN(jcf_print_utf8, (stream, str, length),
523       FILE *stream AND register const unsigned char *str AND int length)
524 {
525   const unsigned char * limit = str + length;
526   while (str < limit)
527     {
528       int ch = UTF8_GET (str, limit);
529       if (ch < 0)
530         {
531           fprintf (stream, "\\<invalid>");
532           return;
533         }
534       jcf_print_char (stream, ch);
535     }
536 }
537
538 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
539
540 void
541 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
542       FILE *stream AND const unsigned char *str AND int length
543       AND int in_char AND int out_char)
544 {
545   const unsigned char *limit = str + length;
546   while (str < limit)
547     {
548       int ch = UTF8_GET (str, limit);
549       if (ch < 0)
550         {
551           fprintf (stream, "\\<invalid>");
552           return;
553         }
554       jcf_print_char (stream, ch == in_char ? out_char : ch);
555     }
556 }
557
558 /* Check that all the cross-references in the constant pool are
559    valid.  Returns 0 on success.
560    Otherwise, returns the index of the (first) invalid entry.
561    Only checks internal consistency, but does not check that
562    any classes, fields, or methods are valid.*/
563
564 int
565 DEFUN(verify_constant_pool, (jcf),
566       JCF *jcf)
567 {
568   int i, n;
569   for (i = 1; i < JPOOL_SIZE (jcf); i++)
570     {
571       switch (JPOOL_TAG (jcf, i))
572         {
573         case CONSTANT_NameAndType:
574           n = JPOOL_USHORT2 (jcf, i);
575           if (n <= 0 || n >= JPOOL_SIZE(jcf)
576               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
577             return i;
578           /* ... fall through ... */
579         case CONSTANT_Class:
580         case CONSTANT_String:
581           n = JPOOL_USHORT1 (jcf, i);
582           if (n <= 0 || n >= JPOOL_SIZE(jcf)
583               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
584             return i;
585           break;
586         case CONSTANT_Fieldref:
587         case CONSTANT_Methodref:
588         case CONSTANT_InterfaceMethodref:
589           n = JPOOL_USHORT1 (jcf, i);
590           if (n <= 0 || n >= JPOOL_SIZE(jcf)
591               || JPOOL_TAG (jcf, n) != CONSTANT_Class)
592             return i;
593           n = JPOOL_USHORT2 (jcf, i);
594           if (n <= 0 || n >= JPOOL_SIZE(jcf)
595               || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
596             return i;
597           break;
598         case CONSTANT_Long:
599         case CONSTANT_Double:
600           i++;
601           break;
602         case CONSTANT_Float:
603         case CONSTANT_Integer:
604         case CONSTANT_Utf8:
605         case CONSTANT_Unicode:
606           break;
607         default:
608           return i;
609         }
610     }
611   return 0;
612 }
613
614 void
615 DEFUN(format_uint, (buffer, value, base),
616       char *buffer AND uint64 value AND int base)
617 {
618 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
619   char buf[WRITE_BUF_SIZE];
620   register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
621   int chars_written;
622   int i;
623
624   /* Now do the actual conversion, placing the result at the *end* of buf. */
625   /* Note this code does not pretend to be optimized. */
626   do {
627     int digit = value % base;
628     static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
629     *--buf_ptr = digit_chars[digit];
630     value /= base;
631   } while (value != 0);
632
633   chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
634   for (i = 0; i < chars_written; i++)
635     buffer[i] = *buf_ptr++;
636   buffer[i] = 0;
637 }
638
639 void
640 DEFUN(format_int, (buffer, value, base),
641       char *buffer AND jlong value AND int base)
642 {
643   uint64 abs_value;
644   if (value < 0)
645     {
646       abs_value = -(uint64)value;
647       *buffer++ = '-';
648     }
649   else
650     abs_value = (uint64) value;
651   format_uint (buffer, abs_value, base);
652 }