Avoid including all of <random> in <algorithm>
[official-gcc.git] / gcc / java / jcf-io.c
bloba560db7b53d49c7b4f02b01f150eac4a4b29f9e0
1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996-2016 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>.
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. */
24 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
30 #include "jcf.h"
31 #include <dirent.h>
33 #include "zlib.h"
35 int
36 jcf_unexpected_eof (JCF *jcf, int count ATTRIBUTE_UNUSED)
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);
45 void
46 jcf_trim_old_input (JCF *jcf)
48 int count = jcf->read_ptr - jcf->buffer;
49 if (count > 0)
51 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
52 jcf->read_ptr -= count;
53 jcf->read_end -= count;
57 int
58 jcf_filbuf_from_stdio (JCF *jcf, int count)
60 FILE *file = (FILE*) (jcf->read_state);
61 if (count > jcf->buffer_end - jcf->read_ptr)
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;
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;
84 #include "zipfile.h"
86 struct ZipFile *SeenZipFiles = NULL;
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.
93 ZipFile *
94 opendir_in_zip (const char *zipfile, int is_system)
96 struct ZipFile* zipf;
97 char magic [4];
98 int fd;
99 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
101 if (strcmp (zipf->name, zipfile) == 0)
102 return zipf;
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)
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;
119 else
121 jcf_dependency_add_file (zipfile, is_system);
122 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
124 free (zipf);
125 close (fd);
126 return NULL;
128 lseek (fd, 0L, SEEK_SET);
129 if (read_zip_archive (zipf) != 0)
131 free (zipf);
132 close (fd);
133 return NULL;
137 SeenZipFiles = zipf;
138 return zipf;
141 /* Returns:
142 0: OK - zipmember found.
143 -1: Not found.
144 -2: Malformed archive.
148 open_in_zip (JCF *jcf, const char *zipfile, const char *zipmember,
149 int is_system)
151 ZipDirectory *zipd;
152 int i, len;
153 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
155 if (zipf == NULL)
156 return -2;
158 if (!zipmember)
159 return 0;
161 len = strlen (zipmember);
163 zipd = (struct ZipDirectory*) zipf->central_directory;
164 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
166 if (len == zipd->filename_length &&
167 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
169 JCF_ZERO (jcf);
171 jcf->filename = xstrdup (zipfile);
172 jcf->classname = xstrdup (zipmember);
173 return read_zip_member(jcf, zipd, zipf);
176 return -1;
179 /* Read data from zip archive member. */
182 read_zip_member (JCF *jcf, ZipDirectory *zipd, ZipFile *zipf)
184 jcf->filbuf = jcf_unexpected_eof;
185 jcf->zipd = zipd;
187 if (zipd->compression_method == Z_NO_COMPRESSION)
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;
197 else
199 char *buffer;
200 z_stream d_stream; /* decompression stream */
201 memset (&d_stream, 0, sizeof (d_stream));
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);
223 return 0;
226 const char *
227 open_class (const char *filename, JCF *jcf, int fd, const char *dep_name)
229 if (jcf)
231 struct stat stat_buf;
232 if (fstat (fd, &stat_buf) != 0
233 || ! S_ISREG (stat_buf.st_mode))
235 perror ("Could not figure length of .class file");
236 return NULL;
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)
249 perror ("Failed to read .class file");
250 return NULL;
252 close (fd);
253 jcf->filbuf = jcf_unexpected_eof;
255 else
256 close (fd);
257 return filename;
261 const char *
262 find_classfile (char *filename, JCF *jcf, const char *dep_name)
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);
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;
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. */
283 const char *
284 find_class (const char *classname, int classname_length, JCF *jcf)
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;
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);
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;
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);
311 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
313 const char *path_name = jcf_path_name (entry);
314 if (klass != 0)
316 int dir_len;
318 strcpy (buffer, path_name);
319 i = strlen (buffer);
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;
325 for (k = 0; k < classname_length; k++, i++)
327 char ch = classname[k];
328 buffer[i] = ch == '.' ? '/' : ch;
330 strcpy (buffer+i, ".class");
332 if (jcf_path_is_zipfile (entry))
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)
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;
354 else
355 continue;
357 klass = stat (buffer, &class_buf);
361 dep_file = buffer;
362 if (!klass)
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;
373 free (buffer);
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;
380 return NULL;
381 found:
383 const char *const tmp = open_class (buffer, jcf, fd, dep_file);
384 jcf->classname = xstrdup (classname);
385 return tmp;
389 void
390 jcf_print_char (FILE *stream, int ch)
392 switch (ch)
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);
418 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
420 void
421 jcf_print_utf8 (FILE *stream, const unsigned char *str, int length)
423 const unsigned char * limit = str + length;
424 while (str < limit)
426 int ch = UTF8_GET (str, limit);
427 if (ch < 0)
429 fprintf (stream, "\\<invalid>");
430 return;
432 jcf_print_char (stream, ch);
436 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
438 void
439 jcf_print_utf8_replace (FILE *stream, const unsigned char *str, int length,
440 int in_char, int out_char)
442 const unsigned char *limit = str + length;
443 while (str < limit)
445 int ch = UTF8_GET (str, limit);
446 if (ch < 0)
448 fprintf (stream, "\\<invalid>");
449 return;
451 jcf_print_char (stream, ch == in_char ? out_char : ch);
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.*/
462 verify_constant_pool (JCF *jcf)
464 int i, n;
465 for (i = 1; i < JPOOL_SIZE (jcf); i++)
467 switch (JPOOL_TAG (jcf, i))
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;
527 return 0;
530 void
531 format_uint (char *buffer, uint64 value, int base)
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;
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);
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;
554 void
555 format_int (char *buffer, jlong value, int base)
557 uint64 abs_value;
558 if (value < 0)
560 abs_value = -(uint64)value;
561 *buffer++ = '-';
563 else
564 abs_value = (uint64) value;
565 format_uint (buffer, abs_value, base);