| /******************************************************************************* |
| * Copyright (c) 2004, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.tools.internal; |
| |
| import java.lang.reflect.*; |
| import java.util.*; |
| |
| public class StructsGenerator extends JNIGenerator { |
| |
| boolean header; |
| |
| static final boolean GLOBAL_REF = false; |
| |
| public StructsGenerator(boolean header) { |
| this.header = header; |
| } |
| |
| @Override |
| public void generateCopyright() { |
| outputln(fixDelimiter(getMetaData().getCopyright())); |
| } |
| |
| @Override |
| public void generateIncludes() { |
| if (header) { |
| output("#include \""); |
| output(getOutputName()); |
| outputln(".h\""); |
| } else { |
| outputln("#include \"swt.h\""); |
| output("#include \""); |
| output(getOutputName()); |
| outputln("_structs.h\""); |
| } |
| outputln(); |
| } |
| |
| @Override |
| public void generate(JNIClass clazz) { |
| int j = 0; |
| JNIField[] fields = clazz.getDeclaredFields(); |
| for (; j < fields.length; j++) { |
| JNIField field = fields[j]; |
| int mods = field.getModifiers(); |
| if ((mods & Modifier.PUBLIC) != 0 && (mods & Modifier.STATIC) == 0) { |
| break; |
| } |
| } |
| if (j == fields.length) return; |
| if (header) { |
| generateHeaderFile(clazz); |
| } else { |
| generateSourceFile(clazz); |
| } |
| } |
| |
| @Override |
| public void generate() { |
| if (!header && getClasses().length == 0) return; |
| super.generate(); |
| } |
| |
| @Override |
| public String getExtension() { |
| return header ? ".h" : super.getExtension(); |
| } |
| |
| @Override |
| public String getSuffix() { |
| return "_structs"; |
| } |
| |
| void generateExcludes(JNIClass[] classes) { |
| HashSet<String> excludes = new HashSet<>(); |
| for (int i = 0; i < classes.length; i++) { |
| JNIClass clazz = classes[i]; |
| String exclude = clazz.getExclude(); |
| if (exclude.length() != 0) { |
| excludes.add(exclude); |
| } |
| } |
| for (String exclude : excludes) { |
| outputln(exclude); |
| for (int i = 0; i < classes.length; i++) { |
| JNIClass clazz = classes[i]; |
| String classExclude = clazz.getExclude(); |
| if (exclude.equals(classExclude)) { |
| output("#define NO_"); |
| outputln(clazz.getSimpleName()); |
| } |
| } |
| outputln("#endif"); |
| outputln(); |
| } |
| } |
| |
| void generateHeaderFile(JNIClass clazz) { |
| generateSourceStart(clazz); |
| generatePrototypes(clazz); |
| generateBlankMacros(clazz); |
| generateSourceEnd(); |
| outputln(); |
| } |
| |
| void generateSourceFile(JNIClass clazz) { |
| generateSourceStart(clazz); |
| generateFIDsStructure(clazz); |
| outputln(); |
| generateGlobalVar(clazz); |
| outputln(); |
| generateFunctions(clazz); |
| generateSourceEnd(); |
| outputln(); |
| } |
| |
| void generateSourceStart(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| output("#ifndef NO_"); |
| outputln(clazzName); |
| } |
| |
| void generateSourceEnd() { |
| outputln("#endif"); |
| } |
| |
| void generateGlobalVar(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| output(clazzName); |
| output("_FID_CACHE "); |
| output(clazzName); |
| outputln("Fc;"); |
| } |
| |
| void generateBlankMacros(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| outputln("#else"); |
| output("#define cache"); |
| output(clazzName); |
| outputln("Fields(a,b)"); |
| output("#define get"); |
| output(clazzName); |
| outputln("Fields(a,b,c) NULL"); |
| output("#define set"); |
| output(clazzName); |
| outputln("Fields(a,b,c)"); |
| output("#define "); |
| output(clazzName); |
| outputln("_sizeof() 0"); |
| } |
| |
| void generatePrototypes(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| output("void cache"); |
| output(clazzName); |
| outputln("Fields(JNIEnv *env, jobject lpObject);"); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| output(" *get"); |
| output(clazzName); |
| output("Fields(JNIEnv *env, jobject lpObject, "); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| outputln(" *lpStruct);"); |
| output("void set"); |
| output(clazzName); |
| output("Fields(JNIEnv *env, jobject lpObject, "); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| outputln(" *lpStruct);"); |
| output("#define "); |
| output(clazzName); |
| output("_sizeof() sizeof("); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| outputln(")"); |
| } |
| |
| void generateFIDsStructure(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| output("typedef struct "); |
| output(clazzName); |
| outputln("_FID_CACHE {"); |
| outputln("\tint cached;"); |
| outputln("\tjclass clazz;"); |
| output("\tjfieldID "); |
| JNIField[] fields = clazz.getDeclaredFields(); |
| boolean first = true; |
| for (int i = 0; i < fields.length; i++) { |
| JNIField field = fields[i]; |
| if (ignoreField(field)) continue; |
| if (!first) output(", "); |
| output(field.getName()); |
| first = false; |
| } |
| outputln(";"); |
| output("} "); |
| output(clazzName); |
| outputln("_FID_CACHE;"); |
| } |
| |
| void generateCacheFunction(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| output("void cache"); |
| output(clazzName); |
| outputln("Fields(JNIEnv *env, jobject lpObject)"); |
| outputln("{"); |
| output("\tif ("); |
| output(clazzName); |
| outputln("Fc.cached) return;"); |
| JNIClass superclazz = clazz.getSuperclass(); |
| if (!superclazz.getName().equals("java.lang.Object")) { |
| String superName = superclazz.getSimpleName(); |
| output("\tcache"); |
| output(superName); |
| outputln("Fields(env, lpObject);"); |
| } |
| output("\t"); |
| output(clazzName); |
| boolean isCPP = getCPP(); |
| if (isCPP) { |
| if (GLOBAL_REF) { |
| output("Fc.clazz = (jclass)env->NewGlobalRef(env->GetObjectClass(lpObject));"); |
| } else { |
| output("Fc.clazz = env->GetObjectClass(lpObject);"); |
| } |
| } else { |
| if (GLOBAL_REF) { |
| output("Fc.clazz = (*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, lpObject));"); |
| } else { |
| output("Fc.clazz = (*env)->GetObjectClass(env, lpObject);"); |
| } |
| } |
| outputln(); |
| JNIField[] fields = clazz.getDeclaredFields(); |
| for (int i = 0; i < fields.length; i++) { |
| JNIField field = fields[i]; |
| if (ignoreField(field)) continue; |
| output("\t"); |
| output(clazzName); |
| output("Fc."); |
| output(field.getName()); |
| if (isCPP) { |
| output(" = env->GetFieldID("); |
| } else { |
| output(" = (*env)->GetFieldID(env, "); |
| } |
| output(clazzName); |
| output("Fc.clazz, \""); |
| output(field.getName()); |
| JNIType type = field.getType(), type64 = field.getType64(); |
| output("\", "); |
| if (type.equals(type64)) output("\""); |
| output(type.getTypeSignature(!type.equals(type64))); |
| if (type.equals(type64)) output("\""); |
| outputln(");"); |
| } |
| output("\t"); |
| output(clazzName); |
| outputln("Fc.cached = 1;"); |
| outputln("}"); |
| } |
| |
| void generateGetFields(JNIClass clazz) { |
| JNIClass superclazz = clazz.getSuperclass(); |
| String clazzName = clazz.getSimpleName(); |
| String superName = superclazz.getSimpleName(); |
| if (!superclazz.getName().equals("java.lang.Object")) { |
| /* Windows exception - cannot call get/set function of super class in this case */ |
| if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) { |
| output("\tget"); |
| output(superName); |
| output("Fields(env, lpObject, ("); |
| output(superName); |
| outputln(" *)lpStruct);"); |
| } else { |
| generateGetFields(superclazz); |
| } |
| } |
| JNIField[] fields = clazz.getDeclaredFields(); |
| for (int i = 0; i < fields.length; i++) { |
| JNIField field = fields[i]; |
| if (ignoreField(field)) continue; |
| String exclude = field.getExclude(); |
| if (exclude.length() != 0) { |
| outputln(exclude); |
| } |
| boolean noWinCE = field.getFlag(FLAG_NO_WINCE); |
| if (noWinCE) { |
| outputln("#ifndef _WIN32_WCE"); |
| } |
| JNIType type = field.getType(), type64 = field.getType64(); |
| String typeName = type.getSimpleName(); |
| String accessor = field.getAccessor(); |
| if (accessor == null || accessor.length() == 0) accessor = field.getName(); |
| boolean isCPP = getCPP(); |
| if (type.isPrimitive()) { |
| output("\tlpStruct->"); |
| output(accessor); |
| output(" = "); |
| output(field.getCast()); |
| if (isCPP) { |
| output("env->Get"); |
| } else { |
| output("(*env)->Get"); |
| } |
| output(type.getTypeSignature1(!type.equals(type64))); |
| if (isCPP) { |
| output("Field(lpObject, "); |
| } else { |
| output("Field(env, lpObject, "); |
| } |
| output(field.getDeclaringClass().getSimpleName()); |
| output("Fc."); |
| output(field.getName()); |
| output(");"); |
| } else if (type.isArray()) { |
| JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType(); |
| if (componentType.isPrimitive()) { |
| outputln("\t{"); |
| output("\t"); |
| output(type.getTypeSignature2(!type.equals(type64))); |
| output(" lpObject1 = ("); |
| output(type.getTypeSignature2(!type.equals(type64))); |
| if (isCPP) { |
| output(")env->GetObjectField(lpObject, "); |
| } else { |
| output(")(*env)->GetObjectField(env, lpObject, "); |
| } |
| output(field.getDeclaringClass().getSimpleName()); |
| output("Fc."); |
| output(field.getName()); |
| outputln(");"); |
| if (isCPP) { |
| output("\tenv->Get"); |
| } else { |
| output("\t(*env)->Get"); |
| } |
| output(componentType.getTypeSignature1(!componentType.equals(componentType64))); |
| if (isCPP) { |
| output("ArrayRegion(lpObject1, 0, sizeof(lpStruct->"); |
| } else { |
| output("ArrayRegion(env, lpObject1, 0, sizeof(lpStruct->"); |
| } |
| output(accessor); |
| output(")"); |
| if (!componentType.isType("byte")) { |
| output(" / sizeof("); |
| output(componentType.getTypeSignature2(!componentType.equals(componentType64))); |
| output(")"); |
| } |
| output(", ("); |
| output(type.getTypeSignature4(!type.equals(type64), false)); |
| output(")"); |
| if (field.getFlag(FLAG_STRUCT)) { |
| output("&"); |
| } |
| output("lpStruct->"); |
| output(accessor); |
| outputln(");"); |
| output("\t}"); |
| } else { |
| throw new Error("not done"); |
| } |
| } else { |
| outputln("\t{"); |
| if (isCPP) { |
| output("\tjobject lpObject1 = env->GetObjectField(lpObject, "); |
| } else { |
| output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, "); |
| } |
| output(field.getDeclaringClass().getSimpleName()); |
| output("Fc."); |
| output(field.getName()); |
| outputln(");"); |
| output("\tif (lpObject1 != NULL) get"); |
| output(typeName); |
| output("Fields(env, lpObject1, &lpStruct->"); |
| output(accessor); |
| outputln(");"); |
| output("\t}"); |
| } |
| outputln(); |
| if (noWinCE) { |
| outputln("#endif"); |
| } |
| if (exclude.length() != 0) { |
| outputln("#endif"); |
| } |
| } |
| } |
| |
| void generateGetFunction(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| output(" *get"); |
| output(clazzName); |
| output("Fields(JNIEnv *env, jobject lpObject, "); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| outputln(" *lpStruct)"); |
| outputln("{"); |
| output("\tif (!"); |
| output(clazzName); |
| output("Fc.cached) cache"); |
| output(clazzName); |
| outputln("Fields(env, lpObject);"); |
| generateGetFields(clazz); |
| outputln("\treturn lpStruct;"); |
| outputln("}"); |
| } |
| |
| void generateSetFields(JNIClass clazz) { |
| JNIClass superclazz = clazz.getSuperclass(); |
| String clazzName = clazz.getSimpleName(); |
| String superName = superclazz.getSimpleName(); |
| if (!superclazz.getName().equals("java.lang.Object")) { |
| /* Windows exception - cannot call get/set function of super class in this case */ |
| if (!(clazzName.equals(superName + "A") || clazzName.equals(superName + "W"))) { |
| output("\tset"); |
| output(superName); |
| output("Fields(env, lpObject, ("); |
| output(superName); |
| outputln(" *)lpStruct);"); |
| } else { |
| generateSetFields(superclazz); |
| } |
| } |
| JNIField[] fields = clazz.getDeclaredFields(); |
| for (int i = 0; i < fields.length; i++) { |
| JNIField field = fields[i]; |
| if (ignoreField(field)) continue; |
| String exclude = field.getExclude(); |
| if (exclude.length() != 0) { |
| outputln(exclude); |
| } |
| boolean noWinCE = field.getFlag(FLAG_NO_WINCE); |
| if (noWinCE) { |
| outputln("#ifndef _WIN32_WCE"); |
| } |
| JNIType type = field.getType(), type64 = field.getType64(); |
| String typeName = type.getSimpleName(); |
| String accessor = field.getAccessor(); |
| if (accessor == null || accessor.length() == 0) accessor = field.getName(); |
| boolean isCPP = getCPP(); |
| if (type.isPrimitive()) { |
| if (isCPP) { |
| output("\tenv->Set"); |
| } else { |
| output("\t(*env)->Set"); |
| } |
| output(type.getTypeSignature1(!type.equals(type64))); |
| if (isCPP) { |
| output("Field(lpObject, "); |
| } else { |
| output("Field(env, lpObject, "); |
| } |
| output(field.getDeclaringClass().getSimpleName()); |
| output("Fc."); |
| output(field.getName()); |
| output(", ("); |
| output(type.getTypeSignature2(!type.equals(type64))); |
| output(")lpStruct->"); |
| output(accessor); |
| output(");"); |
| } else if (type.isArray()) { |
| JNIType componentType = type.getComponentType(), componentType64 = type64.getComponentType(); |
| if (componentType.isPrimitive()) { |
| outputln("\t{"); |
| output("\t"); |
| output(type.getTypeSignature2(!type.equals(type64))); |
| output(" lpObject1 = ("); |
| output(type.getTypeSignature2(!type.equals(type64))); |
| if (isCPP) { |
| output(")env->GetObjectField(lpObject, "); |
| } else { |
| output(")(*env)->GetObjectField(env, lpObject, "); |
| } |
| output(field.getDeclaringClass().getSimpleName()); |
| output("Fc."); |
| output(field.getName()); |
| outputln(");"); |
| if (isCPP) { |
| output("\tenv->Set"); |
| } else { |
| output("\t(*env)->Set"); |
| } |
| output(componentType.getTypeSignature1(!componentType.equals(componentType64))); |
| if (isCPP) { |
| output("ArrayRegion(lpObject1, 0, sizeof(lpStruct->"); |
| } else { |
| output("ArrayRegion(env, lpObject1, 0, sizeof(lpStruct->"); |
| } |
| output(accessor); |
| output(")"); |
| if (!componentType.isType("byte")) { |
| output(" / sizeof("); |
| output(componentType.getTypeSignature2(!componentType.equals(componentType64))); |
| output(")"); |
| } |
| output(", ("); |
| output(type.getTypeSignature4(!type.equals(type64), false)); |
| output(")"); |
| if (field.getFlag(FLAG_STRUCT)) { |
| output("&"); |
| } |
| output("lpStruct->"); |
| output(accessor); |
| outputln(");"); |
| output("\t}"); |
| } else { |
| throw new Error("not done"); |
| } |
| } else { |
| outputln("\t{"); |
| output("\tjobject lpObject1 = (*env)->GetObjectField(env, lpObject, "); |
| output(field.getDeclaringClass().getSimpleName()); |
| output("Fc."); |
| output(field.getName()); |
| outputln(");"); |
| output("\tif (lpObject1 != NULL) set"); |
| output(typeName); |
| output("Fields(env, lpObject1, &lpStruct->"); |
| output(accessor); |
| outputln(");"); |
| output("\t}"); |
| } |
| outputln(); |
| if (noWinCE) { |
| outputln("#endif"); |
| } |
| if (exclude.length() != 0) { |
| outputln("#endif"); |
| } |
| } |
| } |
| |
| void generateSetFunction(JNIClass clazz) { |
| String clazzName = clazz.getSimpleName(); |
| output("void set"); |
| output(clazzName); |
| output("Fields(JNIEnv *env, jobject lpObject, "); |
| if (clazz.getFlag(Flags.FLAG_STRUCT)) { |
| output("struct "); |
| } |
| output(clazzName); |
| outputln(" *lpStruct)"); |
| outputln("{"); |
| output("\tif (!"); |
| output(clazzName); |
| output("Fc.cached) cache"); |
| output(clazzName); |
| outputln("Fields(env, lpObject);"); |
| generateSetFields(clazz); |
| outputln("}"); |
| } |
| |
| void generateFunctions(JNIClass clazz) { |
| generateCacheFunction(clazz); |
| outputln(); |
| generateGetFunction(clazz); |
| outputln(); |
| generateSetFunction(clazz); |
| } |
| |
| boolean ignoreField(JNIField field) { |
| int mods = field.getModifiers(); |
| return |
| ((mods & Modifier.PUBLIC) == 0) || |
| ((mods & Modifier.FINAL) != 0) || |
| ((mods & Modifier.STATIC) != 0); |
| } |
| |
| } |