/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "JNIHeaderGenerator.h" #include "prprf.h" #include "plstr.h" #include "CUtils.h" #include "StringUtils.h" #include "JavaObject.h" #include "FieldOrMethod.h" #include "JNIManglers.h" #ifdef USE_PR_IO #define PR_fprintf fprintf #define PR_Write fwrite #define PRFileDesc FILE #endif bool JNIHeaderGenerator::genHeaderFile(ClassFileSummary &summ, PRFileDesc *fp) { Uint32 i; const ClassFileReader &reader = *summ.getReader(); const char *className = reader.getThisClass()->getUtf()->getUtfString(); PR_fprintf(fp, "/* This file is machine-generated. Do not edit!! */\n"); PR_fprintf(fp, "\n/* Header for class %s */\n\n", className); PR_fprintf(fp, "#include \n\n"); const Method **methods = summ.getMethods(); Uint32 methodCount = summ.getMethodCount(); /* Now go through each method and see if it is overloaded. */ TemporaryBuffer overbuf(methodCount*sizeof(bool)); bool *overloadedMethods = (bool *) (char *) overbuf; for (i = 0; i < methodCount; i++) { const char *methodName = methods[i]->getName(); overloadedMethods[i] = false; for (Uint32 j = 0; j < methodCount; ++j) if (i != j && strcmp(methodName, methods[j]->getName()) == 0) overloadedMethods[i] = true; } /* Go through each native method and generate a declaration for it */ JNILongMangler lmangler; JNIShortMangler smangler; /* extern "C" the generated method headers */ PR_fprintf(fp, "#ifdef __cplusplus\n"); PR_fprintf(fp, "extern \"C\" {\n"); PR_fprintf(fp, "#endif\n"); for (i = 0; i < methodCount; i++) { Method *m = (Method *) methods[i]; const Signature &sig = m->getSignature(); if ((m->getModifiers() & CR_METHOD_NATIVE)) { /* Generate the return type */ char *retString = getArgString(*sig.resultType); const char *methodName = m->getName(); const char *signature = const_cast(m)->getSignatureString(); if (!retString) return false; int32 len = PL_strlen(methodName) + PL_strlen(className)*2 + PL_strlen(signature)*2 + sizeof("Java___"); TemporaryBuffer copy(len); char *mangledMethodName = copy; if (overloadedMethods[i]) { if (!lmangler.mangle(className, methodName, signature, mangledMethodName, len)) continue; } else { if (!smangler.mangle(className, methodName, signature, mangledMethodName, len)) continue; } PR_fprintf(fp, "\n/*\n"); PR_fprintf(fp, " * Class : %s\n", className); PR_fprintf(fp, " * Method : %s\n", methodName); PR_fprintf(fp, " * Signature : %s\n", signature); PR_fprintf(fp, " */\n"); PR_fprintf(fp, "JNIEXPORT JNICALL(%s)\n%s(", retString, mangledMethodName); // Kills the release build since NSPR needs to give us a clean way to // free strings that it allocates #ifdef DEBUG //free(retString); #endif /* The first argument is always a (JNIEnv *) */ PR_fprintf(fp, "JNIEnv *"); /* For static methods, the second argument is a jclass */ if (m->getModifiers() & CR_METHOD_STATIC) PR_fprintf(fp, ", jclass"); for (uint32 j = 0; j < sig.nArguments; j++) { char *typeString = getArgString(*sig.argumentTypes[j]); if (!typeString) return false; PR_fprintf(fp, ", %s", typeString); // Currently does not work with the release build since NSPR needs to // give us a clean way of freeing strings that it allocates #ifdef DEBUG //free(typeString); #endif } PR_fprintf(fp, ");\n\n"); } } PR_fprintf(fp, "#ifdef __cplusplus\n"); PR_fprintf(fp, "}\n"); /* Matches the extern "C" declaration generated earlier */ PR_fprintf(fp, "#endif \n\n"); /* Matches the #ifdef __cplusplus */ return true; } char *JNIHeaderGenerator::getArgString(const Type &type) { switch (type.typeKind) { case tkChar: return PL_strdup("jchar"); break; case tkShort: return PL_strdup("jshort"); break; case tkInt: return PL_strdup("jint"); break; case tkByte: return PL_strdup("jbyte"); break; case tkBoolean: return PL_strdup("jbool"); break; case tkLong: return PL_strdup("jlong"); break; case tkFloat: return PL_strdup("jfloat"); break; case tkDouble: return PL_strdup("jdouble"); break; case tkVoid: return PL_strdup("void"); break; case tkObject: { const Class &clazz = *static_cast(&type); /* Special-case certain objects XXX Need to do throwable here */ if (!PL_strcmp(clazz.getName(), "java.lang.String")) return PL_strdup("jstring"); else return PL_strdup("jobject"); } case tkInterface: return PL_strdup("jobject"); case tkArray: { const Array &atype = *static_cast(&type); switch (atype.componentType.typeKind) { case tkChar: return PL_strdup("jcharArray"); case tkShort: return PL_strdup("jshortArray"); case tkInt: return PL_strdup("jintArray"); case tkByte: return PL_strdup("jbyteArray"); case tkBoolean: return PL_strdup("jboolArray"); case tkLong: return PL_strdup("jlongArray"); case tkFloat: return PL_strdup("jfloatArray"); case tkDouble: return PL_strdup("jdoubleArray"); case tkObject: case tkInterface: case tkArray: return PL_strdup("jobjectArray"); default: return 0; } break; } default: return 0; } }