blob: 26fc0e22214756300639352d8c76c178d94cfced [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.tools.internal;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import org.eclipse.swt.SWT;
public abstract class JNIGenerator {
Class mainClass;
Class[] classes;
MetaData metaData;
boolean isCPP;
String delimiter;
PrintStream output;
ProgressMonitor progress;
public JNIGenerator() {
delimiter = System.getProperty("line.separator");
output = System.out;
metaData = new MetaData(new Properties());
}
String fixDelimiter(String str) {
if (delimiter.equals("\n")) return str;
int index = 0, length = str.length();
StringBuffer buffer = new StringBuffer();
while (index != -1) {
int start = index;
index = str.indexOf('\n', start);
if (index == -1) {
buffer.append(str.substring(start, length));
} else {
buffer.append(str.substring(start, index));
buffer.append(delimiter);
index++;
}
}
return buffer.toString();
}
static String getClassName(Class clazz) {
String name = clazz.getName();
int index = name.lastIndexOf('.') + 1;
return name.substring(index, name.length());
}
static String getFunctionName(Method method) {
return getFunctionName(method, method.getParameterTypes());
}
static String getFunctionName(Method method, Class[] paramTypes) {
if ((method.getModifiers() & Modifier.NATIVE) == 0) return method.getName();
String function = toC(method.getName());
if (!isNativeUnique(method)) {
StringBuffer buffer = new StringBuffer();
buffer.append(function);
buffer.append("__");
if (paramTypes.length > 0) {
for (int i = 0; i < paramTypes.length; i++) {
Class paramType = paramTypes[i];
buffer.append(toC(getTypeSignature(paramType)));
}
}
return buffer.toString();
}
return function;
}
static int getByteCount(Class clazz) {
if (clazz == Integer.TYPE) return 4;
if (clazz == Boolean.TYPE) return 4;
if (clazz == Long.TYPE) return 8;
if (clazz == Short.TYPE) return 2;
if (clazz == Character.TYPE) return 2;
if (clazz == Byte.TYPE) return 1;
if (clazz == Float.TYPE) return 4;
if (clazz == Double.TYPE) return 8;
return 4;
}
static String getTypeSignature(Class clazz) {
if (clazz == Void.TYPE) return "V";
if (clazz == Integer.TYPE) return "I";
if (clazz == Boolean.TYPE) return "Z";
if (clazz == Long.TYPE) return "J";
if (clazz == Short.TYPE) return "S";
if (clazz == Character.TYPE) return "C";
if (clazz == Byte.TYPE) return "B";
if (clazz == Float.TYPE) return "F";
if (clazz == Double.TYPE) return "D";
if (clazz == String.class) return "Ljava/lang/String;";
if (clazz.isArray()) {
Class componentType = clazz.getComponentType();
return "[" + getTypeSignature(componentType);
}
return "L" + clazz.getName().replace('.', '/') + ";";
}
static String getTypeSignature1(Class clazz) {
if (clazz == Void.TYPE) return "Void";
if (clazz == Integer.TYPE) return "Int";
if (clazz == Boolean.TYPE) return "Boolean";
if (clazz == Long.TYPE) return "Long";
if (clazz == Short.TYPE) return "Short";
if (clazz == Character.TYPE) return "Char";
if (clazz == Byte.TYPE) return "Byte";
if (clazz == Float.TYPE) return "Float";
if (clazz == Double.TYPE) return "Double";
if (clazz == String.class) return "String";
return "Object";
}
static String getTypeSignature2(Class clazz) {
if (clazz == Void.TYPE) return "void";
if (clazz == Integer.TYPE) return "jint";
if (clazz == Boolean.TYPE) return "jboolean";
if (clazz == Long.TYPE) return "jlong";
if (clazz == Short.TYPE) return "jshort";
if (clazz == Character.TYPE) return "jchar";
if (clazz == Byte.TYPE) return "jbyte";
if (clazz == Float.TYPE) return "jfloat";
if (clazz == Double.TYPE) return "jdouble";
if (clazz == String.class) return "jstring";
if (clazz == Class.class) return "jclass";
if (clazz.isArray()) {
Class componentType = clazz.getComponentType();
return getTypeSignature2(componentType) + "Array";
}
return "jobject";
}
static String getTypeSignature3(Class clazz) {
if (clazz == Void.TYPE) return "void";
if (clazz == Integer.TYPE) return "int";
if (clazz == Boolean.TYPE) return "boolean";
if (clazz == Long.TYPE) return "long";
if (clazz == Short.TYPE) return "short";
if (clazz == Character.TYPE) return "char";
if (clazz == Byte.TYPE) return "byte";
if (clazz == Float.TYPE) return "float";
if (clazz == Double.TYPE) return "double";
if (clazz == String.class) return "String";
if (clazz.isArray()) {
Class componentType = clazz.getComponentType();
return getTypeSignature3(componentType) + "[]";
}
return clazz.getName();
}
static String getTypeSignature4(Class clazz) {
if (clazz == Void.TYPE) return "void";
if (clazz == Integer.TYPE) return "jint";
if (clazz == Boolean.TYPE) return "jboolean";
if (clazz == Long.TYPE) return "jlong";
if (clazz == Short.TYPE) return "jshort";
if (clazz == Character.TYPE) return "jchar";
if (clazz == Byte.TYPE) return "jbyte";
if (clazz == Float.TYPE) return "jfloat";
if (clazz == Double.TYPE) return "jdouble";
if (clazz == String.class) return "jstring";
if (clazz.isArray()) {
Class componentType = clazz.getComponentType();
return getTypeSignature4(componentType) + " *";
}
return getClassName(clazz) + " *";
}
static HashMap uniqueCache = new HashMap();
static Class uniqueClassCache;
static Method[] uniqueMethodsCache;
static synchronized boolean isNativeUnique(Method method) {
if ((method.getModifiers() & Modifier.NATIVE) == 0) return false;
Object unique = uniqueCache.get(method);
if (unique != null) return ((Boolean)unique).booleanValue();
boolean result = true;
Method[] methods;
String name = method.getName();
Class clazz = method.getDeclaringClass();
if (clazz.equals(uniqueClassCache)) {
methods = uniqueMethodsCache;
} else {
methods = clazz.getDeclaredMethods();
uniqueClassCache = clazz;
uniqueMethodsCache = methods;
}
for (int i = 0; i < methods.length; i++) {
Method mth = methods[i];
if ((mth.getModifiers() & Modifier.NATIVE) != 0 &&
method != mth && !method.equals(mth) &&
name.equals(mth.getName()))
{
result = false;
break;
}
}
uniqueCache.put(method, new Boolean(result));
return result;
}
static void sort(Method[] methods) {
Arrays.sort(methods, new Comparator() {
public int compare(Object a, Object b) {
Method mth1 = (Method)a;
Method mth2 = (Method)b;
int result = mth1.getName().compareTo(mth2.getName());
return result != 0 ? result : getFunctionName(mth1).compareTo(getFunctionName(mth2));
}
});
}
static void sort(Field[] fields) {
Arrays.sort(fields, new Comparator() {
public int compare(Object a, Object b) {
return ((Field)a).getName().compareTo(((Field)b).getName());
}
});
}
static void sort(Class[] classes) {
Arrays.sort(classes, new Comparator() {
public int compare(Object a, Object b) {
return ((Class)a).getName().compareTo(((Class)b).getName());
}
});
}
static String toC(String str) {
int length = str.length();
StringBuffer buffer = new StringBuffer(length * 2);
for (int i = 0; i < length; i++) {
char c = str.charAt(i);
switch (c) {
case '_': buffer.append("_1"); break;
case ';': buffer.append("_2"); break;
case '[': buffer.append("_3"); break;
case '.': buffer.append("_"); break;
case '/': buffer.append("_"); break;
default: buffer.append(c);
}
}
return buffer.toString();
}
public abstract void generate(Class clazz);
public void generateCopyright() {
}
public void generateIncludes() {
}
public void generate() {
if (classes == null) return;
generateCopyright();
generateIncludes();
sort(classes);
for (int i = 0; i < classes.length; i++) {
Class clazz = classes[i];
ClassData data = getMetaData().getMetaData(clazz);
if (data.getFlag("cpp")) {
isCPP = true;
break;
}
}
for (int i = 0; i < classes.length; i++) {
Class clazz = classes[i];
if (getGenerate(clazz)) generate(clazz);
if (progress != null) progress.step();
}
output.flush();
}
public void generateMetaData(String key) {
MetaData mt = getMetaData();
String data = mt.getMetaData(key, null);
if (data == null) return;
if (data.length() == 0) return;
outputln(fixDelimiter(data));
}
public Class[] getClasses() {
return classes;
}
protected boolean getGenerate(Class clazz) {
ClassData data = getMetaData().getMetaData(clazz);
return !data.getFlag("no_gen");
}
public boolean getCPP() {
return isCPP;
}
public String getDelimiter() {
return delimiter;
}
public String getExtension() {
return getCPP() ? ".cpp" : ".c";
}
public String getFileName() {
return getOutputName() + getSuffix() + getExtension();
}
public PrintStream getOutput() {
return output;
}
public String getOutputName() {
return getClassName(getMainClass()).toLowerCase();
}
public Class getMainClass() {
return mainClass;
}
public MetaData getMetaData() {
return metaData;
}
public String getPlatform() {
return SWT.getPlatform();
}
public ProgressMonitor getProgressMonitor() {
return progress;
}
public String getSuffix() {
return "";
}
public void output(String str) {
output.print(str);
}
public void outputln() {
output(getDelimiter());
}
public void outputln(String str) {
output(str);
output(getDelimiter());
}
public void setClasses(Class[] classes) {
this.classes = classes;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public void setMainClass(Class mainClass) {
this.mainClass = mainClass;
}
public void setMetaData(MetaData data) {
metaData = data;
}
public void setOutput(PrintStream output) {
this.output = output;
}
public void setProgressMonitor(ProgressMonitor progress) {
this.progress = progress;
}
}