a560db7b53d49c7b4f02b01f150eac4a4b29f9e0
[platform/upstream/gcc.git] / gcc / java / jcf-io.c
1 /* Utility routines for finding and reading Java(TM) .class files.
2    Copyright (C) 1996-2016 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  
19
20 Java and all Java-based marks are trademarks or registered trademarks
21 of Sun Microsystems, Inc. in the United States and other countries.
22 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
23
24 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29
30 #include "jcf.h"
31 #include <dirent.h>
32
33 #include "zlib.h"
34
35 int
36 jcf_unexpected_eof (JCF *jcf, int count ATTRIBUTE_UNUSED)
37 {
38   if (jcf->filename)
39     fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
40   else
41     fprintf (stderr, "Premature end of .class file <stdin>.\n");
42   exit (-1);
43 }
44
45 void
46 jcf_trim_old_input (JCF *jcf)
47 {
48   int count = jcf->read_ptr - jcf->buffer;
49   if (count > 0)
50     {
51       memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
52       jcf->read_ptr -= count;
53       jcf->read_end -= count;
54     }
55 }
56
57 int
58 jcf_filbuf_from_stdio (JCF *jcf, int count)
59 {
60   FILE *file = (FILE*) (jcf->read_state);
61   if (count > jcf->buffer_end - jcf->read_ptr)
62     {
63       JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
64       JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
65       JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
66       JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
67       unsigned char *new_buffer
68         = jcf->buffer == NULL ? XNEWVAR (unsigned char, new_size)
69         : XRESIZEVAR (unsigned char, jcf->buffer, new_size);
70       jcf->buffer = new_buffer;
71       jcf->buffer_end = new_buffer + new_size;
72       jcf->read_ptr = new_buffer + old_read_ptr;
73       jcf->read_end = new_buffer + old_read_end;
74     }
75   count -= jcf->read_end - jcf->read_ptr;
76   if (count <= 0)
77     return 0;
78   if ((int) fread (jcf->read_end, 1, count, file) != count)
79     jcf_unexpected_eof (jcf, count);
80   jcf->read_end += count;
81   return 0;
82 }
83
84 #include "zipfile.h"
85
86 struct ZipFile *SeenZipFiles = NULL;
87
88 /* Open a zip file with the given name, and cache directory and file
89    descriptor.  If the file is missing, treat it as an empty archive.
90    Return NULL if the .zip file is malformed.
91 */
92
93 ZipFile *
94 opendir_in_zip (const char *zipfile, int is_system)
95 {
96   struct ZipFile* zipf;
97   char magic [4];
98   int fd;
99   for (zipf = SeenZipFiles;  zipf != NULL;  zipf = zipf->next)
100     {
101       if (strcmp (zipf->name, zipfile) == 0)
102         return zipf;
103     }
104
105   zipf = XNEWVAR (struct ZipFile, sizeof (struct ZipFile) + strlen (zipfile) + 1);
106   zipf->next = SeenZipFiles;
107   zipf->name = (char*)(zipf+1);
108   strcpy (zipf->name, zipfile);
109   fd = open (zipfile, O_RDONLY | O_BINARY);
110   zipf->fd = fd;
111   if (fd < 0)
112     {
113       /* A missing zip file is not considered an error.
114        We may want to re-consider that.  FIXME. */
115       zipf->count = 0;
116       zipf->dir_size = 0;
117       zipf->central_directory = NULL;
118     }
119   else
120     {
121       jcf_dependency_add_file (zipfile, is_system);
122       if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
123         {
124           free (zipf);
125           close (fd);
126           return NULL;
127         }
128       lseek (fd, 0L, SEEK_SET);
129       if (read_zip_archive (zipf) != 0)
130         {
131           free (zipf);
132           close (fd);
133           return NULL;
134         }
135     }
136
137   SeenZipFiles = zipf;  
138   return zipf;
139 }
140
141 /* Returns:
142    0:  OK - zipmember found.
143    -1: Not found.
144    -2: Malformed archive.
145 */
146
147 int
148 open_in_zip (JCF *jcf, const char *zipfile, const char *zipmember,
149              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 read_zip_member (JCF *jcf,  ZipDirectory *zipd, ZipFile *zipf)
183 {
184   jcf->filbuf = jcf_unexpected_eof;
185   jcf->zipd = zipd;
186
187   if (zipd->compression_method == Z_NO_COMPRESSION)
188     {
189       jcf->buffer = XNEWVEC (unsigned char, zipd->size);
190       jcf->buffer_end = jcf->buffer + zipd->size;
191       jcf->read_ptr = jcf->buffer;
192       jcf->read_end = jcf->buffer_end;
193       if (lseek (zipf->fd, zipd->filestart, 0) < 0
194           || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
195         return -2;
196     }
197   else
198     {
199       char *buffer;
200       z_stream d_stream; /* decompression stream */
201       memset (&d_stream, 0, sizeof (d_stream));
202
203       jcf->buffer = XNEWVEC (unsigned char, zipd->uncompressed_size);
204       d_stream.next_out = jcf->buffer;
205       d_stream.avail_out = zipd->uncompressed_size;
206       jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
207       jcf->read_ptr = jcf->buffer;
208       jcf->read_end = jcf->buffer_end;
209       buffer = XNEWVEC (char, zipd->size);
210       d_stream.next_in = (unsigned char *) buffer;
211       d_stream.avail_in = zipd->size;
212       if (lseek (zipf->fd, zipd->filestart, 0) < 0
213           || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
214         return -2;
215       /* Handle NO_HEADER using undocumented zlib feature.
216          This is a very common hack.  */
217       inflateInit2 (&d_stream, -MAX_WBITS);
218       inflate (&d_stream, Z_NO_FLUSH);
219       inflateEnd (&d_stream);
220       free (buffer);
221     }
222
223   return 0;
224 }
225
226 const char *
227 open_class (const char *filename, JCF *jcf, int fd, const char *dep_name)
228 {
229   if (jcf)
230     {
231       struct stat stat_buf;
232       if (fstat (fd, &stat_buf) != 0
233           || ! S_ISREG (stat_buf.st_mode))
234         {
235           perror ("Could not figure length of .class file");
236           return NULL;
237         }
238       if (dep_name != NULL)
239         jcf_dependency_add_file (dep_name, 0);
240       JCF_ZERO (jcf);
241       jcf->buffer = XNEWVEC (unsigned char, stat_buf.st_size);
242       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
243       jcf->read_ptr = jcf->buffer;
244       jcf->read_end = jcf->buffer_end;
245       jcf->read_state = NULL;
246       jcf->filename = xstrdup (filename);
247       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
248         {
249           perror ("Failed to read .class file");
250           return NULL;
251         }
252       close (fd);
253       jcf->filbuf = jcf_unexpected_eof;
254     }
255   else
256     close (fd);
257   return filename;
258 }
259
260
261 const char *
262 find_classfile (char *filename, JCF *jcf, const char *dep_name)
263 {
264   int fd = open (filename, O_RDONLY | O_BINARY);
265   if (fd < 0)
266     return NULL;
267   return open_class (filename, jcf, fd, dep_name);
268 }
269
270 /* A hash table keeping track of class names that were not found
271    during class lookup.  (There is no need to cache the values
272    associated with names that were found; they are saved in
273    IDENTIFIER_CLASS_VALUE.)  */
274 static hash_table<nofree_string_hash> *memoized_class_lookups;
275
276 /* Returns a freshly malloc'd string with the fully qualified pathname
277    of the .class file for the class CLASSNAME.  CLASSNAME must be
278    allocated in permanent storage; this function may retain a pointer
279    to it.  Returns NULL on failure.  If JCF != NULL, it is suitably
280    initialized.  SOURCE_OK is true if we should also look for .java
281    file. */
282
283 const char *
284 find_class (const char *classname, int classname_length, JCF *jcf)
285 {
286   int fd;
287   int i, k, klass = -1;
288   struct stat class_buf;
289   char *dep_file;
290   void *entry;
291   int buflen;
292   char *buffer;
293   hashval_t hash;
294
295   /* Create the hash table, if it does not already exist.  */
296   if (!memoized_class_lookups)
297     memoized_class_lookups = new hash_table<nofree_string_hash> (37);
298
299   /* Loop for this class in the hashtable.  If it is present, we've
300      already looked for this class and failed to find it.  */
301   hash = nofree_string_hash::hash (classname);
302   if (memoized_class_lookups->find_with_hash (classname, hash))
303     return NULL;
304
305   /* Allocate and zero out the buffer, since we don't explicitly put a
306      null pointer when we're copying it below.  */
307   buflen = jcf_path_max_len () + classname_length + 10;
308   buffer = XNEWVAR (char, buflen);
309   memset (buffer, 0, buflen);
310
311   for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
312     {
313       const char *path_name = jcf_path_name (entry);
314       if (klass != 0)
315         {
316           int dir_len;
317
318           strcpy (buffer, path_name);
319           i = strlen (buffer);
320
321           /* This is right because we know that `.zip' entries will have a
322              trailing slash.  See jcf-path.c.  */
323           dir_len = i - 1;
324
325           for (k = 0; k < classname_length; k++, i++)
326             {
327               char ch = classname[k];
328               buffer[i] = ch == '.' ? '/' : ch;
329             }
330           strcpy (buffer+i, ".class");
331
332           if (jcf_path_is_zipfile (entry))
333             {
334               int err_code;
335               JCF _jcf;
336               buffer[dir_len] = '\0';
337               SOURCE_FRONTEND_DEBUG 
338                 (("Trying [...%s]:%s", 
339                   &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 
340                   buffer+dir_len+1));
341               if (jcf == NULL)
342                 jcf = &_jcf;
343               err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
344                                       jcf_path_is_system (entry));
345               if (err_code == 0)
346                 {
347                   /* Should we check if .zip is out-of-date wrt .java? */
348                   buffer[dir_len] = '(';
349                   strcpy (buffer+i, ".class)");
350                   if (jcf == &_jcf)
351                     JCF_FINISH (jcf);
352                   return buffer;
353                 }
354               else
355                 continue;
356             }
357           klass = stat (buffer, &class_buf);
358         }
359     }
360
361   dep_file = buffer;
362   if (!klass)
363     {
364       SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
365                               classname+classname_length-
366                               (classname_length <= 30 ? 
367                                classname_length : 30)));
368       fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY | O_BINARY);
369       if (fd >= 0)
370         goto found;
371     }
372
373   free (buffer);
374
375   /* Remember that this class could not be found so that we do not
376      have to look again.  */
377   *memoized_class_lookups->find_slot_with_hash (classname, hash, INSERT)
378     = classname;
379
380   return NULL;
381  found:
382   {
383     const char *const tmp = open_class (buffer, jcf, fd, dep_file);
384     jcf->classname = xstrdup (classname);
385     return tmp;
386   }
387 }
388
389 void
390 jcf_print_char (FILE *stream, int ch)
391 {
392   switch (ch)
393     {
394     case '\'':
395     case '\\':
396     case '\"':
397       fprintf (stream, "\\%c", ch);
398       break;
399     case '\n':
400       fprintf (stream, "\\n");
401       break;
402     case '\t':
403       fprintf (stream, "\\t");
404       break;
405     case '\r':
406       fprintf (stream, "\\r");
407       break;
408     default:
409       if (ch >= ' ' && ch < 127)
410         putc (ch, stream);
411       else if (ch < 256)
412         fprintf (stream, "\\%03x", ch);
413       else
414         fprintf (stream, "\\u%04x", ch);
415     }
416 }
417
418 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
419
420 void
421 jcf_print_utf8 (FILE *stream, const unsigned char *str, int length)
422 {
423   const unsigned char * limit = str + length;
424   while (str < limit)
425     {
426       int ch = UTF8_GET (str, limit);
427       if (ch < 0)
428         {
429           fprintf (stream, "\\<invalid>");
430           return;
431         }
432       jcf_print_char (stream, ch);
433     }
434 }
435
436 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
437
438 void
439 jcf_print_utf8_replace (FILE *stream, const unsigned char *str, int length,
440                         int in_char, int out_char)
441 {
442   const unsigned char *limit = str + length;
443   while (str < limit)
444     {
445       int ch = UTF8_GET (str, limit);
446       if (ch < 0)
447         {
448           fprintf (stream, "\\<invalid>");
449           return;
450         }
451       jcf_print_char (stream, ch == in_char ? out_char : ch);
452     }
453 }
454
455 /* Check that all the cross-references in the constant pool are
456    valid.  Returns 0 on success.
457    Otherwise, returns the index of the (first) invalid entry.
458    Only checks internal consistency, but does not check that
459    any classes, fields, or methods are valid.*/
460
461 int
462 verify_constant_pool (JCF *jcf)
463 {
464   int i, n;
465   for (i = 1; i < JPOOL_SIZE (jcf); i++)
466     {
467       switch (JPOOL_TAG (jcf, i))
468         {
469         case CONSTANT_NameAndType:
470           n = JPOOL_USHORT2 (jcf, i);
471           if (n <= 0 || n >= JPOOL_SIZE(jcf)
472               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
473             return i;
474           /* ... fall through ... */
475         case CONSTANT_Class:
476         case CONSTANT_String:
477           n = JPOOL_USHORT1 (jcf, i);
478           if (n <= 0 || n >= JPOOL_SIZE(jcf)
479               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
480             return i;
481           break;
482         case CONSTANT_Fieldref:
483         case CONSTANT_Methodref:
484         case CONSTANT_InterfaceMethodref:
485           n = JPOOL_USHORT1 (jcf, i);
486           if (n <= 0 || n >= JPOOL_SIZE(jcf)
487               || JPOOL_TAG (jcf, n) != CONSTANT_Class)
488             return i;
489           n = JPOOL_USHORT2 (jcf, i);
490           if (n <= 0 || n >= JPOOL_SIZE(jcf)
491               || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
492             return i;
493           break;
494         case CONSTANT_Long:
495         case CONSTANT_Double:
496           i++;
497           break;
498         case CONSTANT_Float:
499         case CONSTANT_Integer:
500         case CONSTANT_Utf8:
501         case CONSTANT_Unicode:
502           break;
503         case CONSTANT_MethodHandle:
504           n = JPOOL_USHORT1 (jcf, i);
505           if (n < 1 || n > 9)
506             return i;
507           n = JPOOL_USHORT2 (jcf, i);
508           if (n <= 0 || n >= JPOOL_SIZE(jcf))
509             return i;
510           break;
511         case CONSTANT_MethodType:
512           n = JPOOL_USHORT1 (jcf, i);
513           if (n <= 0 || n >= JPOOL_SIZE(jcf)
514               || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
515             return i;
516           break;
517         case CONSTANT_InvokeDynamic:
518           n = JPOOL_USHORT2 (jcf, i);
519           if (n <= 0 || n >= JPOOL_SIZE(jcf)
520               || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
521             return i;
522           break;
523         default:
524           return i;
525         }
526     }
527   return 0;
528 }
529
530 void
531 format_uint (char *buffer, uint64 value, int base)
532 {
533 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
534   char buf[WRITE_BUF_SIZE];
535   char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
536   int chars_written;
537   int i;
538
539   /* Now do the actual conversion, placing the result at the *end* of buf. */
540   /* Note this code does not pretend to be optimized. */
541   do {
542     int digit = value % base;
543     static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
544     *--buf_ptr = digit_chars[digit];
545     value /= base;
546   } while (value != 0);
547
548   chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
549   for (i = 0; i < chars_written; i++)
550     buffer[i] = *buf_ptr++;
551   buffer[i] = 0;
552 }
553
554 void
555 format_int (char *buffer, jlong value, int base)
556 {
557   uint64 abs_value;
558   if (value < 0)
559     {
560       abs_value = -(uint64)value;
561       *buffer++ = '-';
562     }
563   else
564     abs_value = (uint64) value;
565   format_uint (buffer, abs_value, base);
566 }