1/* Utility routines for finding and reading Java(TM) .class files. 2 Copyright (C) 1996, 97-98, 1999 Free Software Foundation, Inc. 3 4This program is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 2, or (at your option) 7any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with GNU CC; see the file COPYING. If not, write to 16the Free Software Foundation, 59 Temple Place - Suite 330, 17Boston, MA 02111-1307, USA. 18 19Java and all Java-based marks are trademarks or registered trademarks 20of Sun Microsystems, Inc. in the United States and other countries. 21The 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 "java-tree.h" 31 32/* DOS brain-damage */ 33#ifndef O_BINARY 34#define O_BINARY 0 /* MS-DOS brain-damage */ 35#endif 36 37int 38DEFUN(jcf_unexpected_eof, (jcf, count), 39 JCF *jcf AND int count ATTRIBUTE_UNUSED) 40{ 41 if (jcf->filename) 42 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename); 43 else 44 fprintf (stderr, "Premature end of .class file <stdin>.\n"); 45 exit (-1); 46} 47 48void 49DEFUN(jcf_trim_old_input, (jcf), 50 JCF *jcf) 51{ 52 int count = jcf->read_ptr - jcf->buffer; 53 if (count > 0) 54 { 55 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr); 56 jcf->read_ptr -= count; 57 jcf->read_end -= count; 58 } 59} 60 61int 62DEFUN(jcf_filbuf_from_stdio, (jcf, count), 63 JCF *jcf AND int count) 64{ 65 FILE *file = (FILE*) (jcf->read_state); 66 if (count > jcf->buffer_end - jcf->read_ptr) 67 { 68 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer; 69 JCF_u4 old_read_end = jcf->read_end - jcf->buffer; 70 JCF_u4 old_size = jcf->buffer_end - jcf->buffer; 71 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count; 72 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size) 73 : REALLOC (jcf->buffer, new_size); 74 jcf->buffer = new_buffer; 75 jcf->buffer_end = new_buffer + new_size; 76 jcf->read_ptr = new_buffer + old_read_ptr; 77 jcf->read_end = new_buffer + old_read_end; 78 } 79 count -= jcf->read_end - jcf->read_ptr; 80 if (count <= 0) 81 return 0; 82 if ((int) fread (jcf->read_end, 1, count, file) != count) 83 jcf_unexpected_eof (jcf, count); 84 jcf->read_end += count; 85 return 0; 86} 87 88#include "zipfile.h" 89 90struct ZipFileCache *SeenZipFiles = NULL; 91 92/* Open a zip file with the given name, and cache directory and file 93 descriptor. If the file is missing, treat it as an empty archive. 94 Return NULL if the .zip file is malformed. 95*/ 96 97ZipFile * 98DEFUN(opendir_in_zip, (zipfile, is_system), 99 const char *zipfile AND int is_system) 100{ 101 struct ZipFileCache* zipf; 102 char magic [4]; 103 int fd; 104 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next) 105 { 106 if (strcmp (zipf->name, zipfile) == 0) 107 return &zipf->z; 108 } 109 110 zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1); 111 zipf->next = SeenZipFiles; 112 zipf->name = (char*)(zipf+1); 113 strcpy (zipf->name, zipfile); 114 SeenZipFiles = zipf; 115 fd = open (zipfile, O_RDONLY | O_BINARY); 116 zipf->z.fd = fd; 117 if (fd < 0) 118 { 119 /* A missing zip file is not considered an error. 120 We may want to re-consider that. FIXME. */ 121 zipf->z.count = 0; 122 zipf->z.dir_size = 0; 123 zipf->z.central_directory = NULL; 124 } 125 else 126 { 127 jcf_dependency_add_file (zipfile, is_system); 128 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC) 129 return NULL; 130 lseek (fd, 0L, SEEK_SET); 131 if (read_zip_archive (&zipf->z) != 0) 132 return NULL; 133 } 134 return &zipf->z; 135} 136 137/* Returns: 138 0: OK - zipmember found. 139 -1: Not found. 140 -2: Malformed archive. 141*/ 142 143int 144DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system), 145 JCF *jcf AND const char *zipfile AND const char *zipmember 146 AND int is_system) 147{ 148 ZipDirectory *zipd; 149 int i, len; 150 ZipFile *zipf = opendir_in_zip (zipfile, is_system); 151 152 if (zipf == NULL) 153 return -2; 154 155 if (!zipmember) 156 return 0; 157 158 len = strlen (zipmember); 159 160 zipd = (struct ZipDirectory*) zipf->central_directory; 161 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd)) 162 { 163 if (len == zipd->filename_length && 164 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0) 165 { 166 JCF_ZERO (jcf); 167 jcf->buffer = ALLOC (zipd->size); 168 jcf->buffer_end = jcf->buffer + zipd->size; 169 jcf->read_ptr = jcf->buffer; 170 jcf->read_end = jcf->buffer_end; 171 jcf->filbuf = jcf_unexpected_eof; 172 jcf->filename = strdup (zipfile); 173 jcf->classname = strdup (zipmember); 174 jcf->zipd = (void *)zipd; 175 if (lseek (zipf->fd, zipd->filestart, 0) < 0 176 || read (zipf->fd, jcf->buffer, zipd->size) != zipd->size) 177 return -2; 178 return 0; 179 } 180 } 181 return -1; 182} 183 184#if JCF_USE_STDIO 185char* 186DEFUN(open_class, (filename, jcf, stream, dep_name), 187 char *filename AND JCF *jcf AND FILE* stream AND const char *dep_name) 188{ 189 if (jcf) 190 { 191 if (dep_name != NULL) 192 jcf_dependency_add_file (dep_name, 0); 193 JCF_ZERO (jcf); 194 jcf->buffer = NULL; 195 jcf->buffer_end = NULL; 196 jcf->read_ptr = NULL; 197 jcf->read_end = NULL; 198 jcf->read_state = stream; 199 jcf->filbuf = jcf_filbuf_from_stdio; 200 } 201 else 202 fclose (stream); 203 return filename; 204} 205#else 206char* 207DEFUN(open_class, (filename, jcf, fd, dep_name), 208 char *filename AND JCF *jcf AND int fd AND const char *dep_name) 209{ 210 if (jcf) 211 { 212 struct stat stat_buf; 213 if (fstat (fd, &stat_buf) != 0 214 || ! S_ISREG (stat_buf.st_mode)) 215 { 216 perror ("Could not figure length of .class file"); 217 return NULL; 218 } 219 if (dep_name != NULL) 220 jcf_dependency_add_file (dep_name, 0); 221 JCF_ZERO (jcf); 222 jcf->buffer = ALLOC (stat_buf.st_size); 223 jcf->buffer_end = jcf->buffer + stat_buf.st_size; 224 jcf->read_ptr = jcf->buffer; 225 jcf->read_end = jcf->buffer_end; 226 jcf->read_state = NULL; 227 jcf->filename = filename; 228 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size) 229 { 230 perror ("Failed to read .class file"); 231 return NULL; 232 } 233 close (fd); 234 jcf->filbuf = jcf_unexpected_eof; 235 } 236 else 237 close (fd); 238 return filename; 239} 240#endif 241 242 243char * 244DEFUN(find_classfile, (filename, jcf, dep_name), 245 char *filename AND JCF *jcf AND const char *dep_name) 246{ 247#if JCF_USE_STDIO 248 FILE *stream = fopen (filename, "rb"); 249 if (stream == NULL) 250 return NULL; 251 return open_class (arg, jcf, stream, dep_name); 252#else 253 int fd = open (filename, O_RDONLY | O_BINARY); 254 if (fd < 0) 255 return NULL; 256 return open_class (filename, jcf, fd, dep_name); 257#endif 258} 259 260/* Returns a freshly malloc'd string with the fully qualified pathname 261 of the .class file for the class CLASSNAME. Returns NULL on 262 failure. If JCF != NULL, it is suitably initialized. 263 SOURCE_OK is true if we should also look for .java file. */ 264 265char * 266DEFUN(find_class, (classname, classname_length, jcf, source_ok), 267 const char *classname AND int classname_length AND JCF *jcf AND int source_ok) 268 269{ 270#if JCF_USE_STDIO 271 FILE *stream; 272#else 273 int fd; 274#endif 275 int i, k, java = -1, class = -1; 276 struct stat java_buf, class_buf; 277 char *dep_file; 278 void *entry; 279 char *java_buffer; 280 281 /* Allocate and zero out the buffer, since we don't explicitly put a 282 null pointer when we're copying it below. */ 283 int buflen = jcf_path_max_len () + classname_length + 10; 284 char *buffer = (char *) ALLOC (buflen); 285 bzero (buffer, buflen); 286 287 java_buffer = (char *) alloca (buflen); 288 289 jcf->java_source = jcf->outofsynch = 0; 290 291 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry)) 292 { 293 char *path_name = jcf_path_name (entry); 294 if (class != 0) 295 { 296 int dir_len; 297 298 strcpy (buffer, path_name); 299 i = strlen (buffer); 300 301 /* This is right because we know that `.zip' entries will have a 302 trailing slash. See jcf-path.c. */ 303 dir_len = i - 1; 304 305 for (k = 0; k < classname_length; k++, i++) 306 { 307 char ch = classname[k]; 308 buffer[i] = ch == '.' ? '/' : ch; 309 } 310 strcpy (buffer+i, ".class"); 311 312 if (jcf_path_is_zipfile (entry)) 313 { 314 int err_code; 315 JCF _jcf; 316 buffer[dir_len] = '\0'; 317 SOURCE_FRONTEND_DEBUG 318 (("Trying [...%s]:%s", 319 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 320 buffer+dir_len+1)); 321 if (jcf == NULL) 322 jcf = &_jcf; 323 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1, 324 jcf_path_is_system (entry)); 325 if (err_code == 0) 326 { 327 /* Should we check if .zip is out-of-date wrt .java? */ 328 buffer[dir_len] = '('; 329 strcpy (buffer+i, ".class)"); 330 if (jcf == &_jcf) 331 JCF_FINISH (jcf); 332 return buffer; 333 } 334 else 335 continue; 336 } 337 class = stat (buffer, &class_buf); 338 } 339 340 if (source_ok) 341 { 342 /* Compute name of .java file. */ 343 int l, m; 344 strcpy (java_buffer, path_name); 345 l = strlen (java_buffer); 346 for (m = 0; m < classname_length; ++m) 347 java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]); 348 strcpy (java_buffer + m + l, ".java"); 349 java = stat (java_buffer, &java_buf); 350 if (java == 0) 351 break; 352 } 353 } 354 355 if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime) 356 jcf->outofsynch = 1; 357 358 if (! java) 359 dep_file = java_buffer; 360 else 361 dep_file = buffer; 362#if JCF_USE_STDIO 363 if (!class) 364 { 365 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); 366 stream = fopen (buffer, "rb"); 367 if (stream) 368 goto found; 369 } 370 /* Give .java a try, if necessary */ 371 if (!java) 372 { 373 strcpy (buffer, java_buffer); 374 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); 375 stream = fopen (buffer, "r"); 376 if (stream) 377 { 378 jcf->java_source = 1; 379 goto found; 380 } 381 } 382#else 383 if (!class) 384 { 385 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); 386 fd = open (buffer, O_RDONLY | O_BINARY); 387 if (fd >= 0) 388 goto found; 389 } 390 /* Give .java a try, if necessary */ 391 if (!java) 392 { 393 strcpy (buffer, java_buffer); 394 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); 395 fd = open (buffer, O_RDONLY); 396 if (fd >= 0) 397 { 398 jcf->java_source = 1; 399 goto found; 400 } 401 } 402#endif 403 404 free (buffer); 405 return NULL; 406 found: 407#if JCF_USE_STDIO 408 if (jcf->java_source) 409 return NULL; /* FIXME */ 410 else 411 return open_class (buffer, jcf, stream, dep_file); 412#else 413 if (jcf->java_source) 414 { 415 JCF_ZERO (jcf); /* JCF_FINISH relies on this */ 416 jcf->java_source = 1; 417 jcf->filename = (char *) strdup (buffer); 418 close (fd); /* We use STDIO for source file */ 419 } 420 else 421 buffer = open_class (buffer, jcf, fd, dep_file); 422 jcf->classname = (char *) ALLOC (classname_length + 1); 423 strncpy (jcf->classname, classname, classname_length + 1); 424 jcf->classname = (char *) strdup (classname); 425 return buffer; 426#endif 427} 428 429void 430DEFUN(jcf_print_char, (stream, ch), 431 FILE *stream AND int ch) 432{ 433 switch (ch) 434 { 435 case '\'': 436 case '\\': 437 case '\"': 438 fprintf (stream, "\\%c", ch); 439 break; 440 case '\n': 441 fprintf (stream, "\\n"); 442 break; 443 case '\t': 444 fprintf (stream, "\\t"); 445 break; 446 case '\r': 447 fprintf (stream, "\\r"); 448 break; 449 default: 450 if (ch >= ' ' && ch < 127) 451 putc (ch, stream); 452 else if (ch < 256) 453 fprintf (stream, "\\%03x", ch); 454 else 455 fprintf (stream, "\\u%04x", ch); 456 } 457} 458 459/* Print UTF8 string at STR of length LENGTH bytes to STREAM. */ 460 461void 462DEFUN(jcf_print_utf8, (stream, str, length), 463 FILE *stream AND register const unsigned char *str AND int length) 464{ 465 const unsigned char * limit = str + length; 466 while (str < limit) 467 { 468 int ch = UTF8_GET (str, limit); 469 if (ch < 0) 470 { 471 fprintf (stream, "\\<invalid>"); 472 return; 473 } 474 jcf_print_char (stream, ch); 475 } 476} 477 478/* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */ 479 480void 481DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char), 482 FILE *stream AND const unsigned char *str AND int length 483 AND int in_char AND int out_char) 484{ 485 486 int i;/* FIXME - actually handle Unicode! */ 487 for (i = 0; i < length; i++) 488 { 489 int ch = str[i]; 490 jcf_print_char (stream, ch == in_char ? out_char : ch); 491 } 492} 493 494/* Check that all the cross-references in the constant pool are 495 valid. Returns 0 on success. 496 Otherwise, returns the index of the (first) invalid entry. */ 497 498int 499DEFUN(verify_constant_pool, (jcf), 500 JCF *jcf) 501{ 502 int i, n; 503 for (i = 1; i < JPOOL_SIZE (jcf); i++) 504 { 505 switch (JPOOL_TAG (jcf, i)) 506 { 507 case CONSTANT_NameAndType: 508 n = JPOOL_USHORT2 (jcf, i); 509 if (n <= 0 || n >= JPOOL_SIZE(jcf) 510 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) 511 return i; 512 /* ... fall through ... */ 513 case CONSTANT_Class: 514 case CONSTANT_String: 515 n = JPOOL_USHORT1 (jcf, i); 516 if (n <= 0 || n >= JPOOL_SIZE(jcf) 517 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) 518 return i; 519 break; 520 case CONSTANT_Fieldref: 521 case CONSTANT_Methodref: 522 case CONSTANT_InterfaceMethodref: 523 n = JPOOL_USHORT1 (jcf, i); 524 if (n <= 0 || n >= JPOOL_SIZE(jcf) 525 || JPOOL_TAG (jcf, n) != CONSTANT_Class) 526 return i; 527 n = JPOOL_USHORT2 (jcf, i); 528 if (n <= 0 || n >= JPOOL_SIZE(jcf) 529 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) 530 return i; 531 break; 532 case CONSTANT_Long: 533 case CONSTANT_Double: 534 i++; 535 break; 536 case CONSTANT_Float: 537 case CONSTANT_Integer: 538 case CONSTANT_Utf8: 539 case CONSTANT_Unicode: 540 break; 541 default: 542 return i; 543 } 544 } 545 return 0; 546} 547 548void 549DEFUN(format_uint, (buffer, value, base), 550 char *buffer AND uint64 value AND int base) 551{ 552#define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8) 553 char buf[WRITE_BUF_SIZE]; 554 register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */ 555 int chars_written; 556 int i; 557 558 /* Now do the actual conversion, placing the result at the *end* of buf. */ 559 /* Note this code does not pretend to be optimized. */ 560 do { 561 int digit = value % base; 562 static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 563 *--buf_ptr = digit_chars[digit]; 564 value /= base; 565 } while (value != 0); 566 567 chars_written = buf+WRITE_BUF_SIZE - buf_ptr; 568 for (i = 0; i < chars_written; i++) 569 buffer[i] = *buf_ptr++; 570 buffer[i] = 0; 571} 572 573void 574DEFUN(format_int, (buffer, value, base), 575 char *buffer AND jlong value AND int base) 576{ 577 uint64 abs_value; 578 if (value < 0) 579 { 580 abs_value = -(uint64)value; 581 *buffer++ = '-'; 582 } 583 else 584 abs_value = (uint64) value; 585 format_uint (buffer, abs_value, base); 586} 587