OSDN Git Service

869bc002da65cd3b984b863e5fdf4a703adf2ee8
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-io.c
1 /* Utility routines for finding and reading Java(TM) .class files.
2    Copyright (C) 1996, 97-98, 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 /* DOS brain-damage */
34 #ifndef O_BINARY
35 #define O_BINARY 0 /* MS-DOS brain-damage */
36 #endif
37
38 int
39 DEFUN(jcf_unexpected_eof, (jcf, count),
40       JCF *jcf AND int count ATTRIBUTE_UNUSED)
41 {
42   if (jcf->filename)
43     fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
44   else
45     fprintf (stderr, "Premature end of .class file <stdin>.\n");
46   exit (-1);
47 }
48
49 void
50 DEFUN(jcf_trim_old_input, (jcf),
51       JCF *jcf)
52 {
53   int count = jcf->read_ptr - jcf->buffer;
54   if (count > 0)
55     {
56       memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
57       jcf->read_ptr -= count;
58       jcf->read_end -= count;
59     }
60 }
61
62 int
63 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
64       JCF *jcf AND int count)
65 {
66   FILE *file = (FILE*) (jcf->read_state);
67   if (count > jcf->buffer_end - jcf->read_ptr)
68     {
69       JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
70       JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
71       JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
72       JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
73       unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
74         : REALLOC (jcf->buffer, new_size);
75       jcf->buffer = new_buffer;
76       jcf->buffer_end = new_buffer + new_size;
77       jcf->read_ptr = new_buffer + old_read_ptr;
78       jcf->read_end = new_buffer + old_read_end;
79     }
80   count -= jcf->read_end - jcf->read_ptr;
81   if (count <= 0)
82     return 0;
83   if ((int) fread (jcf->read_end, 1, count, file) != count)
84     jcf_unexpected_eof (jcf, count);
85   jcf->read_end += count;
86   return 0;
87 }
88
89 #include "zipfile.h"
90
91 struct ZipFileCache *SeenZipFiles = NULL;
92
93 /* Open a zip file with the given name, and cache directory and file
94    descriptor.  If the file is missing, treat it as an empty archive.
95    Return NULL if the .zip file is malformed.
96 */
97
98 ZipFile *
99 DEFUN(opendir_in_zip, (zipfile, is_system),
100       const char *zipfile AND int is_system)
101 {
102   struct ZipFileCache* zipf;
103   char magic [4];
104   int fd;
105   for (zipf = SeenZipFiles;  zipf != NULL;  zipf = zipf->next)
106     {
107       if (strcmp (zipf->name, zipfile) == 0)
108         return &zipf->z;
109     }
110
111   zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1);
112   zipf->next = SeenZipFiles;
113   zipf->name = (char*)(zipf+1);
114   strcpy (zipf->name, zipfile);
115   SeenZipFiles = zipf;
116   fd = open (zipfile, O_RDONLY | O_BINARY);
117   zipf->z.fd = fd;
118   if (fd < 0)
119     {
120       /* A missing zip file is not considered an error.
121        We may want to re-consider that.  FIXME. */
122       zipf->z.count = 0;
123       zipf->z.dir_size = 0;
124       zipf->z.central_directory = NULL;
125     }
126   else
127     {
128       jcf_dependency_add_file (zipfile, is_system);
129       if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
130         return NULL;
131       lseek (fd, 0L, SEEK_SET);
132       if (read_zip_archive (&zipf->z) != 0)
133         return NULL;
134     }
135   return &zipf->z;
136 }
137
138 /* Returns:
139    0:  OK - zipmember found.
140    -1: Not found.
141    -2: Malformed archive.
142 */
143
144 int
145 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
146       JCF *jcf AND const char *zipfile AND const char *zipmember
147       AND int is_system)
148 {
149   ZipDirectory *zipd;
150   int i, len;
151   ZipFile *zipf = opendir_in_zip (zipfile, is_system);
152
153   if (zipf == NULL)
154     return -2;
155
156   if (!zipmember)
157     return 0;
158
159   len = strlen (zipmember);
160   
161   zipd = (struct ZipDirectory*) zipf->central_directory;
162   for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
163     {
164       if (len == zipd->filename_length &&
165           strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
166         {
167           JCF_ZERO (jcf);
168           jcf->buffer = ALLOC (zipd->size);
169           jcf->buffer_end = jcf->buffer + zipd->size;
170           jcf->read_ptr = jcf->buffer;
171           jcf->read_end = jcf->buffer_end;
172           jcf->filbuf = jcf_unexpected_eof;
173           jcf->filename = xstrdup (zipfile);
174           jcf->classname = xstrdup (zipmember);
175           jcf->zipd = (void *)zipd;
176           if (lseek (zipf->fd, zipd->filestart, 0) < 0
177               || read (zipf->fd, jcf->buffer, zipd->size) != zipd->size)
178             return -2;
179           return 0;
180         }
181     }
182   return -1;
183 }
184
185 #if JCF_USE_STDIO
186 char*
187 DEFUN(open_class, (filename, jcf, stream, dep_name),
188       char *filename AND JCF *jcf AND FILE* stream AND const char *dep_name)
189 {
190   if (jcf)
191     {
192       if (dep_name != NULL)
193         jcf_dependency_add_file (dep_name, 0);
194       JCF_ZERO (jcf);
195       jcf->buffer = NULL;
196       jcf->buffer_end = NULL;
197       jcf->read_ptr = NULL;
198       jcf->read_end = NULL;
199       jcf->read_state = stream;
200       jcf->filbuf = jcf_filbuf_from_stdio;
201     }
202   else
203     fclose (stream);
204   return filename;
205 }
206 #else
207 char*
208 DEFUN(open_class, (filename, jcf, fd, dep_name),
209       char *filename AND JCF *jcf AND int fd AND const char *dep_name)
210 {
211   if (jcf)
212     {
213       struct stat stat_buf;
214       if (fstat (fd, &stat_buf) != 0
215           || ! S_ISREG (stat_buf.st_mode))
216         {
217           perror ("Could not figure length of .class file");
218           return NULL;
219         }
220       if (dep_name != NULL)
221         jcf_dependency_add_file (dep_name, 0);
222       JCF_ZERO (jcf);
223       jcf->buffer = ALLOC (stat_buf.st_size);
224       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
225       jcf->read_ptr = jcf->buffer;
226       jcf->read_end = jcf->buffer_end;
227       jcf->read_state = NULL;
228       jcf->filename = filename;
229       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
230         {
231           perror ("Failed to read .class file");
232           return NULL;
233         }
234       close (fd);
235       jcf->filbuf = jcf_unexpected_eof;
236     }
237   else
238     close (fd);
239   return filename;
240 }
241 #endif
242
243
244 const char *
245 DEFUN(find_classfile, (filename, jcf, dep_name),
246       char *filename AND JCF *jcf AND const char *dep_name)
247 {
248 #if JCF_USE_STDIO
249   FILE *stream = fopen (filename, "rb");
250   if (stream == NULL)
251     return NULL;
252   return open_class (arg, jcf, stream, dep_name);
253 #else
254   int fd = open (filename, O_RDONLY | O_BINARY);
255   if (fd < 0)
256     return NULL;
257   return open_class (filename, jcf, fd, dep_name);
258 #endif
259 }
260
261 /* Returns a freshly malloc'd string with the fully qualified pathname
262    of the .class file for the class CLASSNAME.  Returns NULL on
263    failure.  If JCF != NULL, it is suitably initialized.
264    SOURCE_OK is true if we should also look for .java file. */
265
266 const char *
267 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
268       const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
269
270 {
271 #if JCF_USE_STDIO
272   FILE *stream;
273 #else
274   int fd;
275 #endif
276   int i, k, java = -1, class = -1;
277   struct stat java_buf, class_buf;
278   char *dep_file;
279   void *entry;
280   char *java_buffer;
281
282   /* Allocate and zero out the buffer, since we don't explicitly put a
283      null pointer when we're copying it below.  */
284   int buflen = jcf_path_max_len () + classname_length + 10;
285   char *buffer = (char *) ALLOC (buflen);
286   bzero (buffer, buflen);
287
288   java_buffer = (char *) alloca (buflen);
289
290   jcf->java_source = 0;
291
292   for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
293     {
294       const char *path_name = jcf_path_name (entry);
295       if (class != 0)
296         {
297           int dir_len;
298
299           strcpy (buffer, path_name);
300           i = strlen (buffer);
301
302           /* This is right because we know that `.zip' entries will have a
303              trailing slash.  See jcf-path.c.  */
304           dir_len = i - 1;
305
306           for (k = 0; k < classname_length; k++, i++)
307             {
308               char ch = classname[k];
309               buffer[i] = ch == '.' ? '/' : ch;
310             }
311           strcpy (buffer+i, ".class");
312
313           if (jcf_path_is_zipfile (entry))
314             {
315               int err_code;
316               JCF _jcf;
317               buffer[dir_len] = '\0';
318               SOURCE_FRONTEND_DEBUG 
319                 (("Trying [...%s]:%s", 
320                   &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 
321                   buffer+dir_len+1));
322               if (jcf == NULL)
323                 jcf = &_jcf;
324               err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
325                                       jcf_path_is_system (entry));
326               if (err_code == 0)
327                 {
328                   /* Should we check if .zip is out-of-date wrt .java? */
329                   buffer[dir_len] = '(';
330                   strcpy (buffer+i, ".class)");
331                   if (jcf == &_jcf)
332                     JCF_FINISH (jcf);
333                   return buffer;
334                 }
335               else
336                 continue;
337             }
338           class = stat (buffer, &class_buf);
339         }
340
341       if (source_ok)
342         {
343           /* Compute name of .java file.  */
344           int l, m;
345           strcpy (java_buffer, path_name);
346           l = strlen (java_buffer);
347           for (m = 0; m < classname_length; ++m)
348             java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
349           strcpy (java_buffer + m + l, ".java");
350           java = stat (java_buffer, &java_buf);
351           if (java == 0)
352             break;
353         }
354     }
355
356   /* We preferably pick a class file if we have a chance. If the source
357      file is newer than the class file, we issue a warning and parse the
358      source file instead.
359      There should be a flag to allow people have the class file picked
360      up no matter what. FIXME. */
361   if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
362     {
363       char *stripped_class_name = xstrdup (classname);
364       int i = strlen (stripped_class_name);
365       
366       while (stripped_class_name [i] != '.')
367         i--;
368       
369       stripped_class_name [i] = '\0';
370       warning ("Source file for class `%s' is newer than its matching class file. Source file used instead", stripped_class_name);
371       free (stripped_class_name);
372       class = -1;
373     }
374
375   if (! java)
376     dep_file = java_buffer;
377   else
378     dep_file = buffer;
379 #if JCF_USE_STDIO
380   if (!class)
381     {
382       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
383       stream = fopen (buffer, "rb");
384       if (stream)
385         goto found;
386     }
387   /* Give .java a try, if necessary */
388   if (!java)
389     {
390       strcpy (buffer, java_buffer);
391       SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
392       stream = fopen (buffer, "r");
393       if (stream)
394         {
395           jcf->java_source = 1;
396           goto found;
397         }
398     }
399 #else
400   if (!class)
401     {
402       SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
403                               classname+classname_length-
404                               (classname_length <= 30 ? 
405                                classname_length : 30)));
406       fd = open (buffer, O_RDONLY | O_BINARY);
407       if (fd >= 0)
408         goto found;
409     }
410   /* Give .java a try, if necessary */
411   if (!java)
412     {
413       strcpy (buffer, java_buffer);
414       SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
415                               classname+classname_length-
416                               (classname_length <= 30 ? 
417                                classname_length : 30)));
418       fd = open (buffer, O_RDONLY);
419       if (fd >= 0)
420         {
421           jcf->java_source = 1;
422           goto found;
423         }
424     }
425 #endif
426
427   free (buffer);
428   return NULL;
429  found:
430 #if JCF_USE_STDIO
431   if (jcf->java_source)
432     return NULL;                /* FIXME */
433   else
434     return open_class (buffer, jcf, stream, dep_file);
435 #else
436   if (jcf->java_source)
437     {
438       JCF_ZERO (jcf);           /* JCF_FINISH relies on this */
439       jcf->java_source = 1;
440       jcf->filename = xstrdup (buffer);
441       close (fd);               /* We use STDIO for source file */
442     }
443   else
444     buffer = open_class (buffer, jcf, fd, dep_file);
445   jcf->classname = (char *) ALLOC (classname_length + 1);
446   strncpy (jcf->classname, classname, classname_length + 1);
447   jcf->classname = xstrdup (classname);
448   return buffer;
449 #endif
450 }
451
452 void
453 DEFUN(jcf_print_char, (stream, ch),
454       FILE *stream AND int ch)
455 {
456   switch (ch)
457     {
458     case '\'':
459     case '\\':
460     case '\"':
461       fprintf (stream, "\\%c", ch);
462       break;
463     case '\n':
464       fprintf (stream, "\\n");
465       break;
466     case '\t':
467       fprintf (stream, "\\t");
468       break;
469     case '\r':
470       fprintf (stream, "\\r");
471       break;
472     default:
473       if (ch >= ' ' && ch < 127)
474         putc (ch, stream);
475       else if (ch < 256)
476         fprintf (stream, "\\%03x", ch);
477       else
478         fprintf (stream, "\\u%04x", ch);
479     }
480 }
481
482 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
483
484 void
485 DEFUN(jcf_print_utf8, (stream, str, length),
486       FILE *stream AND register const unsigned char *str AND int length)
487 {
488   const unsigned char * limit = str + length;
489   while (str < limit)
490     {
491       int ch = UTF8_GET (str, limit);
492       if (ch < 0)
493         {
494           fprintf (stream, "\\<invalid>");
495           return;
496         }
497       jcf_print_char (stream, ch);
498     }
499 }
500
501 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
502
503 void
504 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
505       FILE *stream AND const unsigned char *str AND int length
506       AND int in_char AND int out_char)
507 {
508   const unsigned char *limit = str + length;
509   while (str < limit)
510     {
511       int ch = UTF8_GET (str, limit);
512       if (ch < 0)
513         {
514           fprintf (stream, "\\<invalid>");
515           return;
516         }
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 }