00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026 #include "system.h"
00027
00028 #include "jcf.h"
00029 #include "tree.h"
00030 #include "toplev.h"
00031 #include "java-tree.h"
00032 #include "hashtab.h"
00033 #if JCF_USE_SCANDIR
00034 #include <dirent.h>
00035 #include <fnmatch.h>
00036 #endif
00037
00038 #include "zlib.h"
00039
00040
00041 #ifndef O_BINARY
00042 #define O_BINARY 0
00043 #endif
00044
00045 int
00046 DEFUN(jcf_unexpected_eof, (jcf, count),
00047 JCF *jcf AND int count ATTRIBUTE_UNUSED)
00048 {
00049 if (jcf->filename)
00050 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
00051 else
00052 fprintf (stderr, "Premature end of .class file <stdin>.\n");
00053 exit (-1);
00054 }
00055
00056 void
00057 DEFUN(jcf_trim_old_input, (jcf),
00058 JCF *jcf)
00059 {
00060 int count = jcf->read_ptr - jcf->buffer;
00061 if (count > 0)
00062 {
00063 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
00064 jcf->read_ptr -= count;
00065 jcf->read_end -= count;
00066 }
00067 }
00068
00069 int
00070 DEFUN(jcf_filbuf_from_stdio, (jcf, count),
00071 JCF *jcf AND int count)
00072 {
00073 FILE *file = (FILE*) (jcf->read_state);
00074 if (count > jcf->buffer_end - jcf->read_ptr)
00075 {
00076 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
00077 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
00078 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
00079 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
00080 unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
00081 : REALLOC (jcf->buffer, new_size);
00082 jcf->buffer = new_buffer;
00083 jcf->buffer_end = new_buffer + new_size;
00084 jcf->read_ptr = new_buffer + old_read_ptr;
00085 jcf->read_end = new_buffer + old_read_end;
00086 }
00087 count -= jcf->read_end - jcf->read_ptr;
00088 if (count <= 0)
00089 return 0;
00090 if ((int) fread (jcf->read_end, 1, count, file) != count)
00091 jcf_unexpected_eof (jcf, count);
00092 jcf->read_end += count;
00093 return 0;
00094 }
00095
00096 #include "zipfile.h"
00097
00098 struct ZipFile *SeenZipFiles = NULL;
00099
00100
00101
00102
00103
00104
00105 ZipFile *
00106 DEFUN(opendir_in_zip, (zipfile, is_system),
00107 const char *zipfile AND int is_system)
00108 {
00109 struct ZipFile* zipf;
00110 char magic [4];
00111 int fd;
00112 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
00113 {
00114 if (strcmp (zipf->name, zipfile) == 0)
00115 return zipf;
00116 }
00117
00118 zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1);
00119 zipf->next = SeenZipFiles;
00120 zipf->name = (char*)(zipf+1);
00121 strcpy (zipf->name, zipfile);
00122 SeenZipFiles = zipf;
00123 fd = open (zipfile, O_RDONLY | O_BINARY);
00124 zipf->fd = fd;
00125 if (fd < 0)
00126 {
00127
00128
00129 zipf->count = 0;
00130 zipf->dir_size = 0;
00131 zipf->central_directory = NULL;
00132 }
00133 else
00134 {
00135 jcf_dependency_add_file (zipfile, is_system);
00136 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
00137 return NULL;
00138 lseek (fd, 0L, SEEK_SET);
00139 if (read_zip_archive (zipf) != 0)
00140 return NULL;
00141 }
00142 return zipf;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 int
00152 DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
00153 JCF *jcf AND const char *zipfile AND const char *zipmember
00154 AND int is_system)
00155 {
00156 ZipDirectory *zipd;
00157 int i, len;
00158 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
00159
00160 if (zipf == NULL)
00161 return -2;
00162
00163 if (!zipmember)
00164 return 0;
00165
00166 len = strlen (zipmember);
00167
00168 zipd = (struct ZipDirectory*) zipf->central_directory;
00169 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
00170 {
00171 if (len == zipd->filename_length &&
00172 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
00173 {
00174 JCF_ZERO (jcf);
00175
00176 jcf->filename = xstrdup (zipfile);
00177 jcf->classname = xstrdup (zipmember);
00178 return read_zip_member(jcf, zipd, zipf);
00179 }
00180 }
00181 return -1;
00182 }
00183
00184
00185
00186 int
00187 DEFUN(read_zip_member, (jcf, zipd, zipf),
00188 JCF *jcf AND ZipDirectory *zipd AND ZipFile *zipf)
00189 {
00190 jcf->filbuf = jcf_unexpected_eof;
00191 jcf->zipd = (void *)zipd;
00192
00193 if (zipd->compression_method == Z_NO_COMPRESSION)
00194 {
00195 jcf->buffer = ALLOC (zipd->size);
00196 jcf->buffer_end = jcf->buffer + zipd->size;
00197 jcf->read_ptr = jcf->buffer;
00198 jcf->read_end = jcf->buffer_end;
00199 if (lseek (zipf->fd, zipd->filestart, 0) < 0
00200 || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
00201 return -2;
00202 }
00203 else
00204 {
00205 char *buffer;
00206 z_stream d_stream;
00207 d_stream.zalloc = (alloc_func) 0;
00208 d_stream.zfree = (free_func) 0;
00209 d_stream.opaque = (voidpf) 0;
00210
00211 jcf->buffer = ALLOC (zipd->uncompressed_size);
00212 d_stream.next_out = jcf->buffer;
00213 d_stream.avail_out = zipd->uncompressed_size;
00214 jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
00215 jcf->read_ptr = jcf->buffer;
00216 jcf->read_end = jcf->buffer_end;
00217 buffer = ALLOC (zipd->size);
00218 d_stream.next_in = buffer;
00219 d_stream.avail_in = zipd->size;
00220 if (lseek (zipf->fd, zipd->filestart, 0) < 0
00221 || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
00222 return -2;
00223
00224
00225 inflateInit2 (&d_stream, -MAX_WBITS);
00226 inflate (&d_stream, Z_NO_FLUSH);
00227 inflateEnd (&d_stream);
00228 FREE (buffer);
00229 }
00230
00231 return 0;
00232 }
00233
00234 #if JCF_USE_STDIO
00235 const char *
00236 DEFUN(open_class, (filename, jcf, stream, dep_name),
00237 const char *filename AND JCF *jcf AND FILE* stream
00238 AND const char *dep_name)
00239 {
00240 if (jcf)
00241 {
00242 if (dep_name != NULL)
00243 jcf_dependency_add_file (dep_name, 0);
00244 JCF_ZERO (jcf);
00245 jcf->buffer = NULL;
00246 jcf->buffer_end = NULL;
00247 jcf->read_ptr = NULL;
00248 jcf->read_end = NULL;
00249 jcf->read_state = stream;
00250 jcf->filename = filename;
00251 jcf->filbuf = jcf_filbuf_from_stdio;
00252 }
00253 else
00254 fclose (stream);
00255 return filename;
00256 }
00257 #else
00258 const char *
00259 DEFUN(open_class, (filename, jcf, fd, dep_name),
00260 const char *filename AND JCF *jcf AND int fd AND const char *dep_name)
00261 {
00262 if (jcf)
00263 {
00264 struct stat stat_buf;
00265 if (fstat (fd, &stat_buf) != 0
00266 || ! S_ISREG (stat_buf.st_mode))
00267 {
00268 perror ("Could not figure length of .class file");
00269 return NULL;
00270 }
00271 if (dep_name != NULL)
00272 jcf_dependency_add_file (dep_name, 0);
00273 JCF_ZERO (jcf);
00274 jcf->buffer = ALLOC (stat_buf.st_size);
00275 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
00276 jcf->read_ptr = jcf->buffer;
00277 jcf->read_end = jcf->buffer_end;
00278 jcf->read_state = NULL;
00279 jcf->filename = filename;
00280 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
00281 {
00282 perror ("Failed to read .class file");
00283 return NULL;
00284 }
00285 close (fd);
00286 jcf->filbuf = jcf_unexpected_eof;
00287 }
00288 else
00289 close (fd);
00290 return filename;
00291 }
00292 #endif
00293
00294
00295 const char *
00296 DEFUN(find_classfile, (filename, jcf, dep_name),
00297 char *filename AND JCF *jcf AND const char *dep_name)
00298 {
00299 #if JCF_USE_STDIO
00300 FILE *stream = fopen (filename, "rb");
00301 if (stream == NULL)
00302 return NULL;
00303 return open_class (arg, jcf, stream, dep_name);
00304 #else
00305 int fd = open (filename, O_RDONLY | O_BINARY);
00306 if (fd < 0)
00307 return NULL;
00308 return open_class (filename, jcf, fd, dep_name);
00309 #endif
00310 }
00311
00312 #if JCF_USE_SCANDIR
00313
00314
00315
00316
00317
00318 static int
00319 DEFUN(compare_path, (key, entry),
00320 const void *key AND const void *entry)
00321 {
00322 return strcmp ((const char *) key,
00323 (*((const struct dirent **) entry))->d_name);
00324 }
00325
00326
00327
00328 static int
00329 DEFUN(java_or_class_file, (entry),
00330 const struct dirent *entry)
00331 {
00332 const char *base = basename (entry->d_name);
00333 return (fnmatch ("*.java", base, 0) == 0 ||
00334 fnmatch ("*.class", base, 0) == 0);
00335 }
00336
00337
00338 typedef struct memoized_dirlist_entry
00339 {
00340
00341 const char *dir;
00342
00343
00344 int num_files;
00345
00346
00347 struct dirent **files;
00348 } memoized_dirlist_entry;
00349
00350
00351
00352
00353
00354 static int
00355 DEFUN(memoized_dirlist_lookup_eq, (entry, key),
00356 const void *entry AND const void *key)
00357 {
00358 return strcmp ((const char *) key,
00359 ((const memoized_dirlist_entry *) entry)->dir) == 0;
00360 }
00361
00362
00363
00364
00365 static htab_t memoized_dirlists;
00366
00367 #endif
00368
00369
00370
00371
00372 static int
00373 DEFUN(caching_stat, (filename, buf),
00374 char *filename AND struct stat *buf)
00375 {
00376 #if JCF_USE_SCANDIR
00377 char *sep;
00378 char *base;
00379 memoized_dirlist_entry *dent;
00380 void **slot;
00381
00382
00383 if (!memoized_dirlists)
00384 memoized_dirlists = htab_create (37,
00385 htab_hash_string,
00386 memoized_dirlist_lookup_eq,
00387 NULL);
00388
00389
00390 sep = strrchr (filename, DIR_SEPARATOR);
00391 if (sep)
00392 {
00393 *sep = '\0';
00394 base = sep + 1;
00395 }
00396 else
00397 base = filename;
00398
00399
00400 slot = htab_find_slot (memoized_dirlists, filename, INSERT);
00401 if (!*slot)
00402 {
00403
00404 dent = ((memoized_dirlist_entry *)
00405 ALLOC (sizeof (memoized_dirlist_entry)));
00406 dent->dir = xstrdup (filename);
00407
00408
00409
00410
00411
00412
00413 dent->num_files = scandir (filename, &dent->files,
00414 java_or_class_file,
00415 alphasort);
00416 *slot = dent;
00417 }
00418 else
00419 dent = *((memoized_dirlist_entry **) slot);
00420
00421
00422 if (sep)
00423 *sep = DIR_SEPARATOR;
00424
00425
00426
00427 if (dent->num_files != -1
00428 && !bsearch (base, dent->files, dent->num_files,
00429 sizeof (struct dirent *), compare_path))
00430 return -1;
00431 #endif
00432
00433 return stat (filename, buf);
00434 }
00435
00436
00437
00438
00439 static int
00440 DEFUN(memoized_class_lookup_eq, (table_entry, classname),
00441 const void *table_entry AND const void *classname)
00442 {
00443 return strcmp ((const char *)classname, (const char *)table_entry) == 0;
00444 }
00445
00446
00447
00448
00449
00450 static htab_t memoized_class_lookups;
00451
00452
00453
00454
00455
00456
00457
00458
00459 const char *
00460 DEFUN(find_class, (classname, classname_length, jcf, source_ok),
00461 const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
00462
00463 {
00464 #if JCF_USE_STDIO
00465 FILE *stream;
00466 #else
00467 int fd;
00468 #endif
00469 int i, k, java = -1, class = -1;
00470 struct stat java_buf, class_buf;
00471 char *dep_file;
00472 void *entry;
00473 char *java_buffer;
00474 int buflen;
00475 char *buffer;
00476 hashval_t hash;
00477
00478
00479 if (!memoized_class_lookups)
00480 memoized_class_lookups = htab_create (37,
00481 htab_hash_string,
00482 memoized_class_lookup_eq,
00483 NULL);
00484
00485
00486
00487 hash = htab_hash_string (classname);
00488 if (htab_find_with_hash (memoized_class_lookups, classname, hash))
00489 return NULL;
00490
00491
00492
00493 buflen = jcf_path_max_len () + classname_length + 10;
00494 buffer = (char *) ALLOC (buflen);
00495 memset (buffer, 0, buflen);
00496
00497 java_buffer = (char *) alloca (buflen);
00498
00499 jcf->java_source = 0;
00500
00501 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
00502 {
00503 const char *path_name = jcf_path_name (entry);
00504 if (class != 0)
00505 {
00506 int dir_len;
00507
00508 strcpy (buffer, path_name);
00509 i = strlen (buffer);
00510
00511
00512
00513 dir_len = i - 1;
00514
00515 for (k = 0; k < classname_length; k++, i++)
00516 {
00517 char ch = classname[k];
00518 buffer[i] = ch == '.' ? '/' : ch;
00519 }
00520 strcpy (buffer+i, ".class");
00521
00522 if (jcf_path_is_zipfile (entry))
00523 {
00524 int err_code;
00525 JCF _jcf;
00526 buffer[dir_len] = '\0';
00527 SOURCE_FRONTEND_DEBUG
00528 (("Trying [...%s]:%s",
00529 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
00530 buffer+dir_len+1));
00531 if (jcf == NULL)
00532 jcf = &_jcf;
00533 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
00534 jcf_path_is_system (entry));
00535 if (err_code == 0)
00536 {
00537
00538 buffer[dir_len] = '(';
00539 strcpy (buffer+i, ".class)");
00540 if (jcf == &_jcf)
00541 JCF_FINISH (jcf);
00542 return buffer;
00543 }
00544 else
00545 continue;
00546 }
00547 class = caching_stat(buffer, &class_buf);
00548 }
00549
00550 if (source_ok)
00551 {
00552
00553 int l, m;
00554 strcpy (java_buffer, path_name);
00555 l = strlen (java_buffer);
00556 for (m = 0; m < classname_length; ++m)
00557 java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]);
00558 strcpy (java_buffer + m + l, ".java");
00559 java = caching_stat (java_buffer, &java_buf);
00560 if (java == 0)
00561 break;
00562 }
00563 }
00564
00565
00566
00567
00568
00569
00570 if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
00571 {
00572 if (flag_newer)
00573 warning ("source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer);
00574 class = -1;
00575 }
00576
00577 if (! java)
00578 dep_file = java_buffer;
00579 else
00580 dep_file = buffer;
00581 #if JCF_USE_STDIO
00582 if (!class)
00583 {
00584 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
00585 stream = fopen (buffer, "rb");
00586 if (stream)
00587 goto found;
00588 }
00589
00590 if (!java)
00591 {
00592 strcpy (buffer, java_buffer);
00593 SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
00594 stream = fopen (buffer, "r");
00595 if (stream)
00596 {
00597 jcf->java_source = 1;
00598 goto found;
00599 }
00600 }
00601 #else
00602 if (!class)
00603 {
00604 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
00605 classname+classname_length-
00606 (classname_length <= 30 ?
00607 classname_length : 30)));
00608 fd = open (buffer, O_RDONLY | O_BINARY);
00609 if (fd >= 0)
00610 goto found;
00611 }
00612
00613 if (!java)
00614 {
00615 strcpy (buffer, java_buffer);
00616 SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
00617 classname+classname_length-
00618 (classname_length <= 30 ?
00619 classname_length : 30)));
00620 fd = open (buffer, O_RDONLY);
00621 if (fd >= 0)
00622 {
00623 jcf->java_source = 1;
00624 goto found;
00625 }
00626 }
00627 #endif
00628
00629 free (buffer);
00630
00631
00632
00633 *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT)
00634 = (void *) classname;
00635
00636 return NULL;
00637 found:
00638 #if JCF_USE_STDIO
00639 if (jcf->java_source)
00640 return NULL;
00641 else
00642 return open_class (buffer, jcf, stream, dep_file);
00643 #else
00644 if (jcf->java_source)
00645 {
00646 JCF_ZERO (jcf);
00647 jcf->java_source = 1;
00648 jcf->filename = xstrdup (buffer);
00649 close (fd);
00650 }
00651 else
00652 buffer = (char *) open_class (buffer, jcf, fd, dep_file);
00653 jcf->classname = xstrdup (classname);
00654 return buffer;
00655 #endif
00656 }
00657
00658 void
00659 DEFUN(jcf_print_char, (stream, ch),
00660 FILE *stream AND int ch)
00661 {
00662 switch (ch)
00663 {
00664 case '\'':
00665 case '\\':
00666 case '\"':
00667 fprintf (stream, "\\%c", ch);
00668 break;
00669 case '\n':
00670 fprintf (stream, "\\n");
00671 break;
00672 case '\t':
00673 fprintf (stream, "\\t");
00674 break;
00675 case '\r':
00676 fprintf (stream, "\\r");
00677 break;
00678 default:
00679 if (ch >= ' ' && ch < 127)
00680 putc (ch, stream);
00681 else if (ch < 256)
00682 fprintf (stream, "\\%03x", ch);
00683 else
00684 fprintf (stream, "\\u%04x", ch);
00685 }
00686 }
00687
00688
00689
00690 void
00691 DEFUN(jcf_print_utf8, (stream, str, length),
00692 FILE *stream AND register const unsigned char *str AND int length)
00693 {
00694 const unsigned char * limit = str + length;
00695 while (str < limit)
00696 {
00697 int ch = UTF8_GET (str, limit);
00698 if (ch < 0)
00699 {
00700 fprintf (stream, "\\<invalid>");
00701 return;
00702 }
00703 jcf_print_char (stream, ch);
00704 }
00705 }
00706
00707
00708
00709 void
00710 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
00711 FILE *stream AND const unsigned char *str AND int length
00712 AND int in_char AND int out_char)
00713 {
00714 const unsigned char *limit = str + length;
00715 while (str < limit)
00716 {
00717 int ch = UTF8_GET (str, limit);
00718 if (ch < 0)
00719 {
00720 fprintf (stream, "\\<invalid>");
00721 return;
00722 }
00723 jcf_print_char (stream, ch == in_char ? out_char : ch);
00724 }
00725 }
00726
00727
00728
00729
00730
00731
00732
00733 int
00734 DEFUN(verify_constant_pool, (jcf),
00735 JCF *jcf)
00736 {
00737 int i, n;
00738 for (i = 1; i < JPOOL_SIZE (jcf); i++)
00739 {
00740 switch (JPOOL_TAG (jcf, i))
00741 {
00742 case CONSTANT_NameAndType:
00743 n = JPOOL_USHORT2 (jcf, i);
00744 if (n <= 0 || n >= JPOOL_SIZE(jcf)
00745 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
00746 return i;
00747
00748 case CONSTANT_Class:
00749 case CONSTANT_String:
00750 n = JPOOL_USHORT1 (jcf, i);
00751 if (n <= 0 || n >= JPOOL_SIZE(jcf)
00752 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
00753 return i;
00754 break;
00755 case CONSTANT_Fieldref:
00756 case CONSTANT_Methodref:
00757 case CONSTANT_InterfaceMethodref:
00758 n = JPOOL_USHORT1 (jcf, i);
00759 if (n <= 0 || n >= JPOOL_SIZE(jcf)
00760 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
00761 return i;
00762 n = JPOOL_USHORT2 (jcf, i);
00763 if (n <= 0 || n >= JPOOL_SIZE(jcf)
00764 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
00765 return i;
00766 break;
00767 case CONSTANT_Long:
00768 case CONSTANT_Double:
00769 i++;
00770 break;
00771 case CONSTANT_Float:
00772 case CONSTANT_Integer:
00773 case CONSTANT_Utf8:
00774 case CONSTANT_Unicode:
00775 break;
00776 default:
00777 return i;
00778 }
00779 }
00780 return 0;
00781 }
00782
00783 void
00784 DEFUN(format_uint, (buffer, value, base),
00785 char *buffer AND uint64 value AND int base)
00786 {
00787 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
00788 char buf[WRITE_BUF_SIZE];
00789 register char *buf_ptr = buf+WRITE_BUF_SIZE;
00790 int chars_written;
00791 int i;
00792
00793
00794
00795 do {
00796 int digit = value % base;
00797 static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00798 *--buf_ptr = digit_chars[digit];
00799 value /= base;
00800 } while (value != 0);
00801
00802 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
00803 for (i = 0; i < chars_written; i++)
00804 buffer[i] = *buf_ptr++;
00805 buffer[i] = 0;
00806 }
00807
00808 void
00809 DEFUN(format_int, (buffer, value, base),
00810 char *buffer AND jlong value AND int base)
00811 {
00812 uint64 abs_value;
00813 if (value < 0)
00814 {
00815 abs_value = -(uint64)value;
00816 *buffer++ = '-';
00817 }
00818 else
00819 abs_value = (uint64) value;
00820 format_uint (buffer, abs_value, base);
00821 }