| /******************************************************************************* |
| * Copyright (c) 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.tools.internal; |
| |
| import java.lang.reflect.*; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| import org.eclipse.swt.internal.Platform; |
| |
| public class NativesGenerator extends JNIGenerator { |
| |
| boolean nativeMacro, enterExitMacro, useCritical; |
| |
| public NativesGenerator() { |
| useCritical = true; |
| enterExitMacro = true; |
| nativeMacro = true; |
| } |
| |
| public void generate(Class clazz, String methodName) { |
| Method[] methods = clazz.getDeclaredMethods(); |
| int count = 0; |
| for (int i = 0; i < methods.length; i++) { |
| if (methods[i].getName().startsWith(methodName)) count++; |
| } |
| Method[] result = new Method[count]; |
| count = 0; |
| for (int i = 0; i < methods.length; i++) { |
| if (methods[i].getName().startsWith(methodName)) result[count++] = methods[i]; |
| } |
| generate(result); |
| } |
| |
| public void generate(Class clazz) { |
| ClassData classData = getMetaData().getMetaData(clazz); |
| if (classData.getFlag("no_gen")) return; |
| generateMetaData("swt_copyright"); |
| generateMetaData("swt_includes"); |
| generateNativeMacro(clazz); |
| Method[] methods = clazz.getDeclaredMethods(); |
| generateExcludes(methods); |
| generate(methods); |
| } |
| |
| public void generateExcludes(Method[] methods) { |
| sort(methods); |
| HashSet excludes = new HashSet(); |
| for (int i = 0; i < methods.length; i++) { |
| Method method = methods[i]; |
| if ((method.getModifiers() & Modifier.NATIVE) == 0) continue; |
| MethodData methodData = getMetaData().getMetaData(method); |
| String exclude = methodData.getExclude(); |
| if (exclude.length() != 0) { |
| excludes.add(exclude); |
| } |
| } |
| for (Iterator iter = excludes.iterator(); iter.hasNext();) { |
| String exclude = (String)iter.next(); |
| output(exclude); |
| outputDelimiter(); |
| for (int i = 0; i < methods.length; i++) { |
| Method method = methods[i]; |
| if ((method.getModifiers() & Modifier.NATIVE) == 0) continue; |
| MethodData methodData = getMetaData().getMetaData(method); |
| String methodExclude = methodData.getExclude(); |
| if (exclude.equals(methodExclude)) { |
| output("#define NO_"); |
| output(getFunctionName(method)); |
| outputDelimiter(); |
| } |
| } |
| output("#endif"); |
| outputDelimiter(); |
| outputDelimiter(); |
| } |
| } |
| |
| public void generate(Method[] methods) { |
| sort(methods); |
| for (int i = 0; i < methods.length; i++) { |
| Method method = methods[i]; |
| if ((method.getModifiers() & Modifier.NATIVE) == 0) continue; |
| generate(method); |
| } |
| } |
| |
| public void generate(Method method) { |
| MethodData methodData = getMetaData().getMetaData(method); |
| if (methodData.getFlag("no_gen")) return; |
| Class returnType = method.getReturnType(); |
| Class[] paramTypes = method.getParameterTypes(); |
| String function = getFunctionName(method); |
| |
| if (!(returnType == Void.TYPE || returnType.isPrimitive())) { |
| output("Warnning: bad return type. :" + method); |
| outputDelimiter(); |
| return; |
| } |
| |
| generateSourceStart(function); |
| generateFunctionPrototype(method, function, paramTypes, returnType); |
| generateFunctionBody(method, methodData, function, paramTypes, returnType); |
| generateSourceEnd(function); |
| outputDelimiter(); |
| } |
| |
| public void setEnterExitMacro(boolean enterExitMacro) { |
| this.enterExitMacro = enterExitMacro; |
| } |
| |
| public void setNativeMacro(boolean nativeMacro) { |
| this.nativeMacro = nativeMacro; |
| } |
| |
| public void setUseCritical(boolean useCritical) { |
| this.useCritical = useCritical; |
| } |
| |
| void generateNativeMacro(Class clazz) { |
| output("#define "); |
| output(getClassName(clazz)); |
| output("_NATIVE(func) Java_"); |
| output(toC(clazz.getName())); |
| output("_##func"); |
| outputDelimiter(); |
| outputDelimiter(); |
| } |
| |
| void generateGetParameter(int i, Class paramType, ParameterData paramData) { |
| if (paramType.isPrimitive()) return; |
| output("\tif (arg" + i); |
| output(") lparg" + i); |
| output(" = "); |
| if (paramType.isArray()) { |
| Class componentType = paramType.getComponentType(); |
| if (componentType.isPrimitive()) { |
| if (useCritical && paramData.getFlag("critical")) { |
| output("(*env)->GetPrimitiveArrayCritical(env, arg" + i); |
| output(", NULL);"); |
| } else { |
| output("(*env)->Get"); |
| output(getTypeSignature1(componentType)); |
| output("ArrayElements(env, arg" + i); |
| output(", NULL);"); |
| } |
| } else { |
| throw new Error("not done"); |
| } |
| } else if (paramType == String.class) { |
| if (paramData.getFlag("unicode")) { |
| output("(*env)->GetStringChars(env, arg" + i); |
| output(", NULL);"); |
| } else { |
| output("(*env)->GetStringUTFChars(env, arg" + i); |
| output(", NULL);"); |
| } |
| } else { |
| if (paramData.getFlag("no_in")) { |
| output("&_arg" + i); |
| output(";"); |
| } else { |
| output("get"); |
| output(getClassName(paramType)); |
| output("Fields(env, arg" + i); |
| output(", &_arg" + i); |
| output(");"); |
| } |
| } |
| outputDelimiter(); |
| } |
| |
| void genereateSetParameter(int i, Class paramType, ParameterData paramData) { |
| if (paramType.isPrimitive()) return; |
| if (paramType.isArray()) { |
| output("\tif (arg" + i); |
| output(") "); |
| Class componentType = paramType.getComponentType(); |
| if (componentType.isPrimitive()) { |
| if (useCritical && paramData.getFlag("critical")) { |
| output("(*env)->ReleasePrimitiveArrayCritical(env, arg" + i); |
| } else { |
| output("(*env)->Release"); |
| output(getTypeSignature1(componentType)); |
| output("ArrayElements(env, arg" + i); |
| } |
| output(", lparg" + i); |
| output(", "); |
| if (paramData.getFlag("no_out")) { |
| output("JNI_ABORT"); |
| } else { |
| output("0"); |
| } |
| output(");"); |
| } else { |
| throw new Error("not done"); |
| } |
| outputDelimiter(); |
| } else if (paramType == String.class) { |
| output("\tif (arg" + i); |
| output(") "); |
| if (paramData.getFlag("unicode")) { |
| output("(*env)->ReleaseStringChars(env, arg" + i); |
| } else { |
| output("(*env)->ReleaseStringUTFChars(env, arg" + i); |
| } |
| output(", lparg" + i); |
| output(");"); |
| outputDelimiter(); |
| } else { |
| if (!paramData.getFlag("no_out")) { |
| output("\tif (arg" + i); |
| output(") "); |
| output("set"); |
| output(getClassName(paramType)); |
| output("Fields(env, arg" + i); |
| output(", lparg" + i); |
| output(");"); |
| outputDelimiter(); |
| } |
| } |
| } |
| |
| void generateExitMacro(String function) { |
| if (!enterExitMacro) return; |
| output("\tNATIVE_EXIT(env, that, \""); |
| output(function); |
| output("\\n\")"); |
| outputDelimiter(); |
| } |
| |
| void generateEnterMacro(String function) { |
| if (!enterExitMacro) return; |
| output("\tNATIVE_ENTER(env, that, \""); |
| output(function); |
| output("\\n\")"); |
| outputDelimiter(); |
| } |
| |
| boolean generateLocalVars(Method method, Class[] paramTypes, Class returnType) { |
| boolean needsReturn = enterExitMacro; |
| for (int i = 0; i < paramTypes.length; i++) { |
| Class paramType = paramTypes[i]; |
| if (paramType.isPrimitive()) continue; |
| ParameterData paramData = getMetaData().getMetaData(method, i); |
| output("\t"); |
| if (paramType.isArray()) { |
| Class componentType = paramType.getComponentType(); |
| if (componentType.isPrimitive()) { |
| output(getTypeSignature2(componentType)); |
| output(" *lparg" + i); |
| output("=NULL;"); |
| } else { |
| throw new Error("not done"); |
| } |
| } else if (paramType == String.class) { |
| if (paramData.getFlag("unicode")) { |
| output("const jchar *lparg" + i); |
| } else { |
| output("const jbyte *lparg" + i); |
| } |
| output("= NULL;"); |
| } else { |
| output(getClassName(paramType)); |
| output(" _arg" + i); |
| if (paramData.getFlag("init")) output("={0}"); |
| output(", *lparg" + i); |
| output("=NULL;"); |
| } |
| outputDelimiter(); |
| needsReturn = true; |
| } |
| if (needsReturn) { |
| if (returnType != Void.TYPE) { |
| output("\t"); |
| output(getTypeSignature2(returnType)); |
| output(" rc;"); |
| outputDelimiter(); |
| } |
| } |
| return needsReturn; |
| } |
| |
| void generateGetters(Method method, Class[] paramTypes) { |
| for (int i = 0; i < paramTypes.length; i++) { |
| Class paramType = paramTypes[i]; |
| ParameterData paramData = getMetaData().getMetaData(method, i); |
| if (!paramData.getFlag("critical")) { |
| generateGetParameter(i, paramType, paramData); |
| } |
| } |
| for (int i = 0; i < paramTypes.length; i++) { |
| Class paramType = paramTypes[i]; |
| ParameterData paramData = getMetaData().getMetaData(method, i); |
| if (paramData.getFlag("critical")) { |
| generateGetParameter(i, paramType, paramData); |
| } |
| } |
| } |
| |
| void generateSetters(Method method, Class[] paramTypes) { |
| for (int i = paramTypes.length - 1; i >= 0; i--) { |
| Class paramType = paramTypes[i]; |
| ParameterData paramData = getMetaData().getMetaData(method, i); |
| if (paramData.getFlag("critical")) { |
| genereateSetParameter(i, paramType, paramData); |
| } |
| } |
| for (int i = paramTypes.length - 1; i >= 0; i--) { |
| Class paramType = paramTypes[i]; |
| ParameterData paramData = getMetaData().getMetaData(method, i); |
| if (!paramData.getFlag("critical")) { |
| genereateSetParameter(i, paramType, paramData); |
| } |
| } |
| } |
| |
| void generateDynamicFunctionCall(Method method, MethodData methodData, Class[] paramTypes, Class returnType, boolean needsReturn) { |
| output("/*"); |
| outputDelimiter(); |
| generateFunctionCall(method, methodData, paramTypes, returnType, needsReturn); |
| output("*/"); |
| outputDelimiter(); |
| output("\t"); |
| output("{"); |
| outputDelimiter(); |
| |
| if (Platform.PLATFORM.equals("win32")) { |
| output("\t\tstatic int initialized = 0;"); |
| outputDelimiter(); |
| output("\t\tstatic HMODULE hm = NULL;"); |
| outputDelimiter(); |
| output("\t\tstatic FARPROC fp = NULL;"); |
| outputDelimiter(); |
| if (returnType != Void.TYPE) { |
| if (needsReturn) { |
| output("\t\trc = 0;"); |
| outputDelimiter(); |
| } |
| } |
| output("\t\tif (!initialized) {"); |
| outputDelimiter(); |
| output("\t\t\tif (!(hm = GetModuleHandle("); |
| output(method.getName()); |
| output("_LIB))) hm = LoadLibrary("); |
| output(method.getName()); |
| output("_LIB);"); |
| outputDelimiter(); |
| output("\t\t\tif (hm) fp = GetProcAddress(hm, \""); |
| output(method.getName()); |
| output("\");"); |
| outputDelimiter(); |
| output("\t\t\tinitialized = 1;"); |
| outputDelimiter(); |
| output("\t\t}"); |
| outputDelimiter(); |
| output("\t\tif (fp) {"); |
| outputDelimiter(); |
| output("\t\t"); |
| generateFunctionCallLeftSide(method, methodData, returnType, needsReturn); |
| output("fp"); |
| generateFunctionCallRightSide(method, methodData, paramTypes, 0); |
| outputDelimiter(); |
| output("\t\t}"); |
| outputDelimiter(); |
| } else { |
| output("\t\tstatic int initialized = 0;"); |
| outputDelimiter(); |
| output("\t\tstatic void *handle = NULL;"); |
| outputDelimiter(); |
| output("\t\tstatic int (*fptr)();"); |
| outputDelimiter(); |
| if (returnType != Void.TYPE) { |
| if (needsReturn) { |
| output("\t\trc = 0;"); |
| outputDelimiter(); |
| } |
| } |
| output("\t\tif (!initialized) {"); |
| outputDelimiter(); |
| output("\t\t\tif (!handle) handle = dlopen("); |
| output(method.getName()); |
| output("_LIB, RTLD_LAZY);"); |
| outputDelimiter(); |
| output("\t\t\tif (handle) fptr = dlsym(handle, \""); |
| output(method.getName()); |
| output("\");"); |
| outputDelimiter(); |
| output("\t\t\tinitialized = 1;"); |
| outputDelimiter(); |
| output("\t\t}"); |
| outputDelimiter(); |
| output("\t\tif (fptr) {"); |
| outputDelimiter(); |
| output("\t\t"); |
| generateFunctionCallLeftSide(method, methodData, returnType, needsReturn); |
| output("(*fptr)"); |
| generateFunctionCallRightSide(method, methodData, paramTypes, 0); |
| outputDelimiter(); |
| output("\t\t}"); |
| outputDelimiter(); |
| } |
| |
| output("\t"); |
| output("}"); |
| outputDelimiter(); |
| } |
| |
| void generateFunctionCallLeftSide(Method method, MethodData methodData, Class returnType, boolean needsReturn) { |
| output("\t"); |
| if (returnType != Void.TYPE) { |
| if (needsReturn) { |
| output("rc = "); |
| } else { |
| output("return "); |
| } |
| output("("); |
| output(getTypeSignature2(returnType)); |
| output(")"); |
| } |
| if (methodData.getFlag("address")) { |
| output("&"); |
| } |
| } |
| |
| void generateFunctionCallRightSide(Method method, MethodData methodData, Class[] paramTypes, int paramStart) { |
| if (!methodData.getFlag("const")) { |
| output("("); |
| for (int i = paramStart; i < paramTypes.length; i++) { |
| Class paramType = paramTypes[i]; |
| ParameterData paramData = getMetaData().getMetaData(method, i); |
| if (i != paramStart) output(", "); |
| if (paramData.getFlag("struct")) output("*"); |
| output(paramData.getCast()); |
| if (!paramType.isPrimitive()) output("lp"); |
| output("arg" + i); |
| } |
| output(")"); |
| } |
| output(";"); |
| } |
| |
| void generateFunctionCall(Method method, MethodData methodData, Class[] paramTypes, Class returnType, boolean needsReturn) { |
| generateFunctionCallLeftSide(method, methodData, returnType, needsReturn); |
| /* |
| * |
| */ |
| int paramStart = 0; |
| if (method.getName().equalsIgnoreCase("call")) { |
| output("("); |
| ParameterData paramData = getMetaData().getMetaData(method, 0); |
| String cast = paramData.getCast(); |
| if (cast.length() != 0 && !cast.equals("()")) { |
| output(cast); |
| } else { |
| output("("); |
| output(getTypeSignature2(returnType)); |
| output(" (*)())"); |
| } |
| output("arg0)"); |
| paramStart = 1; |
| } else if (method.getName().equals("VtblCall")) { |
| output("(("); |
| output(getTypeSignature2(returnType)); |
| output(" (STDMETHODCALLTYPE *)())(*(int **)arg1)[arg0])"); |
| paramStart = 1; |
| } else { |
| output(method.getName()); |
| } |
| generateFunctionCallRightSide(method, methodData, paramTypes, paramStart); |
| outputDelimiter(); |
| } |
| |
| void generateReturn(Method method, Class returnType, boolean needsReturn) { |
| if (needsReturn && returnType != Void.TYPE) { |
| output("\treturn rc;"); |
| outputDelimiter(); |
| } |
| } |
| |
| void generateGTKmemmove(Method method, String function, Class[] paramTypes) { |
| generateEnterMacro(function); |
| output("\t"); |
| boolean get = paramTypes[0].isPrimitive(); |
| String className = getClassName(paramTypes[get ? 1 : 0]); |
| output(get ? "if (arg1) get" : "if (arg0) set"); |
| output(className); |
| output(get ? "Fields(env, arg1, (" : "Fields(env, arg0, ("); |
| output(className); |
| output(get ? " *)arg0)" : " *)arg1)"); |
| output(";"); |
| outputDelimiter(); |
| generateExitMacro(function); |
| } |
| |
| void generateFunctionBody(Method method, MethodData methodData, String function, Class[] paramTypes, Class returnType) { |
| output("{"); |
| outputDelimiter(); |
| |
| /* |
| * |
| */ |
| boolean isGTKmemove = method.getName().equals("memmove") && paramTypes.length == 2 && returnType == Void.TYPE; |
| if (isGTKmemove) { |
| generateGTKmemmove(method, function, paramTypes); |
| } else { |
| boolean needsReturn = generateLocalVars(method, paramTypes, returnType); |
| generateEnterMacro(function); |
| generateGetters(method, paramTypes); |
| if (methodData.getFlag("dynamic")) { |
| generateDynamicFunctionCall(method, methodData, paramTypes, returnType, needsReturn); |
| } else { |
| generateFunctionCall(method, methodData, paramTypes, returnType, needsReturn); |
| } |
| generateSetters(method, paramTypes); |
| generateExitMacro(function); |
| generateReturn(method, returnType, needsReturn); |
| } |
| |
| output("}"); |
| outputDelimiter(); |
| } |
| |
| void generateFunctionPrototype(Method method, String function, Class[] paramTypes, Class returnType) { |
| output("JNIEXPORT "); |
| output(getTypeSignature2(returnType)); |
| output(" JNICALL "); |
| if (nativeMacro) { |
| output(getClassName(method.getDeclaringClass())); |
| output("_NATIVE("); |
| } else { |
| output("Java_"); |
| output(toC(method.getDeclaringClass().getName())); |
| output("_"); |
| } |
| output(function); |
| if (nativeMacro) { |
| output(")"); |
| } |
| outputDelimiter(); |
| output("\t(JNIEnv *env, "); |
| if ((method.getModifiers() & Modifier.STATIC) != 0) { |
| output("jclass"); |
| } else { |
| output("jobject"); |
| } |
| output(" that"); |
| for (int i = 0; i < paramTypes.length; i++) { |
| Class paramType = paramTypes[i]; |
| output(", "); |
| output(getTypeSignature2(paramType)); |
| output(" arg" + i); |
| } |
| output(")"); |
| outputDelimiter(); |
| } |
| |
| void generateSourceStart(String function) { |
| output("#ifndef NO_"); |
| output(function); |
| outputDelimiter(); |
| } |
| |
| void generateSourceEnd(String function) { |
| output("#endif"); |
| outputDelimiter(); |
| } |
| |
| boolean isUnique(Method method) { |
| return isUnique(method, Modifier.NATIVE); |
| } |
| |
| public static void main(String[] args) { |
| // args = new String[]{"org.eclipse.swt.internal.win32.OS"}; |
| if (args.length < 1) { |
| System.out.println("Usage: java NativesGenerator <className1> <className2>"); |
| return; |
| } |
| try { |
| NativesGenerator gen = new NativesGenerator(); |
| for (int i = 0; i < args.length; i++) { |
| String clazzName = args[i]; |
| Class clazz = Class.forName(clazzName); |
| gen.generate(clazz); |
| // gen.generate(clazz, "CommandBar_Destroy"); |
| } |
| } catch (Exception e) { |
| System.out.println("Problem"); |
| e.printStackTrace(System.out); |
| } |
| } |
| |
| } |