1*c87b03e5Sespie /* Utility routines for finding and reading Java(TM) .class files. 2*c87b03e5Sespie Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc. 3*c87b03e5Sespie 4*c87b03e5Sespie This program is free software; you can redistribute it and/or modify 5*c87b03e5Sespie it under the terms of the GNU General Public License as published by 6*c87b03e5Sespie the Free Software Foundation; either version 2, or (at your option) 7*c87b03e5Sespie any later version. 8*c87b03e5Sespie 9*c87b03e5Sespie This program is distributed in the hope that it will be useful, 10*c87b03e5Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of 11*c87b03e5Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*c87b03e5Sespie GNU General Public License for more details. 13*c87b03e5Sespie 14*c87b03e5Sespie You should have received a copy of the GNU General Public License 15*c87b03e5Sespie along with GNU CC; see the file COPYING. If not, write to 16*c87b03e5Sespie the Free Software Foundation, 59 Temple Place - Suite 330, 17*c87b03e5Sespie Boston, MA 02111-1307, USA. 18*c87b03e5Sespie 19*c87b03e5Sespie Java and all Java-based marks are trademarks or registered trademarks 20*c87b03e5Sespie of Sun Microsystems, Inc. in the United States and other countries. 21*c87b03e5Sespie The Free Software Foundation is independent of Sun Microsystems, Inc. */ 22*c87b03e5Sespie 23*c87b03e5Sespie /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */ 24*c87b03e5Sespie 25*c87b03e5Sespie #include "config.h" 26*c87b03e5Sespie #include "system.h" 27*c87b03e5Sespie 28*c87b03e5Sespie #include "jcf.h" 29*c87b03e5Sespie #include "tree.h" 30*c87b03e5Sespie #include "toplev.h" 31*c87b03e5Sespie #include "java-tree.h" 32*c87b03e5Sespie #include "hashtab.h" 33*c87b03e5Sespie #if JCF_USE_SCANDIR 34*c87b03e5Sespie #include <dirent.h> 35*c87b03e5Sespie #include <fnmatch.h> 36*c87b03e5Sespie #endif 37*c87b03e5Sespie 38*c87b03e5Sespie #include "zlib.h" 39*c87b03e5Sespie 40*c87b03e5Sespie /* DOS brain-damage */ 41*c87b03e5Sespie #ifndef O_BINARY 42*c87b03e5Sespie #define O_BINARY 0 /* MS-DOS brain-damage */ 43*c87b03e5Sespie #endif 44*c87b03e5Sespie 45*c87b03e5Sespie int 46*c87b03e5Sespie DEFUN(jcf_unexpected_eof, (jcf, count), 47*c87b03e5Sespie JCF *jcf AND int count ATTRIBUTE_UNUSED) 48*c87b03e5Sespie { 49*c87b03e5Sespie if (jcf->filename) 50*c87b03e5Sespie fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename); 51*c87b03e5Sespie else 52*c87b03e5Sespie fprintf (stderr, "Premature end of .class file <stdin>.\n"); 53*c87b03e5Sespie exit (-1); 54*c87b03e5Sespie } 55*c87b03e5Sespie 56*c87b03e5Sespie void 57*c87b03e5Sespie DEFUN(jcf_trim_old_input, (jcf), 58*c87b03e5Sespie JCF *jcf) 59*c87b03e5Sespie { 60*c87b03e5Sespie int count = jcf->read_ptr - jcf->buffer; 61*c87b03e5Sespie if (count > 0) 62*c87b03e5Sespie { 63*c87b03e5Sespie memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr); 64*c87b03e5Sespie jcf->read_ptr -= count; 65*c87b03e5Sespie jcf->read_end -= count; 66*c87b03e5Sespie } 67*c87b03e5Sespie } 68*c87b03e5Sespie 69*c87b03e5Sespie int 70*c87b03e5Sespie DEFUN(jcf_filbuf_from_stdio, (jcf, count), 71*c87b03e5Sespie JCF *jcf AND int count) 72*c87b03e5Sespie { 73*c87b03e5Sespie FILE *file = (FILE*) (jcf->read_state); 74*c87b03e5Sespie if (count > jcf->buffer_end - jcf->read_ptr) 75*c87b03e5Sespie { 76*c87b03e5Sespie JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer; 77*c87b03e5Sespie JCF_u4 old_read_end = jcf->read_end - jcf->buffer; 78*c87b03e5Sespie JCF_u4 old_size = jcf->buffer_end - jcf->buffer; 79*c87b03e5Sespie JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count; 80*c87b03e5Sespie unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size) 81*c87b03e5Sespie : REALLOC (jcf->buffer, new_size); 82*c87b03e5Sespie jcf->buffer = new_buffer; 83*c87b03e5Sespie jcf->buffer_end = new_buffer + new_size; 84*c87b03e5Sespie jcf->read_ptr = new_buffer + old_read_ptr; 85*c87b03e5Sespie jcf->read_end = new_buffer + old_read_end; 86*c87b03e5Sespie } 87*c87b03e5Sespie count -= jcf->read_end - jcf->read_ptr; 88*c87b03e5Sespie if (count <= 0) 89*c87b03e5Sespie return 0; 90*c87b03e5Sespie if ((int) fread (jcf->read_end, 1, count, file) != count) 91*c87b03e5Sespie jcf_unexpected_eof (jcf, count); 92*c87b03e5Sespie jcf->read_end += count; 93*c87b03e5Sespie return 0; 94*c87b03e5Sespie } 95*c87b03e5Sespie 96*c87b03e5Sespie #include "zipfile.h" 97*c87b03e5Sespie 98*c87b03e5Sespie struct ZipFile *SeenZipFiles = NULL; 99*c87b03e5Sespie 100*c87b03e5Sespie /* Open a zip file with the given name, and cache directory and file 101*c87b03e5Sespie descriptor. If the file is missing, treat it as an empty archive. 102*c87b03e5Sespie Return NULL if the .zip file is malformed. 103*c87b03e5Sespie */ 104*c87b03e5Sespie 105*c87b03e5Sespie ZipFile * 106*c87b03e5Sespie DEFUN(opendir_in_zip, (zipfile, is_system), 107*c87b03e5Sespie const char *zipfile AND int is_system) 108*c87b03e5Sespie { 109*c87b03e5Sespie struct ZipFile* zipf; 110*c87b03e5Sespie char magic [4]; 111*c87b03e5Sespie int fd; 112*c87b03e5Sespie for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next) 113*c87b03e5Sespie { 114*c87b03e5Sespie if (strcmp (zipf->name, zipfile) == 0) 115*c87b03e5Sespie return zipf; 116*c87b03e5Sespie } 117*c87b03e5Sespie 118*c87b03e5Sespie zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1); 119*c87b03e5Sespie zipf->next = SeenZipFiles; 120*c87b03e5Sespie zipf->name = (char*)(zipf+1); 121*c87b03e5Sespie strcpy (zipf->name, zipfile); 122*c87b03e5Sespie SeenZipFiles = zipf; 123*c87b03e5Sespie fd = open (zipfile, O_RDONLY | O_BINARY); 124*c87b03e5Sespie zipf->fd = fd; 125*c87b03e5Sespie if (fd < 0) 126*c87b03e5Sespie { 127*c87b03e5Sespie /* A missing zip file is not considered an error. 128*c87b03e5Sespie We may want to re-consider that. FIXME. */ 129*c87b03e5Sespie zipf->count = 0; 130*c87b03e5Sespie zipf->dir_size = 0; 131*c87b03e5Sespie zipf->central_directory = NULL; 132*c87b03e5Sespie } 133*c87b03e5Sespie else 134*c87b03e5Sespie { 135*c87b03e5Sespie jcf_dependency_add_file (zipfile, is_system); 136*c87b03e5Sespie if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC) 137*c87b03e5Sespie return NULL; 138*c87b03e5Sespie lseek (fd, 0L, SEEK_SET); 139*c87b03e5Sespie if (read_zip_archive (zipf) != 0) 140*c87b03e5Sespie return NULL; 141*c87b03e5Sespie } 142*c87b03e5Sespie return zipf; 143*c87b03e5Sespie } 144*c87b03e5Sespie 145*c87b03e5Sespie /* Returns: 146*c87b03e5Sespie 0: OK - zipmember found. 147*c87b03e5Sespie -1: Not found. 148*c87b03e5Sespie -2: Malformed archive. 149*c87b03e5Sespie */ 150*c87b03e5Sespie 151*c87b03e5Sespie int 152*c87b03e5Sespie DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system), 153*c87b03e5Sespie JCF *jcf AND const char *zipfile AND const char *zipmember 154*c87b03e5Sespie AND int is_system) 155*c87b03e5Sespie { 156*c87b03e5Sespie ZipDirectory *zipd; 157*c87b03e5Sespie int i, len; 158*c87b03e5Sespie ZipFile *zipf = opendir_in_zip (zipfile, is_system); 159*c87b03e5Sespie 160*c87b03e5Sespie if (zipf == NULL) 161*c87b03e5Sespie return -2; 162*c87b03e5Sespie 163*c87b03e5Sespie if (!zipmember) 164*c87b03e5Sespie return 0; 165*c87b03e5Sespie 166*c87b03e5Sespie len = strlen (zipmember); 167*c87b03e5Sespie 168*c87b03e5Sespie zipd = (struct ZipDirectory*) zipf->central_directory; 169*c87b03e5Sespie for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd)) 170*c87b03e5Sespie { 171*c87b03e5Sespie if (len == zipd->filename_length && 172*c87b03e5Sespie strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0) 173*c87b03e5Sespie { 174*c87b03e5Sespie JCF_ZERO (jcf); 175*c87b03e5Sespie 176*c87b03e5Sespie jcf->filename = xstrdup (zipfile); 177*c87b03e5Sespie jcf->classname = xstrdup (zipmember); 178*c87b03e5Sespie return read_zip_member(jcf, zipd, zipf); 179*c87b03e5Sespie } 180*c87b03e5Sespie } 181*c87b03e5Sespie return -1; 182*c87b03e5Sespie } 183*c87b03e5Sespie 184*c87b03e5Sespie /* Read data from zip archive member. */ 185*c87b03e5Sespie 186*c87b03e5Sespie int 187*c87b03e5Sespie DEFUN(read_zip_member, (jcf, zipd, zipf), 188*c87b03e5Sespie JCF *jcf AND ZipDirectory *zipd AND ZipFile *zipf) 189*c87b03e5Sespie { 190*c87b03e5Sespie jcf->filbuf = jcf_unexpected_eof; 191*c87b03e5Sespie jcf->zipd = (void *)zipd; 192*c87b03e5Sespie 193*c87b03e5Sespie if (zipd->compression_method == Z_NO_COMPRESSION) 194*c87b03e5Sespie { 195*c87b03e5Sespie jcf->buffer = ALLOC (zipd->size); 196*c87b03e5Sespie jcf->buffer_end = jcf->buffer + zipd->size; 197*c87b03e5Sespie jcf->read_ptr = jcf->buffer; 198*c87b03e5Sespie jcf->read_end = jcf->buffer_end; 199*c87b03e5Sespie if (lseek (zipf->fd, zipd->filestart, 0) < 0 200*c87b03e5Sespie || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size) 201*c87b03e5Sespie return -2; 202*c87b03e5Sespie } 203*c87b03e5Sespie else 204*c87b03e5Sespie { 205*c87b03e5Sespie char *buffer; 206*c87b03e5Sespie z_stream d_stream; /* decompression stream */ 207*c87b03e5Sespie d_stream.zalloc = (alloc_func) 0; 208*c87b03e5Sespie d_stream.zfree = (free_func) 0; 209*c87b03e5Sespie d_stream.opaque = (voidpf) 0; 210*c87b03e5Sespie 211*c87b03e5Sespie jcf->buffer = ALLOC (zipd->uncompressed_size); 212*c87b03e5Sespie d_stream.next_out = jcf->buffer; 213*c87b03e5Sespie d_stream.avail_out = zipd->uncompressed_size; 214*c87b03e5Sespie jcf->buffer_end = jcf->buffer + zipd->uncompressed_size; 215*c87b03e5Sespie jcf->read_ptr = jcf->buffer; 216*c87b03e5Sespie jcf->read_end = jcf->buffer_end; 217*c87b03e5Sespie buffer = ALLOC (zipd->size); 218*c87b03e5Sespie d_stream.next_in = buffer; 219*c87b03e5Sespie d_stream.avail_in = zipd->size; 220*c87b03e5Sespie if (lseek (zipf->fd, zipd->filestart, 0) < 0 221*c87b03e5Sespie || read (zipf->fd, buffer, zipd->size) != (long) zipd->size) 222*c87b03e5Sespie return -2; 223*c87b03e5Sespie /* Handle NO_HEADER using undocumented zlib feature. 224*c87b03e5Sespie This is a very common hack. */ 225*c87b03e5Sespie inflateInit2 (&d_stream, -MAX_WBITS); 226*c87b03e5Sespie inflate (&d_stream, Z_NO_FLUSH); 227*c87b03e5Sespie inflateEnd (&d_stream); 228*c87b03e5Sespie FREE (buffer); 229*c87b03e5Sespie } 230*c87b03e5Sespie 231*c87b03e5Sespie return 0; 232*c87b03e5Sespie } 233*c87b03e5Sespie 234*c87b03e5Sespie const char * 235*c87b03e5Sespie DEFUN(open_class, (filename, jcf, fd, dep_name), 236*c87b03e5Sespie const char *filename AND JCF *jcf AND int fd AND const char *dep_name) 237*c87b03e5Sespie { 238*c87b03e5Sespie if (jcf) 239*c87b03e5Sespie { 240*c87b03e5Sespie struct stat stat_buf; 241*c87b03e5Sespie if (fstat (fd, &stat_buf) != 0 242*c87b03e5Sespie || ! S_ISREG (stat_buf.st_mode)) 243*c87b03e5Sespie { 244*c87b03e5Sespie perror ("Could not figure length of .class file"); 245*c87b03e5Sespie return NULL; 246*c87b03e5Sespie } 247*c87b03e5Sespie if (dep_name != NULL) 248*c87b03e5Sespie jcf_dependency_add_file (dep_name, 0); 249*c87b03e5Sespie JCF_ZERO (jcf); 250*c87b03e5Sespie jcf->buffer = ALLOC (stat_buf.st_size); 251*c87b03e5Sespie jcf->buffer_end = jcf->buffer + stat_buf.st_size; 252*c87b03e5Sespie jcf->read_ptr = jcf->buffer; 253*c87b03e5Sespie jcf->read_end = jcf->buffer_end; 254*c87b03e5Sespie jcf->read_state = NULL; 255*c87b03e5Sespie jcf->filename = filename; 256*c87b03e5Sespie if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size) 257*c87b03e5Sespie { 258*c87b03e5Sespie perror ("Failed to read .class file"); 259*c87b03e5Sespie return NULL; 260*c87b03e5Sespie } 261*c87b03e5Sespie close (fd); 262*c87b03e5Sespie jcf->filbuf = jcf_unexpected_eof; 263*c87b03e5Sespie } 264*c87b03e5Sespie else 265*c87b03e5Sespie close (fd); 266*c87b03e5Sespie return filename; 267*c87b03e5Sespie } 268*c87b03e5Sespie 269*c87b03e5Sespie 270*c87b03e5Sespie const char * 271*c87b03e5Sespie DEFUN(find_classfile, (filename, jcf, dep_name), 272*c87b03e5Sespie char *filename AND JCF *jcf AND const char *dep_name) 273*c87b03e5Sespie { 274*c87b03e5Sespie int fd = open (filename, O_RDONLY | O_BINARY); 275*c87b03e5Sespie if (fd < 0) 276*c87b03e5Sespie return NULL; 277*c87b03e5Sespie return open_class (filename, jcf, fd, dep_name); 278*c87b03e5Sespie } 279*c87b03e5Sespie 280*c87b03e5Sespie #if JCF_USE_SCANDIR 281*c87b03e5Sespie 282*c87b03e5Sespie /* A comparison function (as for qsort) that compares KEY (a char * 283*c87b03e5Sespie giving the basename of a file) with the name stored in ENTRY (a 284*c87b03e5Sespie dirent **). */ 285*c87b03e5Sespie 286*c87b03e5Sespie static int 287*c87b03e5Sespie DEFUN(compare_path, (key, entry), 288*c87b03e5Sespie const void *key AND const void *entry) 289*c87b03e5Sespie { 290*c87b03e5Sespie return strcmp ((const char *) key, 291*c87b03e5Sespie (*((const struct dirent **) entry))->d_name); 292*c87b03e5Sespie } 293*c87b03e5Sespie 294*c87b03e5Sespie /* Returns nonzero if ENTRY names a .java or .class file. */ 295*c87b03e5Sespie 296*c87b03e5Sespie static int 297*c87b03e5Sespie DEFUN(java_or_class_file, (entry), 298*c87b03e5Sespie const struct dirent *entry) 299*c87b03e5Sespie { 300*c87b03e5Sespie const char *base = basename (entry->d_name); 301*c87b03e5Sespie return (fnmatch ("*.java", base, 0) == 0 || 302*c87b03e5Sespie fnmatch ("*.class", base, 0) == 0); 303*c87b03e5Sespie } 304*c87b03e5Sespie 305*c87b03e5Sespie /* Information about the files present in a particular directory. */ 306*c87b03e5Sespie typedef struct memoized_dirlist_entry 307*c87b03e5Sespie { 308*c87b03e5Sespie /* The name of the directory. */ 309*c87b03e5Sespie const char *dir; 310*c87b03e5Sespie /* The number of .java and .class files present, or -1 if we could 311*c87b03e5Sespie not, for some reason, obtain the list. */ 312*c87b03e5Sespie int num_files; 313*c87b03e5Sespie /* The .java and .class files in the directory, in alphabetical 314*c87b03e5Sespie order. */ 315*c87b03e5Sespie struct dirent **files; 316*c87b03e5Sespie } memoized_dirlist_entry; 317*c87b03e5Sespie 318*c87b03e5Sespie /* Returns true if ENTRY (a memoized_dirlist_entry *) correponds to 319*c87b03e5Sespie the directory given by KEY (a char *) giving the directory 320*c87b03e5Sespie name. */ 321*c87b03e5Sespie 322*c87b03e5Sespie static int 323*c87b03e5Sespie DEFUN(memoized_dirlist_lookup_eq, (entry, key), 324*c87b03e5Sespie const void *entry AND const void *key) 325*c87b03e5Sespie { 326*c87b03e5Sespie return strcmp ((const char *) key, 327*c87b03e5Sespie ((const memoized_dirlist_entry *) entry)->dir) == 0; 328*c87b03e5Sespie } 329*c87b03e5Sespie 330*c87b03e5Sespie /* A hash table mapping directory names to the lists of .java and 331*c87b03e5Sespie .class files in that directory. */ 332*c87b03e5Sespie 333*c87b03e5Sespie static htab_t memoized_dirlists; 334*c87b03e5Sespie 335*c87b03e5Sespie #endif 336*c87b03e5Sespie 337*c87b03e5Sespie /* Like stat, but avoids actually making the stat system call if we 338*c87b03e5Sespie know that it cannot succeed. FILENAME and BUF are as for stat. */ 339*c87b03e5Sespie 340*c87b03e5Sespie static int 341*c87b03e5Sespie DEFUN(caching_stat, (filename, buf), 342*c87b03e5Sespie char *filename AND struct stat *buf) 343*c87b03e5Sespie { 344*c87b03e5Sespie #if JCF_USE_SCANDIR 345*c87b03e5Sespie char *sep; 346*c87b03e5Sespie char origsep = 0; 347*c87b03e5Sespie char *base; 348*c87b03e5Sespie memoized_dirlist_entry *dent; 349*c87b03e5Sespie void **slot; 350*c87b03e5Sespie 351*c87b03e5Sespie /* If the hashtable has not already been created, create it now. */ 352*c87b03e5Sespie if (!memoized_dirlists) 353*c87b03e5Sespie memoized_dirlists = htab_create (37, 354*c87b03e5Sespie htab_hash_string, 355*c87b03e5Sespie memoized_dirlist_lookup_eq, 356*c87b03e5Sespie NULL); 357*c87b03e5Sespie 358*c87b03e5Sespie /* Get the name of the directory. */ 359*c87b03e5Sespie sep = strrchr (filename, DIR_SEPARATOR); 360*c87b03e5Sespie #ifdef DIR_SEPARATOR_2 361*c87b03e5Sespie if (! sep) 362*c87b03e5Sespie sep = strrchr (filename, DIR_SEPARATOR_2); 363*c87b03e5Sespie #endif 364*c87b03e5Sespie if (sep) 365*c87b03e5Sespie { 366*c87b03e5Sespie origsep = *sep; 367*c87b03e5Sespie *sep = '\0'; 368*c87b03e5Sespie base = sep + 1; 369*c87b03e5Sespie } 370*c87b03e5Sespie else 371*c87b03e5Sespie base = filename; 372*c87b03e5Sespie 373*c87b03e5Sespie /* Obtain the entry for this directory from the hash table. */ 374*c87b03e5Sespie slot = htab_find_slot (memoized_dirlists, filename, INSERT); 375*c87b03e5Sespie if (!*slot) 376*c87b03e5Sespie { 377*c87b03e5Sespie /* We have not already scanned this directory; scan it now. */ 378*c87b03e5Sespie dent = ((memoized_dirlist_entry *) 379*c87b03e5Sespie ALLOC (sizeof (memoized_dirlist_entry))); 380*c87b03e5Sespie dent->dir = xstrdup (filename); 381*c87b03e5Sespie /* Unfortunately, scandir is not fully standardized. In 382*c87b03e5Sespie particular, the type of the function pointer passed as the 383*c87b03e5Sespie third argument sometimes takes a "const struct dirent *" 384*c87b03e5Sespie parameter, and sometimes just a "struct dirent *". We cast 385*c87b03e5Sespie to (void *) so that either way it is quietly accepted. */ 386*c87b03e5Sespie dent->num_files = scandir (filename, &dent->files, 387*c87b03e5Sespie (void *) java_or_class_file, 388*c87b03e5Sespie alphasort); 389*c87b03e5Sespie *slot = dent; 390*c87b03e5Sespie } 391*c87b03e5Sespie else 392*c87b03e5Sespie dent = *((memoized_dirlist_entry **) slot); 393*c87b03e5Sespie 394*c87b03e5Sespie /* Put the separator back. */ 395*c87b03e5Sespie if (sep) 396*c87b03e5Sespie *sep = origsep; 397*c87b03e5Sespie 398*c87b03e5Sespie /* If the file is not in the list, there is no need to stat it; it 399*c87b03e5Sespie does not exist. */ 400*c87b03e5Sespie if (dent->num_files != -1 401*c87b03e5Sespie && !bsearch (base, dent->files, dent->num_files, 402*c87b03e5Sespie sizeof (struct dirent *), compare_path)) 403*c87b03e5Sespie return -1; 404*c87b03e5Sespie #endif 405*c87b03e5Sespie 406*c87b03e5Sespie return stat (filename, buf); 407*c87b03e5Sespie } 408*c87b03e5Sespie 409*c87b03e5Sespie /* Returns 1 if the CLASSNAME (really a char *) matches the name 410*c87b03e5Sespie stored in TABLE_ENTRY (also a char *). */ 411*c87b03e5Sespie 412*c87b03e5Sespie static int 413*c87b03e5Sespie DEFUN(memoized_class_lookup_eq, (table_entry, classname), 414*c87b03e5Sespie const void *table_entry AND const void *classname) 415*c87b03e5Sespie { 416*c87b03e5Sespie return strcmp ((const char *)classname, (const char *)table_entry) == 0; 417*c87b03e5Sespie } 418*c87b03e5Sespie 419*c87b03e5Sespie /* A hash table keeping track of class names that were not found 420*c87b03e5Sespie during class lookup. (There is no need to cache the values 421*c87b03e5Sespie associated with names that were found; they are saved in 422*c87b03e5Sespie IDENTIFIER_CLASS_VALUE.) */ 423*c87b03e5Sespie static htab_t memoized_class_lookups; 424*c87b03e5Sespie 425*c87b03e5Sespie /* Returns a freshly malloc'd string with the fully qualified pathname 426*c87b03e5Sespie of the .class file for the class CLASSNAME. CLASSNAME must be 427*c87b03e5Sespie allocated in permanent storage; this function may retain a pointer 428*c87b03e5Sespie to it. Returns NULL on failure. If JCF != NULL, it is suitably 429*c87b03e5Sespie initialized. SOURCE_OK is true if we should also look for .java 430*c87b03e5Sespie file. */ 431*c87b03e5Sespie 432*c87b03e5Sespie const char * 433*c87b03e5Sespie DEFUN(find_class, (classname, classname_length, jcf, source_ok), 434*c87b03e5Sespie const char *classname AND int classname_length AND JCF *jcf AND int source_ok) 435*c87b03e5Sespie 436*c87b03e5Sespie { 437*c87b03e5Sespie int fd; 438*c87b03e5Sespie int i, k, java = -1, class = -1; 439*c87b03e5Sespie struct stat java_buf, class_buf; 440*c87b03e5Sespie char *dep_file; 441*c87b03e5Sespie void *entry; 442*c87b03e5Sespie char *java_buffer; 443*c87b03e5Sespie int buflen; 444*c87b03e5Sespie char *buffer; 445*c87b03e5Sespie hashval_t hash; 446*c87b03e5Sespie 447*c87b03e5Sespie /* Create the hash table, if it does not already exist. */ 448*c87b03e5Sespie if (!memoized_class_lookups) 449*c87b03e5Sespie memoized_class_lookups = htab_create (37, 450*c87b03e5Sespie htab_hash_string, 451*c87b03e5Sespie memoized_class_lookup_eq, 452*c87b03e5Sespie NULL); 453*c87b03e5Sespie 454*c87b03e5Sespie /* Loop for this class in the hashtable. If it is present, we've 455*c87b03e5Sespie already looked for this class and failed to find it. */ 456*c87b03e5Sespie hash = htab_hash_string (classname); 457*c87b03e5Sespie if (htab_find_with_hash (memoized_class_lookups, classname, hash)) 458*c87b03e5Sespie return NULL; 459*c87b03e5Sespie 460*c87b03e5Sespie /* Allocate and zero out the buffer, since we don't explicitly put a 461*c87b03e5Sespie null pointer when we're copying it below. */ 462*c87b03e5Sespie buflen = jcf_path_max_len () + classname_length + 10; 463*c87b03e5Sespie buffer = ALLOC (buflen); 464*c87b03e5Sespie memset (buffer, 0, buflen); 465*c87b03e5Sespie 466*c87b03e5Sespie java_buffer = alloca (buflen); 467*c87b03e5Sespie 468*c87b03e5Sespie jcf->java_source = 0; 469*c87b03e5Sespie 470*c87b03e5Sespie for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry)) 471*c87b03e5Sespie { 472*c87b03e5Sespie const char *path_name = jcf_path_name (entry); 473*c87b03e5Sespie if (class != 0) 474*c87b03e5Sespie { 475*c87b03e5Sespie int dir_len; 476*c87b03e5Sespie 477*c87b03e5Sespie strcpy (buffer, path_name); 478*c87b03e5Sespie i = strlen (buffer); 479*c87b03e5Sespie 480*c87b03e5Sespie /* This is right because we know that `.zip' entries will have a 481*c87b03e5Sespie trailing slash. See jcf-path.c. */ 482*c87b03e5Sespie dir_len = i - 1; 483*c87b03e5Sespie 484*c87b03e5Sespie for (k = 0; k < classname_length; k++, i++) 485*c87b03e5Sespie { 486*c87b03e5Sespie char ch = classname[k]; 487*c87b03e5Sespie buffer[i] = ch == '.' ? '/' : ch; 488*c87b03e5Sespie } 489*c87b03e5Sespie strcpy (buffer+i, ".class"); 490*c87b03e5Sespie 491*c87b03e5Sespie if (jcf_path_is_zipfile (entry)) 492*c87b03e5Sespie { 493*c87b03e5Sespie int err_code; 494*c87b03e5Sespie JCF _jcf; 495*c87b03e5Sespie buffer[dir_len] = '\0'; 496*c87b03e5Sespie SOURCE_FRONTEND_DEBUG 497*c87b03e5Sespie (("Trying [...%s]:%s", 498*c87b03e5Sespie &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 499*c87b03e5Sespie buffer+dir_len+1)); 500*c87b03e5Sespie if (jcf == NULL) 501*c87b03e5Sespie jcf = &_jcf; 502*c87b03e5Sespie err_code = open_in_zip (jcf, buffer, buffer+dir_len+1, 503*c87b03e5Sespie jcf_path_is_system (entry)); 504*c87b03e5Sespie if (err_code == 0) 505*c87b03e5Sespie { 506*c87b03e5Sespie /* Should we check if .zip is out-of-date wrt .java? */ 507*c87b03e5Sespie buffer[dir_len] = '('; 508*c87b03e5Sespie strcpy (buffer+i, ".class)"); 509*c87b03e5Sespie if (jcf == &_jcf) 510*c87b03e5Sespie JCF_FINISH (jcf); 511*c87b03e5Sespie return buffer; 512*c87b03e5Sespie } 513*c87b03e5Sespie else 514*c87b03e5Sespie continue; 515*c87b03e5Sespie } 516*c87b03e5Sespie class = caching_stat(buffer, &class_buf); 517*c87b03e5Sespie } 518*c87b03e5Sespie 519*c87b03e5Sespie if (source_ok) 520*c87b03e5Sespie { 521*c87b03e5Sespie /* Compute name of .java file. */ 522*c87b03e5Sespie int l, m; 523*c87b03e5Sespie strcpy (java_buffer, path_name); 524*c87b03e5Sespie l = strlen (java_buffer); 525*c87b03e5Sespie for (m = 0; m < classname_length; ++m) 526*c87b03e5Sespie java_buffer[m + l] = (classname[m] == '.' 527*c87b03e5Sespie ? DIR_SEPARATOR : classname[m]); 528*c87b03e5Sespie strcpy (java_buffer + m + l, ".java"); 529*c87b03e5Sespie java = caching_stat (java_buffer, &java_buf); 530*c87b03e5Sespie if (java == 0) 531*c87b03e5Sespie break; 532*c87b03e5Sespie } 533*c87b03e5Sespie } 534*c87b03e5Sespie 535*c87b03e5Sespie /* We preferably pick a class file if we have a chance. If the source 536*c87b03e5Sespie file is newer than the class file, we issue a warning and parse the 537*c87b03e5Sespie source file instead. 538*c87b03e5Sespie There should be a flag to allow people have the class file picked 539*c87b03e5Sespie up no matter what. FIXME. */ 540*c87b03e5Sespie if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime) 541*c87b03e5Sespie { 542*c87b03e5Sespie if (flag_newer) 543*c87b03e5Sespie warning ("source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer); 544*c87b03e5Sespie class = -1; 545*c87b03e5Sespie } 546*c87b03e5Sespie 547*c87b03e5Sespie if (! java) 548*c87b03e5Sespie dep_file = java_buffer; 549*c87b03e5Sespie else 550*c87b03e5Sespie dep_file = buffer; 551*c87b03e5Sespie if (!class) 552*c87b03e5Sespie { 553*c87b03e5Sespie SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n", 554*c87b03e5Sespie classname+classname_length- 555*c87b03e5Sespie (classname_length <= 30 ? 556*c87b03e5Sespie classname_length : 30))); 557*c87b03e5Sespie fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY | O_BINARY); 558*c87b03e5Sespie if (fd >= 0) 559*c87b03e5Sespie goto found; 560*c87b03e5Sespie } 561*c87b03e5Sespie /* Give .java a try, if necessary */ 562*c87b03e5Sespie if (!java) 563*c87b03e5Sespie { 564*c87b03e5Sespie strcpy (buffer, java_buffer); 565*c87b03e5Sespie SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n", 566*c87b03e5Sespie classname+classname_length- 567*c87b03e5Sespie (classname_length <= 30 ? 568*c87b03e5Sespie classname_length : 30))); 569*c87b03e5Sespie fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY); 570*c87b03e5Sespie if (fd >= 0) 571*c87b03e5Sespie { 572*c87b03e5Sespie jcf->java_source = 1; 573*c87b03e5Sespie goto found; 574*c87b03e5Sespie } 575*c87b03e5Sespie } 576*c87b03e5Sespie 577*c87b03e5Sespie free (buffer); 578*c87b03e5Sespie 579*c87b03e5Sespie /* Remember that this class could not be found so that we do not 580*c87b03e5Sespie have to look again. */ 581*c87b03e5Sespie *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT) 582*c87b03e5Sespie = (void *) classname; 583*c87b03e5Sespie 584*c87b03e5Sespie return NULL; 585*c87b03e5Sespie found: 586*c87b03e5Sespie if (jcf->java_source) 587*c87b03e5Sespie { 588*c87b03e5Sespie JCF_ZERO (jcf); /* JCF_FINISH relies on this */ 589*c87b03e5Sespie jcf->java_source = 1; 590*c87b03e5Sespie jcf->filename = xstrdup (buffer); 591*c87b03e5Sespie close (fd); /* We use STDIO for source file */ 592*c87b03e5Sespie } 593*c87b03e5Sespie else 594*c87b03e5Sespie buffer = (char *) open_class (buffer, jcf, fd, dep_file); 595*c87b03e5Sespie jcf->classname = xstrdup (classname); 596*c87b03e5Sespie return buffer; 597*c87b03e5Sespie } 598*c87b03e5Sespie 599*c87b03e5Sespie void 600*c87b03e5Sespie DEFUN(jcf_print_char, (stream, ch), 601*c87b03e5Sespie FILE *stream AND int ch) 602*c87b03e5Sespie { 603*c87b03e5Sespie switch (ch) 604*c87b03e5Sespie { 605*c87b03e5Sespie case '\'': 606*c87b03e5Sespie case '\\': 607*c87b03e5Sespie case '\"': 608*c87b03e5Sespie fprintf (stream, "\\%c", ch); 609*c87b03e5Sespie break; 610*c87b03e5Sespie case '\n': 611*c87b03e5Sespie fprintf (stream, "\\n"); 612*c87b03e5Sespie break; 613*c87b03e5Sespie case '\t': 614*c87b03e5Sespie fprintf (stream, "\\t"); 615*c87b03e5Sespie break; 616*c87b03e5Sespie case '\r': 617*c87b03e5Sespie fprintf (stream, "\\r"); 618*c87b03e5Sespie break; 619*c87b03e5Sespie default: 620*c87b03e5Sespie if (ch >= ' ' && ch < 127) 621*c87b03e5Sespie putc (ch, stream); 622*c87b03e5Sespie else if (ch < 256) 623*c87b03e5Sespie fprintf (stream, "\\%03x", ch); 624*c87b03e5Sespie else 625*c87b03e5Sespie fprintf (stream, "\\u%04x", ch); 626*c87b03e5Sespie } 627*c87b03e5Sespie } 628*c87b03e5Sespie 629*c87b03e5Sespie /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */ 630*c87b03e5Sespie 631*c87b03e5Sespie void 632*c87b03e5Sespie DEFUN(jcf_print_utf8, (stream, str, length), 633*c87b03e5Sespie FILE *stream AND register const unsigned char *str AND int length) 634*c87b03e5Sespie { 635*c87b03e5Sespie const unsigned char * limit = str + length; 636*c87b03e5Sespie while (str < limit) 637*c87b03e5Sespie { 638*c87b03e5Sespie int ch = UTF8_GET (str, limit); 639*c87b03e5Sespie if (ch < 0) 640*c87b03e5Sespie { 641*c87b03e5Sespie fprintf (stream, "\\<invalid>"); 642*c87b03e5Sespie return; 643*c87b03e5Sespie } 644*c87b03e5Sespie jcf_print_char (stream, ch); 645*c87b03e5Sespie } 646*c87b03e5Sespie } 647*c87b03e5Sespie 648*c87b03e5Sespie /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */ 649*c87b03e5Sespie 650*c87b03e5Sespie void 651*c87b03e5Sespie DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char), 652*c87b03e5Sespie FILE *stream AND const unsigned char *str AND int length 653*c87b03e5Sespie AND int in_char AND int out_char) 654*c87b03e5Sespie { 655*c87b03e5Sespie const unsigned char *limit = str + length; 656*c87b03e5Sespie while (str < limit) 657*c87b03e5Sespie { 658*c87b03e5Sespie int ch = UTF8_GET (str, limit); 659*c87b03e5Sespie if (ch < 0) 660*c87b03e5Sespie { 661*c87b03e5Sespie fprintf (stream, "\\<invalid>"); 662*c87b03e5Sespie return; 663*c87b03e5Sespie } 664*c87b03e5Sespie jcf_print_char (stream, ch == in_char ? out_char : ch); 665*c87b03e5Sespie } 666*c87b03e5Sespie } 667*c87b03e5Sespie 668*c87b03e5Sespie /* Check that all the cross-references in the constant pool are 669*c87b03e5Sespie valid. Returns 0 on success. 670*c87b03e5Sespie Otherwise, returns the index of the (first) invalid entry. 671*c87b03e5Sespie Only checks internal consistency, but does not check that 672*c87b03e5Sespie any classes, fields, or methods are valid.*/ 673*c87b03e5Sespie 674*c87b03e5Sespie int 675*c87b03e5Sespie DEFUN(verify_constant_pool, (jcf), 676*c87b03e5Sespie JCF *jcf) 677*c87b03e5Sespie { 678*c87b03e5Sespie int i, n; 679*c87b03e5Sespie for (i = 1; i < JPOOL_SIZE (jcf); i++) 680*c87b03e5Sespie { 681*c87b03e5Sespie switch (JPOOL_TAG (jcf, i)) 682*c87b03e5Sespie { 683*c87b03e5Sespie case CONSTANT_NameAndType: 684*c87b03e5Sespie n = JPOOL_USHORT2 (jcf, i); 685*c87b03e5Sespie if (n <= 0 || n >= JPOOL_SIZE(jcf) 686*c87b03e5Sespie || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) 687*c87b03e5Sespie return i; 688*c87b03e5Sespie /* ... fall through ... */ 689*c87b03e5Sespie case CONSTANT_Class: 690*c87b03e5Sespie case CONSTANT_String: 691*c87b03e5Sespie n = JPOOL_USHORT1 (jcf, i); 692*c87b03e5Sespie if (n <= 0 || n >= JPOOL_SIZE(jcf) 693*c87b03e5Sespie || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) 694*c87b03e5Sespie return i; 695*c87b03e5Sespie break; 696*c87b03e5Sespie case CONSTANT_Fieldref: 697*c87b03e5Sespie case CONSTANT_Methodref: 698*c87b03e5Sespie case CONSTANT_InterfaceMethodref: 699*c87b03e5Sespie n = JPOOL_USHORT1 (jcf, i); 700*c87b03e5Sespie if (n <= 0 || n >= JPOOL_SIZE(jcf) 701*c87b03e5Sespie || JPOOL_TAG (jcf, n) != CONSTANT_Class) 702*c87b03e5Sespie return i; 703*c87b03e5Sespie n = JPOOL_USHORT2 (jcf, i); 704*c87b03e5Sespie if (n <= 0 || n >= JPOOL_SIZE(jcf) 705*c87b03e5Sespie || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) 706*c87b03e5Sespie return i; 707*c87b03e5Sespie break; 708*c87b03e5Sespie case CONSTANT_Long: 709*c87b03e5Sespie case CONSTANT_Double: 710*c87b03e5Sespie i++; 711*c87b03e5Sespie break; 712*c87b03e5Sespie case CONSTANT_Float: 713*c87b03e5Sespie case CONSTANT_Integer: 714*c87b03e5Sespie case CONSTANT_Utf8: 715*c87b03e5Sespie case CONSTANT_Unicode: 716*c87b03e5Sespie break; 717*c87b03e5Sespie default: 718*c87b03e5Sespie return i; 719*c87b03e5Sespie } 720*c87b03e5Sespie } 721*c87b03e5Sespie return 0; 722*c87b03e5Sespie } 723*c87b03e5Sespie 724*c87b03e5Sespie void 725*c87b03e5Sespie DEFUN(format_uint, (buffer, value, base), 726*c87b03e5Sespie char *buffer AND uint64 value AND int base) 727*c87b03e5Sespie { 728*c87b03e5Sespie #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8) 729*c87b03e5Sespie char buf[WRITE_BUF_SIZE]; 730*c87b03e5Sespie register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */ 731*c87b03e5Sespie int chars_written; 732*c87b03e5Sespie int i; 733*c87b03e5Sespie 734*c87b03e5Sespie /* Now do the actual conversion, placing the result at the *end* of buf. */ 735*c87b03e5Sespie /* Note this code does not pretend to be optimized. */ 736*c87b03e5Sespie do { 737*c87b03e5Sespie int digit = value % base; 738*c87b03e5Sespie static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 739*c87b03e5Sespie *--buf_ptr = digit_chars[digit]; 740*c87b03e5Sespie value /= base; 741*c87b03e5Sespie } while (value != 0); 742*c87b03e5Sespie 743*c87b03e5Sespie chars_written = buf+WRITE_BUF_SIZE - buf_ptr; 744*c87b03e5Sespie for (i = 0; i < chars_written; i++) 745*c87b03e5Sespie buffer[i] = *buf_ptr++; 746*c87b03e5Sespie buffer[i] = 0; 747*c87b03e5Sespie } 748*c87b03e5Sespie 749*c87b03e5Sespie void 750*c87b03e5Sespie DEFUN(format_int, (buffer, value, base), 751*c87b03e5Sespie char *buffer AND jlong value AND int base) 752*c87b03e5Sespie { 753*c87b03e5Sespie uint64 abs_value; 754*c87b03e5Sespie if (value < 0) 755*c87b03e5Sespie { 756*c87b03e5Sespie abs_value = -(uint64)value; 757*c87b03e5Sespie *buffer++ = '-'; 758*c87b03e5Sespie } 759*c87b03e5Sespie else 760*c87b03e5Sespie abs_value = (uint64) value; 761*c87b03e5Sespie format_uint (buffer, abs_value, base); 762*c87b03e5Sespie } 763