OSDN Git Service

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