OSDN Git Service

* jcf-write.c (write_classfile): Add output class file as target.
[pf3gnuchains/gcc-fork.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 #define ENABLE_UNZIP 1
29
30 #include "jcf.h"
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33
34 /* DOS brain-damage */
35 #ifndef O_BINARY
36 #define O_BINARY 0 /* MS-DOS brain-damage */
37 #endif
38
39 char *classpath;
40
41 int
42 DEFUN(jcf_unexpected_eof, (jcf, count),
43       JCF *jcf AND int count)
44 {
45   if (jcf->filename)
46     fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
47   else
48     fprintf (stderr, "Premature end of .class file <stdin>.\n");
49   exit (-1);
50 }
51
52 void
53 DEFUN(jcf_trim_old_input, (jcf),
54       JCF *jcf)
55 {
56   int count = jcf->read_ptr - jcf->buffer;
57   if (count > 0)
58     {
59       memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
60       jcf->read_ptr -= count;
61       jcf->read_end -= count;
62     }
63 }
64
65 int
66 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
67       JCF *jcf AND int count)
68 {
69   FILE *file = (FILE*) (jcf->read_state);
70   if (count > jcf->buffer_end - jcf->read_ptr)
71     {
72       JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
73       JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
74       JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
75       JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
76       unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
77         : REALLOC (jcf->buffer, new_size);
78       jcf->buffer = new_buffer;
79       jcf->buffer_end = new_buffer + new_size;
80       jcf->read_ptr = new_buffer + old_read_ptr;
81       jcf->read_end = new_buffer + old_read_end;
82     }
83   count -= jcf->read_end - jcf->read_ptr;
84   if (count <= 0)
85     return 0;
86   if (fread (jcf->read_end, 1, count, file) != count)
87     jcf_unexpected_eof (jcf, count);
88   jcf->read_end += count;
89   return 0;
90 }
91
92 #if ENABLE_UNZIP
93 #include "zipfile.h"
94
95 struct ZipFileCache *SeenZipFiles = NULL;
96
97 int
98 DEFUN(open_in_zip, (jcf, 
99 zipfile, zipmember),
100       JCF *jcf AND const char *zipfile AND const char *zipmember)
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, 0); /* FIXME: system file? */
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 #endif /* ENABLE_UNZIP */
169
170 #if JCF_USE_STDIO
171 char*
172 DEFUN(open_class, (filename, jcf, stream, dep_name),
173       char *filename AND JCF *jcf AND FILE* stream AND char *dep_name)
174 {
175   if (jcf)
176     {
177       if (dep_name != NULL)
178         jcf_dependency_add_file (dep_name, 0);
179       JCF_ZERO (jcf);
180       jcf->buffer = NULL;
181       jcf->buffer_end = NULL;
182       jcf->read_ptr = NULL;
183       jcf->read_end = NULL;
184       jcf->read_state = stream;
185       jcf->filbuf = jcf_filbuf_from_stdio;
186     }
187   else
188     fclose (stream);
189   return filename;
190 }
191 #else
192 char*
193 DEFUN(open_class, (filename, jcf, fd, dep_name),
194       char *filename AND JCF *jcf AND int fd AND char *dep_name)
195 {
196   if (jcf)
197     {
198       struct stat stat_buf;
199       if (fstat (fd, &stat_buf) != 0
200           || ! S_ISREG (stat_buf.st_mode))
201         {
202           perror ("Could not figure length of .class file");
203           return NULL;
204         }
205       if (dep_name != NULL)
206         jcf_dependency_add_file (dep_name, 0);
207       JCF_ZERO (jcf);
208       jcf->buffer = ALLOC (stat_buf.st_size);
209       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
210       jcf->read_ptr = jcf->buffer;
211       jcf->read_end = jcf->buffer_end;
212       jcf->read_state = NULL;
213       jcf->filename = filename;
214       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
215         {
216           perror ("Failed to read .class file");
217           return NULL;
218         }
219       close (fd);
220       jcf->filbuf = jcf_unexpected_eof;
221     }
222   else
223     close (fd);
224   return filename;
225 }
226 #endif
227
228
229 char *
230 DEFUN(find_classfile, (filename, jcf, dep_name),
231       char *filename AND JCF *jcf AND char *dep_name)
232 {
233 #if JCF_USE_STDIO
234   FILE *stream = fopen (filename, "rb");
235   if (stream == NULL)
236     return NULL;
237   return open_class (arg, jcf, stream, dep_name);
238 #else
239   int fd = open (filename, O_RDONLY | O_BINARY);
240   if (fd < 0)
241     return NULL;
242   return open_class (filename, jcf, fd, dep_name);
243 #endif
244 }
245
246 /* Returns a freshly malloc'd string with the fully qualified pathname
247    of the .class file for the class CLASSNAME.  Returns NULL on
248    failure.  If JCF != NULL, it is suitably initialized.  With
249    DO_CLASS_FILE set to 1, search a .class/.java file named after
250    CLASSNAME, otherwise, search a ZIP directory entry named after
251    CLASSNAME.  */
252
253 char *
254 DEFUN(find_class, (classname, classname_length, jcf, do_class_file),
255       const char *classname AND int classname_length AND JCF *jcf AND int do_class_file)
256
257 {
258 #if JCF_USE_STDIO
259   FILE *stream;
260 #else
261   int fd;
262 #endif
263   int i, j, k, java, class;
264   struct stat java_buf, class_buf;
265   char *dep_file;
266
267   /* A temporary buffer that we grow to be large enough to hold
268      whatever class name we're working on.  */
269   static int temp_len = 0;
270   static char *temp_buffer = NULL;
271
272   /* Allocate and zero out the buffer, since we don't explicitly put a
273      null pointer when we're copying it below.  */
274   int buflen = strlen (classpath) + classname_length + 10;
275   char *buffer = (char *) ALLOC (buflen);
276   bzero (buffer, buflen);
277
278   if (buflen > temp_len)
279     {
280       temp_len = buflen;
281       if (temp_buffer == NULL)
282         temp_buffer = (char *) ALLOC (temp_len);
283       else
284         temp_buffer = (char *) REALLOC (temp_buffer, temp_len);
285     }
286
287   jcf->java_source = jcf->outofsynch = 0;
288   for (j = 0; classpath[j] != '\0'; )
289     {
290       for (i = 0; classpath[j] != ':' && classpath[j] != '\0'; i++, j++)
291         buffer[i] = classpath[j];
292       if (classpath[j] == ':')
293         j++;
294       if (i > 0)  /* Empty directory is redundant */
295         {
296           int dir_len;
297           if (buffer[i-1] != '/')
298             buffer[i++] = '/';
299           dir_len = i-1;
300           for (k = 0; k < classname_length; k++, i++)
301             {
302               char ch = classname[k];
303               buffer[i] = ch == '.' ? '/' : ch;
304             }
305           if (do_class_file)
306             strcpy (buffer+i, ".class");
307 #if ENABLE_UNZIP
308           if (dir_len > 4
309               && buffer[dir_len-4] == '.' && buffer[dir_len-3] == 'z'
310               && buffer[dir_len-2] == 'i' && buffer[dir_len-1] == 'p')
311             {
312               int err_code;
313               JCF _jcf;
314               if (!do_class_file)
315                 strcpy (buffer+i, "/");
316               buffer[dir_len] = '\0';
317               if (do_class_file)
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               if (err_code == 0)
326                 {
327                   if (!do_class_file)
328                     jcf->seen_in_zip = 1;
329                   else
330                     {
331                       buffer[dir_len] = '(';
332                       strcpy (buffer+i, ".class)");
333                     }
334                   if (jcf == &_jcf)
335                     JCF_FINISH (jcf);
336                   return buffer;
337                 }
338               else
339                 continue;
340             }
341 #endif
342           /* If we do directories, do them here */
343           if (!do_class_file)
344             {
345               struct stat dir_buff;
346               int dir;
347               buffer[i] = '\0'; /* Was previously unterminated here. */
348               if (!(dir = stat (buffer, &dir_buff)))
349                 {
350                   jcf->seen_in_zip = 0;
351                   goto found;
352                 }
353             }
354
355           /* Check for out of synch .class/.java files */
356           class = stat (buffer, &class_buf);
357           strcpy (buffer+i, ".java");
358           /* Stash the name of the .java file in the temp buffer.  */
359           strcpy (temp_buffer, buffer);
360           java = stat (buffer, &java_buf);
361           if ((!java && !class) && java_buf.st_mtime >= class_buf.st_mtime)
362             jcf->outofsynch = 1;
363
364           if (! java)
365             dep_file = temp_buffer;
366           else
367             dep_file = buffer;
368 #if JCF_USE_STDIO
369           if (!class)
370             {
371               strcpy (buffer+i, ".class");
372               SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
373               stream = fopen (buffer, "rb");
374               if (stream)
375                 goto found;
376             }
377           /* Give .java a try, if necessary */
378           if (!java)
379             {
380               strcpy (buffer+i, ".java");
381               SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
382               stream = fopen (buffer, "r");
383               if (stream)
384                 {
385                   jcf->java_source = 1;
386                   goto found;
387                 }
388             }
389 #else
390           if (!class)
391             {
392               strcpy (buffer+i, ".class");
393               SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
394               fd = open (buffer, O_RDONLY | O_BINARY);
395               if (fd >= 0)
396                 goto found;
397             }
398           /* Give .java a try, if necessary */
399           if (!java)
400             {
401               if (do_class_file)
402                 strcpy (buffer+i, ".java");
403               SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
404               fd = open (buffer, O_RDONLY | O_BINARY);
405               if (fd >= 0)
406                 {
407                   jcf->java_source = 1;
408                   goto found;
409                 }
410             }
411 #endif
412         }
413     }
414   free (buffer);
415   return NULL;
416  found:
417 #if JCF_USE_STDIO
418   if (jcf->java_source)
419     return NULL;                /* FIXME */
420   else
421     return open_class (buffer, jcf, stream, dep_file);
422 #else
423   if (jcf->java_source)
424     {
425       JCF_ZERO (jcf);           /* JCF_FINISH relies on this */
426       jcf->java_source = 1;
427       jcf->filename = (char *) strdup (buffer);
428       close (fd);               /* We use STDIO for source file */
429     }
430   else if (do_class_file)
431     buffer = open_class (buffer, jcf, fd, dep_file);
432   jcf->classname = (char *) ALLOC (classname_length + 1);
433   strncpy (jcf->classname, classname, classname_length + 1);
434   jcf->classname = (char *) strdup (classname);
435   return buffer;
436 #endif
437 }
438
439 void
440 DEFUN(jcf_print_char, (stream, ch),
441       FILE *stream AND int ch)
442 {
443   switch (ch)
444     {
445     case '\'':
446     case '\\':
447     case '\"':
448       fprintf (stream, "\\%c", ch);
449       break;
450     case '\n':
451       fprintf (stream, "\\n");
452       break;
453     case '\t':
454       fprintf (stream, "\\t");
455       break;
456     case '\r':
457       fprintf (stream, "\\r");
458       break;
459     default:
460       if (ch >= ' ' && ch < 127)
461         putc (ch, stream);
462       else if (ch < 256)
463         fprintf (stream, "\\%03x", ch);
464       else
465         fprintf (stream, "\\u%04x", ch);
466     }
467 }
468
469 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
470
471 void
472 DEFUN(jcf_print_utf8, (stream, str, length),
473       FILE *stream AND register unsigned char *str AND int length)
474 {
475   unsigned char* limit = str + length;
476   while (str < limit)
477     {
478       int ch = UTF8_GET (str, limit);
479       if (ch < 0)
480         {
481           fprintf (stream, "\\<invalid>");
482           return;
483         }
484       jcf_print_char (stream, ch);
485     }
486 }
487
488 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
489
490 void
491 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
492       FILE *stream AND unsigned char *str AND int length
493       AND int in_char AND int out_char)
494 {
495
496   int i;/* FIXME - actually handle Unicode! */
497   for (i = 0; i < length; i++)
498     {
499       int ch = str[i];
500       jcf_print_char (stream, ch == in_char ? out_char : ch);
501     }
502 }
503
504 /* Check that all the cross-references in the constant pool are
505    valid.  Returns 0 on success.
506    Otherwise, returns the index of the (first) invalid entry. */
507
508 int
509 DEFUN(verify_constant_pool, (jcf),
510       JCF *jcf)
511 {
512   int i, n;
513   for (i = 1; i < JPOOL_SIZE (jcf); i++)
514     {
515       switch (JPOOL_TAG (jcf, i))
516         {
517         case CONSTANT_NameAndType:
518           n = JPOOL_USHORT2 (jcf, i);
519           if (n <= 0 || n >= JPOOL_SIZE(jcf)
520               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
521             return i;
522           /* ... fall through ... */
523         case CONSTANT_Class:
524         case CONSTANT_String:
525           n = JPOOL_USHORT1 (jcf, i);
526           if (n <= 0 || n >= JPOOL_SIZE(jcf)
527               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
528             return i;
529           break;
530         case CONSTANT_Fieldref:
531         case CONSTANT_Methodref:
532         case CONSTANT_InterfaceMethodref:
533           n = JPOOL_USHORT1 (jcf, i);
534           if (n <= 0 || n >= JPOOL_SIZE(jcf)
535               || JPOOL_TAG (jcf, n) != CONSTANT_Class)
536             return i;
537           n = JPOOL_USHORT2 (jcf, i);
538           if (n <= 0 || n >= JPOOL_SIZE(jcf)
539               || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
540             return i;
541           break;
542         case CONSTANT_Long:
543         case CONSTANT_Double:
544           i++;
545           break;
546         case CONSTANT_Float:
547         case CONSTANT_Integer:
548         case CONSTANT_Utf8:
549         case CONSTANT_Unicode:
550           break;
551         default:
552           return i;
553         }
554     }
555   return 0;
556 }
557
558 void
559 DEFUN(format_uint, (buffer, value, base),
560       char *buffer AND uint64 value AND int base)
561 {
562 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
563   char buf[WRITE_BUF_SIZE];
564   register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
565   int chars_written;
566   int i;
567
568   /* Now do the actual conversion, placing the result at the *end* of buf. */
569   /* Note this code does not pretend to be optimized. */
570   do {
571     int digit = value % base;
572     static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
573     *--buf_ptr = digit_chars[digit];
574     value /= base;
575   } while (value != 0);
576
577   chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
578   for (i = 0; i < chars_written; i++)
579     buffer[i] = *buf_ptr++;
580   buffer[i] = 0;
581 }
582
583 void
584 DEFUN(format_int, (buffer, value, base),
585       char *buffer AND jlong value AND int base)
586 {
587   uint64 abs_value;
588   if (value < 0)
589     {
590       abs_value = -(uint64)value;
591       *buffer++ = '-';
592     }
593   else
594     abs_value = (uint64) value;
595   format_uint (buffer, abs_value, base);
596 }