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
00026
00027 #include "config.h"
00028 #include "system.h"
00029 #include <math.h>
00030
00031 #include "jcf.h"
00032 #include "tree.h"
00033 #include "javaop.h"
00034 #include "java-tree.h"
00035 #include "java-opcodes.h"
00036
00037 #include <getopt.h>
00038
00039
00040
00041
00042 FILE *out = NULL;
00043
00044
00045 static int found_error = 0;
00046
00047
00048 static int flag_jni = 0;
00049
00050
00051
00052 int flag_newer = 1;
00053
00054
00055 const char *output_directory = "";
00056
00057
00058 const char *temp_directory = "/tmp";
00059
00060
00061 static int friend_count;
00062
00063
00064
00065 static char **friend_specs = NULL;
00066
00067
00068 static int prepend_count;
00069
00070
00071 static char **prepend_specs = NULL;
00072
00073
00074 static int add_count;
00075
00076
00077 static char **add_specs = NULL;
00078
00079
00080 static int append_count;
00081
00082
00083 static char **append_specs = NULL;
00084
00085 int verbose = 0;
00086
00087 int stubs = 0;
00088
00089 struct JCF *current_jcf;
00090
00091
00092
00093
00094 static JCF_u2 last_access;
00095
00096
00097
00098 #define METHOD_IS_FINAL(Class, Method) \
00099 (((Class) & ACC_FINAL) || ((Method) & (ACC_FINAL | ACC_PRIVATE)))
00100
00101
00102
00103 #define METHOD_IS_NATIVE(Method) \
00104 ((Method) & ACC_NATIVE)
00105
00106
00107
00108 struct method_name
00109 {
00110 unsigned char *name;
00111 int length;
00112 unsigned char *signature;
00113 int sig_length;
00114 struct method_name *next;
00115 };
00116
00117
00118 static struct method_name *method_name_list;
00119
00120 static void print_field_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
00121 static void print_mangled_classname PARAMS ((FILE*, JCF*, const char*, int));
00122 static int print_cxx_classname PARAMS ((FILE*, const char*, JCF*, int));
00123 static void print_method_info PARAMS ((FILE*, JCF*, int, int, JCF_u2));
00124 static void print_c_decl PARAMS ((FILE*, JCF*, int, int, int, const char *,
00125 int));
00126 static void print_stub_or_jni PARAMS ((FILE*, JCF*, int, int, int,
00127 const char *, int));
00128 static void print_full_cxx_name PARAMS ((FILE*, JCF*, int, int, int,
00129 const char *, int));
00130 static void decompile_method PARAMS ((FILE*, JCF*, int));
00131 static void add_class_decl PARAMS ((FILE*, JCF*, JCF_u2));
00132
00133 static int java_float_finite PARAMS ((jfloat));
00134 static int java_double_finite PARAMS ((jdouble));
00135 static void print_name PARAMS ((FILE *, JCF *, int));
00136 static void print_base_classname PARAMS ((FILE *, JCF *, int));
00137 static int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
00138 static char *cxx_keyword_subst PARAMS ((const unsigned char *, int));
00139 static void generate_access PARAMS ((FILE *, JCF_u2));
00140 static int name_is_method_p PARAMS ((const unsigned char *, int));
00141 static char *get_field_name PARAMS ((JCF *, int, JCF_u2));
00142 static void print_field_name PARAMS ((FILE *, JCF *, int, JCF_u2));
00143 static const unsigned char *super_class_name PARAMS ((JCF *, int *));
00144 static void print_include PARAMS ((FILE *, const unsigned char *, int));
00145 static const unsigned char *decode_signature_piece
00146 PARAMS ((FILE *, const unsigned char *, const unsigned char *, int *));
00147 static void print_class_decls PARAMS ((FILE *, JCF *, int));
00148 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
00149 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
00150 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
00151 static int overloaded_jni_method_exists_p PARAMS ((const unsigned char *, int,
00152 const char *, int));
00153 static void jni_print_char PARAMS ((FILE *, int));
00154 static void decompile_return_statement PARAMS ((FILE *, JCF *, int, int, int));
00155
00156 JCF_u2 current_field_name;
00157 JCF_u2 current_field_value;
00158 JCF_u2 current_field_signature;
00159 JCF_u2 current_field_flags;
00160
00161 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
00162 ( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
00163 current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
00164
00165
00166
00167
00168 static int field_pass;
00169
00170
00171
00172 static int method_pass;
00173
00174 #define HANDLE_END_FIELD() \
00175 if (field_pass) \
00176 { \
00177 if (out && ! stubs && ! flag_jni) \
00178 print_field_info (out, jcf, current_field_name, \
00179 current_field_signature, \
00180 current_field_flags); \
00181 } \
00182 else if (! stubs && ! flag_jni) \
00183 add_class_decl (out, jcf, current_field_signature);
00184
00185 #define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
00186
00187 static int method_declared = 0;
00188 static int method_access = 0;
00189 static int method_printed = 0;
00190 static int method_synthetic = 0;
00191 static int method_signature = 0;
00192
00193 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
00194 { \
00195 method_synthetic = 0; \
00196 method_printed = 0; \
00197 decompiled = 0; \
00198 method_signature = SIGNATURE; \
00199 if (ATTRIBUTE_COUNT) \
00200 method_synthetic = peek_attribute (jcf, ATTRIBUTE_COUNT, \
00201 (const char *)"Synthetic", 9); \
00202
00203
00204
00205 \
00206 if (method_synthetic) \
00207 { \
00208 skip_attribute (jcf, ATTRIBUTE_COUNT); \
00209 ATTRIBUTE_COUNT = 0; \
00210 } \
00211 if (method_pass && !method_synthetic) \
00212 { \
00213 if (out) \
00214 print_method_info (out, jcf, NAME, SIGNATURE, \
00215 ACCESS_FLAGS); \
00216 } \
00217 else if (!method_synthetic) \
00218 { \
00219 print_method_info (NULL, jcf, NAME, SIGNATURE, \
00220 ACCESS_FLAGS); \
00221 if (! stubs && ! flag_jni) \
00222 add_class_decl (out, jcf, SIGNATURE); \
00223 } \
00224 }
00225
00226 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
00227 if (out && method_declared) decompile_method (out, jcf, CODE_LENGTH);
00228
00229 static int decompiled = 0;
00230 #define HANDLE_END_METHOD() \
00231 if (out && method_printed && !method_synthetic) \
00232 fputs (decompiled || stubs ? "\n" : ";\n", out);
00233
00234
00235 #define NEED_PEEK_ATTRIBUTE
00236 #define NEED_SKIP_ATTRIBUTE
00237
00238 #include "jcf-reader.c"
00239
00240
00241 #define F_NAN_MASK 0x7f800000
00242 #if (1 == HOST_FLOAT_WORDS_BIG_ENDIAN) && ! defined (HOST_WORDS_BIG_ENDIAN)
00243 #define D_NAN_MASK 0x000000007ff00000LL
00244 #else
00245 #define D_NAN_MASK 0x7ff0000000000000LL
00246 #endif
00247
00248
00249 static int
00250 java_float_finite (f)
00251 jfloat f;
00252 {
00253 union Word u;
00254 u.f = f;
00255
00256
00257
00258
00259 return (u.i & F_NAN_MASK) != F_NAN_MASK;
00260 }
00261
00262
00263 static int
00264 java_double_finite (d)
00265 jdouble d;
00266 {
00267 union DWord u;
00268 u.d = d;
00269
00270
00271 return (u.l & D_NAN_MASK) != D_NAN_MASK;
00272 }
00273
00274
00275
00276 static void
00277 jni_print_char (stream, ch)
00278 FILE *stream;
00279 int ch;
00280 {
00281 if (! flag_jni)
00282 jcf_print_char (stream, ch);
00283 else if (ch == '(' || ch == ')')
00284 {
00285
00286 }
00287 else if (ch == '_')
00288 fputs ("_1", stream);
00289 else if (ch == ';')
00290 fputs ("_2", stream);
00291 else if (ch == '[')
00292 fputs ("_3", stream);
00293 else if (ch == '/')
00294 fputs ("_", stream);
00295 else if (ISALNUM (ch))
00296 fputc (ch, stream);
00297 else
00298 {
00299
00300 fprintf (stream, "_0%04x", ch);
00301 }
00302 }
00303
00304
00305
00306
00307 static void
00308 DEFUN(print_name, (stream, jcf, name_index),
00309 FILE* stream AND JCF* jcf AND int name_index)
00310 {
00311 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
00312 {
00313 fprintf (stream, "<not a UTF8 constant>");
00314 found_error = 1;
00315 }
00316 else if (! flag_jni)
00317 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
00318 JPOOL_UTF_LENGTH (jcf, name_index));
00319 else
00320 {
00321
00322 const unsigned char *str = JPOOL_UTF_DATA (jcf, name_index);
00323 int length = JPOOL_UTF_LENGTH (jcf, name_index);
00324 const unsigned char *limit = str + length;
00325 while (str < limit)
00326 {
00327 int ch = UTF8_GET (str, limit);
00328 if (ch < 0)
00329 {
00330 fprintf (stream, "\\<invalid>");
00331 return;
00332 }
00333 jni_print_char (stream, ch);
00334 }
00335 }
00336 }
00337
00338
00339
00340
00341 static void
00342 print_base_classname (stream, jcf, index)
00343 FILE *stream;
00344 JCF *jcf;
00345 int index;
00346 {
00347 int name_index = JPOOL_USHORT1 (jcf, index);
00348 int len;
00349 const unsigned char *s, *p, *limit;
00350
00351 s = JPOOL_UTF_DATA (jcf, name_index);
00352 len = JPOOL_UTF_LENGTH (jcf, name_index);
00353 limit = s + len;
00354 p = s;
00355 while (s < limit)
00356 {
00357 int c = UTF8_GET (s, limit);
00358 if (c == '/')
00359 p = s;
00360 }
00361
00362 while (p < limit)
00363 {
00364 int ch = UTF8_GET (p, limit);
00365 if (ch == '/')
00366 fputs ("::", stream);
00367 else
00368 jcf_print_char (stream, ch);
00369 }
00370 }
00371
00372
00373
00374
00375 static int
00376 utf8_cmp (str, length, name)
00377 const unsigned char *str;
00378 int length;
00379 const char *name;
00380 {
00381 const unsigned char *limit = str + length;
00382 int i;
00383
00384 for (i = 0; name[i]; ++i)
00385 {
00386 int ch = UTF8_GET (str, limit);
00387 if (ch != name[i])
00388 return ch - name[i];
00389 }
00390
00391 return str == limit ? 0 : 1;
00392 }
00393
00394
00395
00396 static const char *const cxx_keywords[] =
00397 {
00398 "_Complex",
00399 "__alignof",
00400 "__alignof__",
00401 "__asm",
00402 "__asm__",
00403 "__attribute",
00404 "__attribute__",
00405 "__builtin_va_arg",
00406 "__complex",
00407 "__complex__",
00408 "__const",
00409 "__const__",
00410 "__extension__",
00411 "__imag",
00412 "__imag__",
00413 "__inline",
00414 "__inline__",
00415 "__label__",
00416 "__null",
00417 "__real",
00418 "__real__",
00419 "__restrict",
00420 "__restrict__",
00421 "__signed",
00422 "__signed__",
00423 "__typeof",
00424 "__typeof__",
00425 "__volatile",
00426 "__volatile__",
00427 "and",
00428 "and_eq",
00429 "asm",
00430 "auto",
00431 "bitand",
00432 "bitor",
00433 "bool",
00434 "break",
00435 "case",
00436 "catch",
00437 "char",
00438 "class",
00439 "compl",
00440 "const",
00441 "const_cast",
00442 "continue",
00443 "default",
00444 "delete",
00445 "do",
00446 "double",
00447 "dynamic_cast",
00448 "else",
00449 "enum",
00450 "explicit",
00451 "export",
00452 "extern",
00453 "false",
00454 "float",
00455 "for",
00456 "friend",
00457 "goto",
00458 "if",
00459 "inline",
00460 "int",
00461 "long",
00462 "mutable",
00463 "namespace",
00464 "new",
00465 "not",
00466 "not_eq",
00467 "operator",
00468 "or",
00469 "or_eq",
00470 "private",
00471 "protected",
00472 "public",
00473 "register",
00474 "reinterpret_cast",
00475 "return",
00476 "short",
00477 "signed",
00478 "sizeof",
00479 "static",
00480 "static_cast",
00481 "struct",
00482 "switch",
00483 "template",
00484 "this",
00485 "throw",
00486 "true",
00487 "try",
00488 "typedef",
00489 "typeid",
00490 "typename",
00491 "typeof",
00492 "union",
00493 "unsigned",
00494 "using",
00495 "virtual",
00496 "void",
00497 "volatile",
00498 "wchar_t",
00499 "while",
00500 "xor",
00501 "xor_eq"
00502 };
00503
00504
00505
00506
00507
00508
00509 static char *
00510 cxx_keyword_subst (str, length)
00511 const unsigned char *str;
00512 int length;
00513 {
00514 int last = ARRAY_SIZE (cxx_keywords);
00515 int first = 0;
00516 int mid = (last + first) / 2;
00517 int old = -1;
00518
00519 for (mid = (last + first) / 2;
00520 mid != old;
00521 old = mid, mid = (last + first) / 2)
00522 {
00523 int kwl = strlen (cxx_keywords[mid]);
00524 int min_length = kwl > length ? length : kwl;
00525 int r = utf8_cmp (str, min_length, cxx_keywords[mid]);
00526
00527 if (r == 0)
00528 {
00529 int i;
00530
00531
00532 for (i = min_length; i < length && str[i] == '$'; ++i)
00533 ;
00534
00535
00536 if (i == length)
00537 {
00538 char *dup = xmalloc (2 + length - min_length + kwl);
00539 strcpy (dup, cxx_keywords[mid]);
00540 for (i = kwl; i < length + 1; ++i)
00541 dup[i] = '$';
00542 dup[i] = '\0';
00543 return dup;
00544 }
00545 r = 1;
00546 }
00547
00548 if (r < 0)
00549 last = mid;
00550 else
00551 first = mid;
00552 }
00553 return NULL;
00554 }
00555
00556
00557
00558 static void
00559 generate_access (stream, flags)
00560 FILE *stream;
00561 JCF_u2 flags;
00562 {
00563 if ((flags & ACC_VISIBILITY) == last_access)
00564 return;
00565 last_access = (flags & ACC_VISIBILITY);
00566
00567 switch (last_access)
00568 {
00569 case 0:
00570 fputs ("public: // actually package-private\n", stream);
00571 break;
00572 case ACC_PUBLIC:
00573 fputs ("public:\n", stream);
00574 break;
00575 case ACC_PRIVATE:
00576 fputs ("private:\n", stream);
00577 break;
00578 case ACC_PROTECTED:
00579 fputs ("public: // actually protected\n", stream);
00580 break;
00581 default:
00582 found_error = 1;
00583 fprintf (stream, "#error unrecognized visibility %d\n",
00584 (flags & ACC_VISIBILITY));
00585 break;
00586 }
00587 }
00588
00589
00590 static int
00591 name_is_method_p (name, length)
00592 const unsigned char *name;
00593 int length;
00594 {
00595 struct method_name *p;
00596
00597 for (p = method_name_list; p != NULL; p = p->next)
00598 {
00599 if (p->length == length && ! memcmp (p->name, name, length))
00600 return 1;
00601 }
00602 return 0;
00603 }
00604
00605
00606
00607 static int
00608 overloaded_jni_method_exists_p (name, length, signature, sig_length)
00609 const unsigned char *name;
00610 int length;
00611 const char *signature;
00612 int sig_length;
00613 {
00614 struct method_name *p;
00615
00616 for (p = method_name_list; p != NULL; p = p->next)
00617 {
00618 if (p->length == length
00619 && ! memcmp (p->name, name, length)
00620 && (p->sig_length != sig_length
00621 || memcmp (p->signature, signature, sig_length)))
00622 return 1;
00623 }
00624 return 0;
00625 }
00626
00627
00628 static char *
00629 get_field_name (jcf, name_index, flags)
00630 JCF *jcf;
00631 int name_index;
00632 JCF_u2 flags;
00633 {
00634 unsigned char *name = JPOOL_UTF_DATA (jcf, name_index);
00635 int length = JPOOL_UTF_LENGTH (jcf, name_index);
00636 char *override;
00637
00638 if (name_is_method_p (name, length))
00639 {
00640
00641
00642
00643
00644 if ((flags & ACC_STATIC))
00645 {
00646 fprintf (stderr, "static field has same name as method\n");
00647 found_error = 1;
00648 return NULL;
00649 }
00650
00651 override = xmalloc (length + 3);
00652 memcpy (override, name, length);
00653 strcpy (override + length, "__");
00654 }
00655 else
00656 override = cxx_keyword_subst (name, length);
00657
00658 return override;
00659 }
00660
00661
00662
00663 static void
00664 print_field_name (stream, jcf, name_index, flags)
00665 FILE *stream;
00666 JCF *jcf;
00667 int name_index;
00668 JCF_u2 flags;
00669 {
00670 char *override = get_field_name (jcf, name_index, flags);
00671
00672 if (override)
00673 {
00674 fputs (override, stream);
00675 free (override);
00676 }
00677 else
00678 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index),
00679 JPOOL_UTF_LENGTH (jcf, name_index));
00680 }
00681
00682 static void
00683 DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
00684 FILE *stream AND JCF* jcf
00685 AND int name_index AND int sig_index AND JCF_u2 flags)
00686 {
00687 char *override = NULL;
00688
00689 generate_access (stream, flags);
00690 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
00691 {
00692 fprintf (stream, "<not a UTF8 constant>");
00693 found_error = 1;
00694 return;
00695 }
00696
00697 fputs (" ", out);
00698 if ((flags & ACC_STATIC))
00699 fputs ("static ", out);
00700
00701 if ((flags & ACC_FINAL))
00702 {
00703 if (current_field_value > 0)
00704 {
00705 char buffer[25];
00706 int done = 1;
00707
00708 switch (JPOOL_TAG (jcf, current_field_value))
00709 {
00710 case CONSTANT_Integer:
00711 {
00712 jint num;
00713 int most_negative = 0;
00714 fputs ("const jint ", out);
00715 print_field_name (out, jcf, name_index, 0);
00716 fputs (" = ", out);
00717 num = JPOOL_INT (jcf, current_field_value);
00718
00719
00720 if (num == (jint) 0x80000000)
00721 {
00722 most_negative = 1;
00723 ++num;
00724 }
00725 format_int (buffer, (jlong) num, 10);
00726 fprintf (out, "%sL%s;\n", buffer, most_negative ? " - 1" : "");
00727 }
00728 break;
00729 case CONSTANT_Long:
00730 {
00731 jlong num;
00732 int most_negative = 0;
00733 fputs ("const jlong ", out);
00734 print_field_name (out, jcf, name_index, 0);
00735 fputs (" = ", out);
00736 num = JPOOL_LONG (jcf, current_field_value);
00737
00738
00739 if (num == (jlong) 0x8000000000000000LL)
00740 {
00741 most_negative = 1;
00742 ++num;
00743 }
00744 format_int (buffer, num, 10);
00745 fprintf (out, "%sLL%s;\n", buffer, most_negative ? " - 1" :"");
00746 }
00747 break;
00748 case CONSTANT_Float:
00749 {
00750 jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
00751 fputs ("const jfloat ", out);
00752 print_field_name (out, jcf, name_index, 0);
00753 if (! java_float_finite (fnum))
00754 fputs (";\n", out);
00755 else
00756 fprintf (out, " = %.10g;\n", fnum);
00757 }
00758 break;
00759 case CONSTANT_Double:
00760 {
00761 jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
00762 fputs ("const jdouble ", out);
00763 print_field_name (out, jcf, name_index, 0);
00764 if (! java_double_finite (dnum))
00765 fputs (";\n", out);
00766 else
00767 fprintf (out, " = %.17g;\n", dnum);
00768 }
00769 break;
00770 default:
00771
00772
00773 done = 0;
00774 break;
00775 }
00776
00777 if (done)
00778 return;
00779 }
00780 }
00781
00782 override = get_field_name (jcf, name_index, flags);
00783 print_c_decl (out, jcf, name_index, sig_index, 0, override, flags);
00784 fputs (";\n", out);
00785
00786 if (override)
00787 free (override);
00788 }
00789
00790
00791 static void
00792 DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
00793 FILE *stream AND JCF* jcf
00794 AND int name_index AND int sig_index AND JCF_u2 flags)
00795 {
00796 const unsigned char *str;
00797 int length, is_init = 0;
00798 char *override = NULL;
00799
00800 method_declared = 0;
00801 method_access = flags;
00802 if (stream && JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
00803 fprintf (stream, "<not a UTF8 constant>");
00804 str = JPOOL_UTF_DATA (jcf, name_index);
00805 length = JPOOL_UTF_LENGTH (jcf, name_index);
00806
00807 if (str[0] == '<')
00808 {
00809
00810
00811 if (! utf8_cmp (str, length, "<init>"))
00812 is_init = 1;
00813 else if (! METHOD_IS_FINAL (jcf->access_flags, flags)
00814 && ! (flags & ACC_STATIC))
00815 {
00816
00817
00818 fprintf (stderr, "ignored method `");
00819 jcf_print_utf8 (stderr, str, length);
00820 fprintf (stderr, "' marked virtual\n");
00821 found_error = 1;
00822 return;
00823 }
00824 else
00825 return;
00826 }
00827
00828
00829
00830 if (! stream)
00831 {
00832 struct method_name *nn;
00833
00834 nn = (struct method_name *) xmalloc (sizeof (struct method_name));
00835 nn->name = (char *) xmalloc (length);
00836 memcpy (nn->name, str, length);
00837 nn->length = length;
00838 nn->next = method_name_list;
00839 nn->sig_length = JPOOL_UTF_LENGTH (jcf, sig_index);
00840 nn->signature = (char *) xmalloc (nn->sig_length);
00841 memcpy (nn->signature, JPOOL_UTF_DATA (jcf, sig_index),
00842 nn->sig_length);
00843 method_name_list = nn;
00844
00845
00846 return;
00847 }
00848
00849
00850 if (! flag_jni)
00851 {
00852
00853
00854
00855
00856
00857 override = cxx_keyword_subst (str, length);
00858 }
00859
00860 if (! stubs && ! flag_jni)
00861 {
00862 method_printed = 1;
00863
00864 generate_access (stream, flags);
00865
00866 fputs (" ", out);
00867 if ((flags & ACC_STATIC))
00868 fputs ("static ", out);
00869 else if (! METHOD_IS_FINAL (jcf->access_flags, flags))
00870 {
00871
00872 if (! is_init)
00873 fputs ("virtual ", out);
00874 }
00875 print_c_decl (out, jcf, name_index, sig_index, is_init, override, flags);
00876
00877 if ((flags & ACC_ABSTRACT))
00878 fputs (" = 0", out);
00879 else
00880 method_declared = 1;
00881 }
00882 else
00883 {
00884 if (METHOD_IS_NATIVE (flags))
00885 {
00886 method_printed = 1;
00887 print_stub_or_jni (out, jcf, name_index, sig_index,
00888 is_init, override, flags);
00889 }
00890 }
00891
00892 if (override)
00893 free (override);
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903 static void
00904 decompile_return_statement (out, jcf, methodtype, nameindex, objecttype)
00905 FILE *out;
00906 JCF *jcf;
00907 int methodtype, nameindex, objecttype;
00908 {
00909 int cast = 0;
00910 int obj_name_len, method_name_len;
00911 const unsigned char *obj_data, *method_data;
00912
00913 obj_name_len = JPOOL_UTF_LENGTH (jcf, objecttype);
00914 obj_data = JPOOL_UTF_DATA (jcf, objecttype);
00915
00916 method_name_len = JPOOL_UTF_LENGTH (jcf, methodtype);
00917 method_data = JPOOL_UTF_DATA (jcf, methodtype);
00918
00919
00920 while (*method_data != ')')
00921 {
00922 ++method_data;
00923 --method_name_len;
00924 }
00925
00926 ++method_data;
00927 --method_name_len;
00928
00929
00930 if (method_data[0] == 'L' && method_data[method_name_len - 1] == ';')
00931 {
00932 ++method_data;
00933 method_name_len -= 2;
00934 }
00935 if (obj_data[0] == 'L' && obj_data[obj_name_len - 1] == ';')
00936 {
00937 ++obj_data;
00938 obj_name_len -= 2;
00939 }
00940
00941
00942
00943
00944 if (method_name_len != obj_name_len)
00945 cast = 1;
00946 else
00947 {
00948 int i;
00949 for (i = 0; i < method_name_len; ++i)
00950 {
00951 if (method_data[i] != obj_data[i])
00952 {
00953 cast = 1;
00954 break;
00955 }
00956 }
00957 }
00958
00959 fputs (" { return ", out);
00960
00961 if (cast)
00962 {
00963 int array_depth = 0;
00964 const unsigned char *limit;
00965
00966 fputs ("reinterpret_cast<", out);
00967
00968 while (*method_data == '[')
00969 {
00970 ++method_data;
00971 ++array_depth;
00972 --method_name_len;
00973 fputs ("JArray<", out);
00974 }
00975
00976
00977 fputs (" ::", out);
00978
00979
00980
00981
00982 if (array_depth && method_data[0] == 'L'
00983 && method_data[method_name_len - 1] == ';')
00984 {
00985 ++method_data;
00986 method_name_len -= 2;
00987 }
00988
00989 limit = method_data + method_name_len;
00990 while (method_data < limit)
00991 {
00992 int ch = UTF8_GET (method_data, limit);
00993 if (ch == '/')
00994 fputs ("::", out);
00995 else
00996 jcf_print_char (out, ch);
00997 }
00998 fputs (" *", out);
00999
01000
01001 while (array_depth > 0)
01002 {
01003 fputs ("> *", out);
01004 --array_depth;
01005 }
01006
01007
01008 fputs ("> (", out);
01009 }
01010
01011 if (nameindex == -1)
01012 fputs ("this", out);
01013 else
01014 print_field_name (out, jcf, nameindex, 0);
01015
01016 if (cast)
01017 fputs (")", out);
01018
01019 fputs ("; }", out);
01020 }
01021
01022
01023
01024
01025 static void
01026 decompile_method (out, jcf, code_len)
01027 FILE *out;
01028 JCF *jcf;
01029 int code_len;
01030 {
01031 const unsigned char *codes = jcf->read_ptr;
01032 int index;
01033 uint16 name_and_type, name;
01034
01035
01036 if ((method_access & ACC_SYNCHRONIZED))
01037 return;
01038
01039 if (code_len == 5
01040 && codes[0] == OPCODE_aload_0
01041 && codes[1] == OPCODE_getfield
01042 && (codes[4] == OPCODE_areturn
01043 || codes[4] == OPCODE_dreturn
01044 || codes[4] == OPCODE_freturn
01045 || codes[4] == OPCODE_ireturn
01046 || codes[4] == OPCODE_lreturn))
01047 {
01048
01049 index = (codes[2] << 8) | codes[3];
01050
01051 name_and_type = JPOOL_USHORT2 (jcf, index);
01052
01053 name = JPOOL_USHORT1 (jcf, name_and_type);
01054 if (codes[4] == OPCODE_areturn)
01055 decompile_return_statement (out, jcf, method_signature,
01056 name, JPOOL_USHORT2 (jcf, name_and_type));
01057 else
01058 {
01059 fputs (" { return ", out);
01060
01061 print_field_name (out, jcf, name, 0);
01062 fputs ("; }", out);
01063 }
01064 decompiled = 1;
01065 }
01066 else if (code_len == 2
01067 && codes[0] == OPCODE_aload_0
01068 && codes[1] == OPCODE_areturn
01069
01070
01071 && ! (method_access & ACC_STATIC))
01072 {
01073 decompile_return_statement (out, jcf, method_signature, -1,
01074 JPOOL_USHORT1 (jcf, jcf->this_class));
01075 decompiled = 1;
01076 }
01077 else if (code_len == 1 && codes[0] == OPCODE_return)
01078 {
01079
01080 fputs (" { }", out);
01081 decompiled = 1;
01082 }
01083 else if (code_len == 2
01084 && codes[0] == OPCODE_aconst_null
01085 && codes[1] == OPCODE_areturn)
01086 {
01087
01088
01089 fputs (" { return 0; }", out);
01090 decompiled = 1;
01091 }
01092 }
01093
01094
01095
01096 static const unsigned char *
01097 decode_signature_piece (stream, signature, limit, need_space)
01098 FILE *stream;
01099 const unsigned char *signature, *limit;
01100 int *need_space;
01101 {
01102 const char *ctype;
01103 int array_depth = 0;
01104
01105 switch (signature[0])
01106 {
01107 case '[':
01108
01109
01110 array_loop:
01111 for (signature++; (signature < limit
01112 && ISDIGIT (*signature)); signature++)
01113 ;
01114 switch (*signature)
01115 {
01116 case 'B':
01117 ctype = "jbyteArray";
01118 break;
01119 case 'C':
01120 ctype = "jcharArray";
01121 break;
01122 case 'D':
01123 ctype = "jdoubleArray";
01124 break;
01125 case 'F':
01126 ctype = "jfloatArray";
01127 break;
01128 case 'I':
01129 ctype = "jintArray";
01130 break;
01131 case 'S':
01132 ctype = "jshortArray";
01133 break;
01134 case 'J':
01135 ctype = "jlongArray";
01136 break;
01137 case 'Z':
01138 ctype = "jbooleanArray";
01139 break;
01140 case '[':
01141
01142 ++array_depth;
01143 if (! flag_jni)
01144 fputs ("JArray<", stream);
01145 goto array_loop;
01146
01147 case 'L':
01148
01149
01150 ++signature;
01151
01152 if (! flag_jni)
01153 fputs ("JArray< ::", stream);
01154 while (signature < limit && *signature != ';')
01155 {
01156 int ch = UTF8_GET (signature, limit);
01157 if (! flag_jni)
01158 {
01159 if (ch == '/')
01160 fputs ("::", stream);
01161 else
01162 jcf_print_char (stream, ch);
01163 }
01164 }
01165 if (! flag_jni)
01166 fputs (" *> *", stream);
01167 *need_space = 0;
01168 ctype = NULL;
01169 break;
01170 default:
01171
01172 return NULL;
01173 }
01174
01175
01176
01177
01178 if (flag_jni && ctype == NULL)
01179 {
01180 ctype = "jobjectArray";
01181 *need_space = 1;
01182 }
01183
01184
01185 if (ctype != NULL)
01186 goto printit;
01187 ++signature;
01188 break;
01189
01190 case '(':
01191 case ')':
01192
01193 return NULL;
01194
01195 case 'B': ctype = "jbyte"; goto printit;
01196 case 'C': ctype = "jchar"; goto printit;
01197 case 'D': ctype = "jdouble"; goto printit;
01198 case 'F': ctype = "jfloat"; goto printit;
01199 case 'I': ctype = "jint"; goto printit;
01200 case 'J': ctype = "jlong"; goto printit;
01201 case 'S': ctype = "jshort"; goto printit;
01202 case 'Z': ctype = "jboolean"; goto printit;
01203 case 'V': ctype = "void"; goto printit;
01204 case 'L':
01205 if (flag_jni)
01206 {
01207
01208
01209
01210
01211
01212
01213 if (! strncmp (signature, "Ljava/lang/String;",
01214 sizeof ("Ljava/lang/String;") -1))
01215 ctype = "jstring";
01216 else if (! strncmp (signature, "Ljava/lang/Class;",
01217 sizeof ("Ljava/lang/Class;") - 1))
01218 ctype = "jclass";
01219 else if (! strncmp (signature, "Ljava/lang/Throwable;",
01220 sizeof ("Ljava/lang/Throwable;") - 1))
01221 ctype = "jthrowable";
01222 else if (! strncmp (signature, "Ljava/lang/ref/WeakReference;",
01223 sizeof ("Ljava/lang/ref/WeakReference;") - 1))
01224 ctype = "jweak";
01225 else
01226 ctype = "jobject";
01227
01228 while (*signature && *signature != ';')
01229 ++signature;
01230
01231 goto printit;
01232 }
01233
01234 fputs ("::", stream);
01235 ++signature;
01236 while (*signature && *signature != ';')
01237 {
01238 int ch = UTF8_GET (signature, limit);
01239 if (ch == '/')
01240 fputs ("::", stream);
01241 else
01242 jcf_print_char (stream, ch);
01243 }
01244 fputs (" *", stream);
01245 if (*signature == ';')
01246 signature++;
01247 *need_space = 0;
01248 break;
01249 default:
01250 *need_space = 1;
01251 jni_print_char (stream, *signature++);
01252 break;
01253 printit:
01254 signature++;
01255 *need_space = 1;
01256 fputs (ctype, stream);
01257 break;
01258 }
01259
01260 if (! flag_jni)
01261 {
01262 while (array_depth-- > 0)
01263 fputs ("> *", stream);
01264 }
01265
01266 return signature;
01267 }
01268
01269 static void
01270 DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, is_init,
01271 name_override, flags),
01272 FILE* stream AND JCF* jcf
01273 AND int name_index AND int signature_index
01274 AND int is_init AND const char *name_override AND int flags)
01275 {
01276 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
01277 {
01278 fprintf (stream, "<not a UTF8 constant>");
01279 found_error = 1;
01280 }
01281 else
01282 {
01283 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
01284 const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
01285 register const unsigned char *str = str0;
01286 const unsigned char *limit = str + length;
01287 int need_space = 0;
01288 int is_method = str[0] == '(';
01289 const unsigned char *next;
01290
01291
01292
01293
01294 if (is_method && ! is_init)
01295 {
01296 while (str < limit)
01297 {
01298 int ch = *str++;
01299 if (ch == ')')
01300 break;
01301 }
01302 }
01303
01304
01305
01306 if (! is_method || ! is_init)
01307 {
01308 next = decode_signature_piece (stream, str, limit, &need_space);
01309 if (! next)
01310 {
01311 fprintf (stderr, "unparseable signature: `%s'\n", str0);
01312 found_error = 1;
01313 return;
01314 }
01315 }
01316
01317
01318 if (need_space)
01319 fputs (" ", stream);
01320 print_full_cxx_name (stream, jcf, name_index,
01321 signature_index, is_init, name_override,
01322 flags);
01323 }
01324 }
01325
01326
01327 static void
01328 DEFUN(print_full_cxx_name, (stream, jcf, name_index, signature_index,
01329 is_init, name_override, flags),
01330 FILE* stream AND JCF* jcf
01331 AND int name_index AND int signature_index AND int is_init
01332 AND const char *name_override AND int flags)
01333 {
01334 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
01335 const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
01336 register const unsigned char *str = str0;
01337 const unsigned char *limit = str + length;
01338 int need_space = 0;
01339 int is_method = str[0] == '(';
01340 const unsigned char *next;
01341
01342 if (name_override)
01343 fputs (name_override, stream);
01344 else if (name_index)
01345 {
01346
01347 if (is_init)
01348 print_base_classname (stream, jcf, jcf->this_class);
01349 else
01350 print_name (stream, jcf, name_index);
01351 }
01352
01353 if (flag_jni)
01354 {
01355 unsigned char *signature = JPOOL_UTF_DATA (jcf, signature_index);
01356 int sig_len = JPOOL_UTF_LENGTH (jcf, signature_index);
01357 if (overloaded_jni_method_exists_p (JPOOL_UTF_DATA (jcf, name_index),
01358 JPOOL_UTF_LENGTH (jcf, name_index),
01359 signature, sig_len))
01360 {
01361
01362
01363
01364 unsigned char *limit = signature + sig_len;
01365 fputs ("__", stream);
01366 while (signature < limit)
01367 {
01368 int ch = UTF8_GET (signature, limit);
01369 jni_print_char (stream, ch);
01370 if (ch == ')')
01371 {
01372
01373 break;
01374 }
01375 }
01376 }
01377 }
01378
01379 if (is_method)
01380 {
01381
01382
01383 fputs (" (", stream);
01384
01385 str = str0 + 1;
01386
01387
01388 if (flag_jni)
01389 {
01390
01391
01392 fputs ("JNIEnv *env", stream);
01393
01394 fputs ((flags & ACC_STATIC) ? ", jclass" : ", jobject", stream);
01395
01396 if (*str != ')')
01397 fputs (", ", stream);
01398 }
01399
01400 while (str < limit && *str != ')')
01401 {
01402 next = decode_signature_piece (stream, str, limit, &need_space);
01403 if (! next)
01404 {
01405 fprintf (stderr, "unparseable signature: `%s'\n", str0);
01406 found_error = 1;
01407 return;
01408 }
01409
01410 if (next < limit && *next != ')')
01411 fputs (", ", stream);
01412 str = next;
01413 }
01414
01415 fputs (")", stream);
01416 }
01417 }
01418
01419
01420 static void
01421 DEFUN (print_name_for_stub_or_jni, (stream, jcf, name_index, signature_index,
01422 is_init, name_override, flags),
01423 FILE *stream AND JCF *jcf
01424 AND int name_index AND int signature_index
01425 AND int is_init AND const char *name_override AND int flags)
01426 {
01427 const char *const prefix = flag_jni ? "Java_" : "";
01428 print_cxx_classname (stream, prefix, jcf, jcf->this_class);
01429 fputs (flag_jni ? "_" : "::", stream);
01430 print_full_cxx_name (stream, jcf, name_index,
01431 signature_index, is_init, name_override,
01432 flags);
01433 }
01434
01435 static void
01436 DEFUN(print_stub_or_jni, (stream, jcf, name_index, signature_index, is_init,
01437 name_override, flags),
01438 FILE* stream AND JCF* jcf
01439 AND int name_index AND int signature_index
01440 AND int is_init AND const char *name_override AND int flags)
01441 {
01442 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
01443 {
01444 fprintf (stream, "<not a UTF8 constant>");
01445 found_error = 1;
01446 }
01447 else
01448 {
01449 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
01450 const unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index);
01451 register const unsigned char *str = str0;
01452 const unsigned char *limit = str + length;
01453 int need_space = 0;
01454 int is_method = str[0] == '(';
01455 const unsigned char *next;
01456
01457
01458 if (! is_method && flag_jni)
01459 return;
01460
01461 if (flag_jni && ! stubs)
01462 fputs ("extern ", stream);
01463
01464
01465
01466
01467 if (is_method && ! is_init)
01468 {
01469 while (str < limit)
01470 {
01471 int ch = *str++;
01472 if (ch == ')')
01473 break;
01474 }
01475 }
01476
01477
01478
01479
01480 if (! is_method || ! is_init)
01481 {
01482 next = decode_signature_piece (stream, str, limit, &need_space);
01483 if (! next)
01484 {
01485 fprintf (stderr, "unparseable signature: `%s'\n", str0);
01486 found_error = 1;
01487 return;
01488 }
01489 }
01490
01491
01492
01493 fputs (need_space && ! stubs ? " " : "\n", stream);
01494
01495
01496 print_name_for_stub_or_jni (stream, jcf, name_index,
01497 signature_index, is_init, name_override,
01498 flags);
01499
01500
01501 if (stubs)
01502 {
01503 if (flag_jni)
01504 fputs ("\n{\n (*env)->FatalError (\"", stream);
01505 else
01506 fputs ("\n{\n throw new ::java::lang::UnsupportedOperationException (JvNewStringLatin1 (\"", stream);
01507 print_name_for_stub_or_jni (stream, jcf, name_index,
01508 signature_index, is_init,
01509 name_override,
01510 flags);
01511 fprintf (stream, " not implemented\")%s;\n}\n\n",
01512 flag_jni ? "" : ")");
01513 }
01514 }
01515 }
01516
01517 static void
01518 DEFUN(print_mangled_classname, (stream, jcf, prefix, index),
01519 FILE *stream AND JCF *jcf AND const char *prefix AND int index)
01520 {
01521 int name_index = JPOOL_USHORT1 (jcf, index);
01522 fputs (prefix, stream);
01523 jcf_print_utf8_replace (out,
01524 JPOOL_UTF_DATA (jcf, name_index),
01525 JPOOL_UTF_LENGTH (jcf, name_index),
01526 '/', '_');
01527 }
01528
01529
01530
01531
01532 static int
01533 print_cxx_classname (stream, prefix, jcf, index)
01534 FILE *stream;
01535 const char *prefix;
01536 JCF *jcf;
01537 int index;
01538 {
01539 int name_index = JPOOL_USHORT1 (jcf, index);
01540 int len, c;
01541 const unsigned char *s, *p, *limit;
01542
01543 s = JPOOL_UTF_DATA (jcf, name_index);
01544 len = JPOOL_UTF_LENGTH (jcf, name_index);
01545 limit = s + len;
01546
01547
01548 p = s;
01549 c = UTF8_GET (p, limit);
01550 if (c == '[')
01551 return 0;
01552
01553 fputs (prefix, stream);
01554
01555
01556 if (! flag_jni && ! stubs)
01557 fputs ("::", stream);
01558
01559 while (s < limit)
01560 {
01561 c = UTF8_GET (s, limit);
01562 if (c == '/')
01563 fputs (flag_jni ? "_" : "::", stream);
01564 else
01565 jni_print_char (stream, c);
01566 }
01567
01568 return 1;
01569 }
01570
01571 int written_class_count = 0;
01572
01573
01574
01575 static const unsigned char *
01576 super_class_name (derived_jcf, len)
01577 JCF *derived_jcf;
01578 int *len;
01579 {
01580 int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class);
01581 int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index);
01582 const unsigned char *supername =
01583 JPOOL_UTF_DATA (derived_jcf, supername_index);
01584
01585 if (len)
01586 *len = supername_length;
01587
01588 return supername;
01589 }
01590
01591
01592
01593
01594
01595 struct include
01596 {
01597 char *name;
01598 struct include *next;
01599 };
01600
01601
01602 static struct include *all_includes = NULL;
01603
01604
01605 static void
01606 print_include (out, utf8, len)
01607 FILE *out;
01608 const unsigned char *utf8;
01609 int len;
01610 {
01611 struct include *incl;
01612
01613 if (! out)
01614 return;
01615
01616 if (len == -1)
01617 len = strlen (utf8);
01618
01619 for (incl = all_includes; incl; incl = incl->next)
01620 {
01621
01622 if (len == (int) strlen (incl->name)
01623 && ! strncmp (incl->name, utf8, len))
01624 return;
01625 }
01626
01627 incl = (struct include *) xmalloc (sizeof (struct include));
01628 incl->name = xmalloc (len + 1);
01629 strncpy (incl->name, utf8, len);
01630 incl->name[len] = '\0';
01631 incl->next = all_includes;
01632 all_includes = incl;
01633
01634 fputs ("#include <", out);
01635 jcf_print_utf8_replace (out, utf8, len,
01636 '/',
01637 flag_jni ? '_' : '/');
01638 fputs (".h>\n", out);
01639 }
01640
01641
01642
01643
01644 struct namelet
01645 {
01646
01647 char *name;
01648
01649 int is_class;
01650
01651 struct namelet *subnamelets;
01652
01653 struct namelet *next;
01654 };
01655
01656 static void add_namelet PARAMS ((const unsigned char *,
01657 const unsigned char *, struct namelet *));
01658 static void print_namelet PARAMS ((FILE *, struct namelet *, int));
01659
01660
01661 static struct namelet root =
01662 {
01663 NULL,
01664 0,
01665 NULL,
01666 NULL
01667 };
01668
01669
01670
01671
01672 static void
01673 add_namelet (name, name_limit, parent)
01674 const unsigned char *name, *name_limit;
01675 struct namelet *parent;
01676 {
01677 const unsigned char *p;
01678 struct namelet *n = NULL, *np;
01679
01680
01681
01682
01683 if (parent == &root)
01684 {
01685 #define JAVALANG "java/lang/"
01686 #define JAVAIO "java/io/"
01687 #define JAVAUTIL "java/util/"
01688 if ((name_limit - name >= (int) sizeof (JAVALANG) - 1
01689 && ! strncmp (name, JAVALANG, sizeof (JAVALANG) - 1))
01690 || (name_limit - name >= (int) sizeof (JAVAUTIL) - 1
01691 && ! strncmp (name, JAVAUTIL, sizeof (JAVAUTIL) - 1))
01692 || (name_limit - name >= (int) sizeof (JAVAIO) - 1
01693 && ! strncmp (name, JAVAIO, sizeof (JAVAIO) - 1)))
01694 return;
01695 }
01696
01697 for (p = name; p < name_limit && *p != '/'; ++p)
01698 ;
01699
01700
01701 for (np = parent->subnamelets; np != NULL; np = np->next)
01702 {
01703
01704 if ((int) strlen (np->name) == p - name &&
01705 ! strncmp (name, np->name, p - name))
01706 {
01707 n = np;
01708 break;
01709 }
01710 }
01711
01712 if (n == NULL)
01713 {
01714 n = (struct namelet *) xmalloc (sizeof (struct namelet));
01715 n->name = xmalloc (p - name + 1);
01716 strncpy (n->name, name, p - name);
01717 n->name[p - name] = '\0';
01718 n->is_class = (p == name_limit);
01719 n->subnamelets = NULL;
01720 n->next = parent->subnamelets;
01721 parent->subnamelets = n;
01722 }
01723
01724
01725
01726 if (p < name_limit)
01727 add_namelet (p + 1, name_limit, n);
01728 }
01729
01730
01731 static void
01732 print_namelet (out, name, depth)
01733 FILE *out;
01734 struct namelet *name;
01735 int depth;
01736 {
01737 int i, term = 0;
01738 struct namelet *c;
01739
01740 if (name->name)
01741 {
01742 for (i = 0; i < depth; ++i)
01743 fputc (' ', out);
01744 fprintf (out, "%s %s", name->is_class ? "class" : "namespace",
01745 name->name);
01746 if (name->is_class && name->subnamelets == NULL)
01747 fputs (";\n", out);
01748 else
01749 {
01750 term = 1;
01751 fputs ("\n", out);
01752 for (i = 0; i < depth; ++i)
01753 fputc (' ', out);
01754 fputs ("{\n", out);
01755 }
01756 }
01757
01758 c = name->subnamelets;
01759 while (c != NULL)
01760 {
01761 struct namelet *next = c->next;
01762 print_namelet (out, c, depth + 2);
01763 c = next;
01764 }
01765 name->subnamelets = NULL;
01766
01767 if (name->name)
01768 {
01769 if (term)
01770 {
01771 for (i = 0; i < depth; ++i)
01772 fputc (' ', out);
01773 fputs ("}\n", out);
01774
01775 if (name->is_class)
01776 fputs (";", out);
01777 }
01778
01779 free (name->name);
01780 free (name);
01781 }
01782 }
01783
01784
01785
01786
01787 static void
01788 add_class_decl (out, jcf, signature)
01789 FILE *out;
01790 JCF *jcf;
01791 JCF_u2 signature;
01792 {
01793 const unsigned char *s = JPOOL_UTF_DATA (jcf, signature);
01794 int len = JPOOL_UTF_LENGTH (jcf, signature);
01795 int i;
01796
01797 for (i = 0; i < len; ++i)
01798 {
01799 int start;
01800
01801
01802 if (s[i] == '[')
01803 {
01804 print_include (out, "gcj/array", -1);
01805 continue;
01806 }
01807
01808
01809
01810 if (s[i] != 'L')
01811 continue;
01812
01813 for (start = ++i; i < len && s[i] != ';'; ++i)
01814 ;
01815
01816 add_namelet (&s[start], &s[i], &root);
01817 }
01818 }
01819
01820
01821
01822
01823
01824 static void
01825 print_class_decls (out, jcf, self)
01826 FILE *out;
01827 JCF *jcf;
01828 int self;
01829 {
01830
01831
01832 int name_index = JPOOL_USHORT1 (jcf, self);
01833 int len;
01834 const unsigned char *s;
01835
01836 s = JPOOL_UTF_DATA (jcf, name_index);
01837 len = JPOOL_UTF_LENGTH (jcf, name_index);
01838 add_namelet (s, s + len, &root);
01839
01840 if (root.subnamelets)
01841 {
01842 fputs ("extern \"Java\"\n{\n", out);
01843
01844
01845 print_namelet (out, &root, 0);
01846 fputs ("};\n\n", out);
01847 }
01848 }
01849
01850
01851
01852 static void
01853 DEFUN(process_file, (jcf, out),
01854 JCF *jcf AND FILE *out)
01855 {
01856 int code, i;
01857 uint32 field_start, method_end, method_start;
01858
01859 current_jcf = jcf;
01860
01861 last_access = -1;
01862
01863 if (jcf_parse_preamble (jcf) != 0)
01864 {
01865 fprintf (stderr, "Not a valid Java .class file.\n");
01866 found_error = 1;
01867 return;
01868 }
01869
01870
01871 code = jcf_parse_constant_pool (jcf);
01872 if (code != 0)
01873 {
01874 fprintf (stderr, "error while parsing constant pool\n");
01875 found_error = 1;
01876 return;
01877 }
01878 code = verify_constant_pool (jcf);
01879 if (code > 0)
01880 {
01881 fprintf (stderr, "error in constant pool entry #%d\n", code);
01882 found_error = 1;
01883 return;
01884 }
01885
01886 jcf_parse_class (jcf);
01887
01888 if (written_class_count++ == 0 && out)
01889 {
01890 const char *cstart, *cstart2, *mode, *cend, *what, *jflag;
01891 if (flag_jni)
01892 {
01893 cstart = "/*";
01894 cstart2 = " ";
01895 cend = " */";
01896 mode = "";
01897 what = "JNI";
01898 jflag = " -jni";
01899 }
01900 else
01901 {
01902 cstart = "//";
01903 cstart2 = "//";
01904 cend = "";
01905 mode = " -*- c++ -*-";
01906 what = "CNI";
01907 jflag = "";
01908 }
01909
01910 if (! stubs)
01911 fprintf (out, "%s DO NOT EDIT THIS FILE - it is machine generated%s%s\n\n",
01912 cstart, mode, cend);
01913 else
01914 {
01915 fprintf (out, "%s This file was created by `gcjh -stubs%s'.%s\n\
01916 %s\n\
01917 %s This file is intended to give you a head start on implementing native\n\
01918 %s methods using %s.\n\
01919 %s Be aware: running `gcjh -stubs %s' once more for this class may\n\
01920 %s overwrite any edits you have made to this file.%s\n\n",
01921 cstart, jflag, mode,
01922 cstart2,
01923 cstart2,
01924 cstart2,
01925 what,
01926 cstart2,
01927 jflag,
01928 cstart2,
01929 cend);
01930 }
01931 }
01932
01933 if (out)
01934 {
01935 if (! stubs)
01936 {
01937 print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class);
01938 fprintf (out, "__\n");
01939
01940 print_mangled_classname (out, jcf, "#define __", jcf->this_class);
01941 fprintf (out, "__\n\n");
01942
01943 if (flag_jni)
01944 {
01945 fprintf (out, "#include <jni.h>\n\n");
01946 fprintf (out, "#ifdef __cplusplus\n");
01947 fprintf (out, "extern \"C\"\n");
01948 fprintf (out, "{\n");
01949 fprintf (out, "#endif\n");
01950 }
01951 else
01952 {
01953
01954
01955
01956 fprintf (out, "#pragma interface\n");
01957
01958 if (jcf->super_class)
01959 {
01960 int super_length;
01961 const unsigned char *supername =
01962 super_class_name (jcf, &super_length);
01963
01964 fputs ("\n", out);
01965 print_include (out, supername, super_length);
01966 }
01967 }
01968 }
01969 else
01970 {
01971
01972
01973 char *name;
01974 int i, len = strlen (jcf->classname);
01975 if (len > 6 && ! strcmp (&jcf->classname[len - 6], ".class"))
01976 len -= 6;
01977
01978 name = xmalloc (len + 1);
01979 for (i = 0; i < len; ++i)
01980 name[i] = jcf->classname[i] == '.' ? '/' : jcf->classname[i];
01981 name[i] = '\0';
01982 print_include (out, name, len);
01983 free (name);
01984
01985 if (! flag_jni)
01986 {
01987 print_include (out, "gcj/cni", -1);
01988 print_include (out, "java/lang/UnsupportedOperationException",
01989 -1);
01990 }
01991 }
01992 }
01993
01994
01995
01996
01997
01998
01999 field_pass = 0;
02000 field_start = JCF_TELL (jcf);
02001 jcf_parse_fields (jcf);
02002
02003 method_start = JCF_TELL (jcf);
02004 method_pass = 0;
02005 jcf_parse_methods (jcf);
02006
02007 if (out)
02008 fputs ("\n", out);
02009
02010 if (out && ! flag_jni)
02011 {
02012 if (! stubs)
02013 print_class_decls (out, jcf, jcf->this_class);
02014
02015 for (i = 0; i < prepend_count; ++i)
02016 fprintf (out, "%s\n", prepend_specs[i]);
02017 if (prepend_count > 0)
02018 fputc ('\n', out);
02019
02020 if (! stubs)
02021 {
02022 if (! print_cxx_classname (out, "class ", jcf, jcf->this_class))
02023 {
02024 fprintf (stderr, "class is of array type\n");
02025 found_error = 1;
02026 return;
02027 }
02028 if (jcf->super_class)
02029 {
02030 if (! print_cxx_classname (out, " : public ",
02031 jcf, jcf->super_class))
02032 {
02033 fprintf (stderr, "base class is of array type\n");
02034 found_error = 1;
02035 return;
02036 }
02037 }
02038
02039 fputs ("\n{\n", out);
02040 }
02041 }
02042
02043
02044 JCF_SEEK (jcf, method_start);
02045 method_pass = 1;
02046 jcf_parse_methods (jcf);
02047 method_end = JCF_TELL (jcf);
02048
02049 field_pass = 1;
02050 JCF_SEEK (jcf, field_start);
02051 jcf_parse_fields (jcf);
02052 JCF_SEEK (jcf, method_end);
02053
02054 jcf_parse_final_attributes (jcf);
02055
02056 if (out && ! stubs)
02057 {
02058 if (flag_jni)
02059 {
02060 fprintf (out, "\n#ifdef __cplusplus\n");
02061 fprintf (out, "}\n");
02062 fprintf (out, "#endif\n");
02063 }
02064 else
02065 {
02066
02067 for (i = 0; i < friend_count; ++i)
02068 fprintf (out, " friend %s\n", friend_specs[i]);
02069
02070
02071 if (add_count > 0)
02072 fputc ('\n', out);
02073 for (i = 0; i < add_count; ++i)
02074 fprintf (out, " %s\n", add_specs[i]);
02075
02076
02077 generate_access (out, ACC_PUBLIC);
02078 fprintf (out, "\n static ::java::lang::Class class$;\n");
02079
02080 fputs ("}", out);
02081
02082 if (jcf->access_flags & ACC_INTERFACE)
02083 fputs (" __attribute__ ((java_interface))", out);
02084
02085 fputs (";\n", out);
02086
02087 if (append_count > 0)
02088 fputc ('\n', out);
02089 for (i = 0; i < append_count; ++i)
02090 fprintf (out, "%s\n", append_specs[i]);
02091 }
02092
02093 print_mangled_classname (out, jcf,
02094 "\n#endif /* __", jcf->this_class);
02095 fprintf (out, "__ */\n");
02096 }
02097 }
02098
02099
02100
02101
02102 #define LONG_OPT(Num) ((Num) + 128)
02103
02104 #define OPT_classpath LONG_OPT (0)
02105 #define OPT_CLASSPATH OPT_classpath
02106 #define OPT_bootclasspath LONG_OPT (1)
02107 #define OPT_extdirs LONG_OPT (2)
02108 #define OPT_HELP LONG_OPT (3)
02109 #define OPT_TEMP LONG_OPT (4)
02110 #define OPT_VERSION LONG_OPT (5)
02111 #define OPT_PREPEND LONG_OPT (6)
02112 #define OPT_FRIEND LONG_OPT (7)
02113 #define OPT_ADD LONG_OPT (8)
02114 #define OPT_APPEND LONG_OPT (9)
02115 #define OPT_M LONG_OPT (10)
02116 #define OPT_MM LONG_OPT (11)
02117 #define OPT_MG LONG_OPT (12)
02118 #define OPT_MD LONG_OPT (13)
02119 #define OPT_MMD LONG_OPT (14)
02120
02121 static const struct option options[] =
02122 {
02123 { "classpath", required_argument, NULL, OPT_classpath },
02124 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
02125 { "extdirs", required_argument, NULL, OPT_extdirs },
02126 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
02127 { "help", no_argument, NULL, OPT_HELP },
02128 { "stubs", no_argument, &stubs, 1 },
02129 { "td", required_argument, NULL, OPT_TEMP },
02130 { "verbose", no_argument, NULL, 'v' },
02131 { "version", no_argument, NULL, OPT_VERSION },
02132 { "prepend", required_argument, NULL, OPT_PREPEND },
02133 { "friend", required_argument, NULL, OPT_FRIEND },
02134 { "add", required_argument, NULL, OPT_ADD },
02135 { "append", required_argument, NULL, OPT_APPEND },
02136 { "M", no_argument, NULL, OPT_M },
02137 { "MM", no_argument, NULL, OPT_MM },
02138 { "MG", no_argument, NULL, OPT_MG },
02139 { "MD", no_argument, NULL, OPT_MD },
02140 { "MMD", no_argument, NULL, OPT_MMD },
02141 { "jni", no_argument, &flag_jni, 1 },
02142 { NULL, no_argument, NULL, 0 }
02143 };
02144
02145 static void
02146 usage ()
02147 {
02148 fprintf (stderr, "Try `gcjh --help' for more information.\n");
02149 exit (1);
02150 }
02151
02152 static void
02153 help ()
02154 {
02155 printf ("Usage: gcjh [OPTION]... CLASS...\n\n");
02156 printf ("Generate C++ header files from .class files\n\n");
02157 printf (" -stubs Generate an implementation stub file\n");
02158 printf (" -jni Generate a JNI header or stub\n");
02159 printf ("\n");
02160 printf (" -add TEXT Insert TEXT into class body\n");
02161 printf (" -append TEXT Insert TEXT after class declaration\n");
02162 printf (" -friend TEXT Insert TEXT as `friend' declaration\n");
02163 printf (" -prepend TEXT Insert TEXT before start of class\n");
02164 printf ("\n");
02165 printf (" --classpath PATH Set path to find .class files\n");
02166 printf (" -IDIR Append directory to class path\n");
02167 printf (" --bootclasspath PATH Override built-in class path\n");
02168 printf (" --extdirs PATH Set extensions directory path\n");
02169 printf (" -d DIRECTORY Set output directory name\n");
02170 printf (" -o FILE Set output file name\n");
02171 printf (" -td DIRECTORY Set temporary directory name\n");
02172 printf ("\n");
02173 printf (" --help Print this help, then exit\n");
02174 printf (" --version Print version number, then exit\n");
02175 printf (" -v, --verbose Print extra information while running\n");
02176 printf ("\n");
02177 printf (" -M Print all dependencies to stdout;\n");
02178 printf (" suppress ordinary output\n");
02179 printf (" -MM Print non-system dependencies to stdout;\n");
02180 printf (" suppress ordinary output\n");
02181 printf (" -MD Print all dependencies to stdout\n");
02182 printf (" -MMD Print non-system dependencies to stdout\n");
02183
02184 printf ("\n");
02185 printf ("For bug reporting instructions, please see:\n");
02186 printf ("%s.\n", GCCBUGURL);
02187 exit (0);
02188 }
02189
02190 static void
02191 version ()
02192 {
02193 printf ("gcjh (GCC) %s\n\n", version_string);
02194 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
02195 printf ("This is free software; see the source for copying conditions. There is NO\n");
02196 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
02197 exit (0);
02198 }
02199
02200 int
02201 DEFUN(main, (argc, argv),
02202 int argc AND char** argv)
02203 {
02204 JCF jcf;
02205 int argi;
02206 char *output_file = NULL;
02207 int emit_dependencies = 0, suppress_output = 0;
02208 int opt;
02209
02210 if (argc <= 1)
02211 {
02212 fprintf (stderr, "gcjh: no classes specified\n");
02213 usage ();
02214 }
02215
02216 jcf_path_init ();
02217
02218
02219
02220 while ((opt = getopt_long_only (argc, argv, "I:d:o:v", options, NULL)) != -1)
02221 {
02222 switch (opt)
02223 {
02224 case 0:
02225
02226 break;
02227
02228 case 'o':
02229 output_file = optarg;
02230 break;
02231
02232 case 'd':
02233 output_directory = optarg;
02234 break;
02235
02236 case 'I':
02237 jcf_path_include_arg (optarg);
02238 break;
02239
02240 case 'v':
02241 verbose++;
02242 break;
02243
02244 case OPT_classpath:
02245 jcf_path_classpath_arg (optarg);
02246 break;
02247
02248 case OPT_bootclasspath:
02249 jcf_path_bootclasspath_arg (optarg);
02250 break;
02251
02252 case OPT_extdirs:
02253 jcf_path_extdirs_arg (optarg);
02254 break;
02255
02256 case OPT_HELP:
02257 help ();
02258 break;
02259
02260 case OPT_TEMP:
02261 temp_directory = optarg;
02262 break;
02263
02264 case OPT_VERSION:
02265 version ();
02266 break;
02267
02268 case OPT_PREPEND:
02269 if (prepend_count == 0)
02270 prepend_specs = (char**) ALLOC (argc * sizeof (char*));
02271 prepend_specs[prepend_count++] = optarg;
02272 break;
02273
02274 case OPT_FRIEND:
02275 if (friend_count == 0)
02276 friend_specs = (char**) ALLOC (argc * sizeof (char*));
02277 friend_specs[friend_count++] = optarg;
02278 break;
02279
02280 case OPT_ADD:
02281 if (add_count == 0)
02282 add_specs = (char**) ALLOC (argc * sizeof (char*));
02283 add_specs[add_count++] = optarg;
02284 break;
02285
02286 case OPT_APPEND:
02287 if (append_count == 0)
02288 append_specs = (char**) ALLOC (argc * sizeof (char*));
02289 append_specs[append_count++] = optarg;
02290 break;
02291
02292 case OPT_M:
02293 emit_dependencies = 1;
02294 suppress_output = 1;
02295 jcf_dependency_init (1);
02296 break;
02297
02298 case OPT_MM:
02299 emit_dependencies = 1;
02300 suppress_output = 1;
02301 jcf_dependency_init (0);
02302 break;
02303
02304 case OPT_MG:
02305 fprintf (stderr, "gcjh: `-MG' option is unimplemented\n");
02306 exit (1);
02307
02308 case OPT_MD:
02309 emit_dependencies = 1;
02310 jcf_dependency_init (1);
02311 break;
02312
02313 case OPT_MMD:
02314 emit_dependencies = 1;
02315 jcf_dependency_init (0);
02316 break;
02317
02318 default:
02319 usage ();
02320 break;
02321 }
02322 }
02323
02324 if (optind == argc)
02325 {
02326 fprintf (stderr, "gcjh: no classes specified\n");
02327 usage ();
02328 }
02329
02330 jcf_path_seal (verbose);
02331
02332 if (output_file && emit_dependencies)
02333 {
02334 fprintf (stderr, "gcjh: can't specify both -o and -MD\n");
02335 exit (1);
02336 }
02337
02338 for (argi = optind; argi < argc; argi++)
02339 {
02340 char *classname = argv[argi];
02341 char *current_output_file;
02342 const char *classfile_name;
02343
02344 if (verbose)
02345 fprintf (stderr, "Processing %s\n", classname);
02346 if (! output_file)
02347 jcf_dependency_reset ();
02348 classfile_name = find_class (classname, strlen (classname), &jcf, 0);
02349 if (classfile_name == NULL)
02350 {
02351 fprintf (stderr, "%s: no such class\n", classname);
02352 exit (1);
02353 }
02354 if (verbose)
02355 fprintf (stderr, "Found in %s\n", classfile_name);
02356 if (output_file)
02357 {
02358 if (strcmp (output_file, "-") == 0)
02359 out = stdout;
02360 else if (out == NULL)
02361 {
02362 out = fopen (output_file, "w");
02363 }
02364 if (out == NULL)
02365 {
02366 perror (output_file);
02367 exit (1);
02368 }
02369 current_output_file = output_file;
02370 }
02371 else
02372 {
02373 int dir_len = strlen (output_directory);
02374 int i, classname_length = strlen (classname);
02375 current_output_file = (char*) ALLOC (dir_len + classname_length + 5);
02376 strcpy (current_output_file, output_directory);
02377 if (dir_len > 0 && output_directory[dir_len-1] != '/')
02378 current_output_file[dir_len++] = '/';
02379 for (i = 0; classname[i] != '\0'; i++)
02380 {
02381 char ch = classname[i];
02382 if (ch == '.')
02383 ch = '/';
02384 if (flag_jni && ch == '/')
02385 ch = '_';
02386 current_output_file[dir_len++] = ch;
02387 }
02388 if (emit_dependencies)
02389 {
02390 if (suppress_output)
02391 {
02392 jcf_dependency_set_dep_file ("-");
02393 out = NULL;
02394 }
02395 else
02396 {
02397
02398
02399 strcpy (current_output_file + dir_len, ".hd");
02400 jcf_dependency_set_dep_file (current_output_file);
02401 }
02402 }
02403 strcpy (current_output_file + dir_len,
02404 stubs ? (flag_jni ? ".c" : ".cc") : ".h");
02405 jcf_dependency_set_target (current_output_file);
02406 if (! suppress_output)
02407 {
02408 out = fopen (current_output_file, "w");
02409 if (out == NULL)
02410 {
02411 perror (current_output_file);
02412 exit (1);
02413 }
02414 }
02415 }
02416 process_file (&jcf, out);
02417 JCF_FINISH (&jcf);
02418 if (current_output_file != output_file)
02419 free (current_output_file);
02420 jcf_dependency_write ();
02421 }
02422
02423 if (out != NULL && out != stdout)
02424 fclose (out);
02425
02426 return found_error;
02427 }