001 /*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005 package org.bridj.util;
006
007 import java.io.IOException;
008 import java.lang.reflect.Method;
009 import java.lang.reflect.Modifier;
010 import java.util.HashMap;
011 import java.util.Map;
012 import java.util.Set;
013 import java.util.WeakHashMap;
014 import java.util.regex.Pattern;
015 import org.bridj.BridJ;
016 import org.bridj.Platform;
017 import org.bridj.Version;
018
019 /**
020 *
021 * @author ochafik
022 */
023 public class JNIUtils {
024
025 private static class NativeMethodsCache {
026 Map<String, String> signatures = new HashMap<String, String>();
027 public NativeMethodsCache(String internalClassName) throws IOException {
028 for (String[] sig : BytecodeAnalyzer.getNativeMethodSignatures(internalClassName, Platform.getClassLoader())) {
029 signatures.put(sig[1], sig[2]);
030 }
031 }
032 public String get(String name) {
033 return signatures.get(name);
034 }
035 public Set<String> getNames() {
036 return signatures.keySet();
037 }
038 }
039 private static Map<String, NativeMethodsCache> nativeMethodsCache = new WeakHashMap<String, NativeMethodsCache>();
040 private static synchronized NativeMethodsCache getNativeMethodsCache(String internalClassName) throws IOException {
041 NativeMethodsCache cache = nativeMethodsCache.get(internalClassName);
042 if (cache == null)
043 nativeMethodsCache.put(internalClassName, cache = new NativeMethodsCache(internalClassName));
044 return cache;
045 }
046 private static final String bridjPackage = BridJ.class.getPackage().getName();
047
048 private static final String bridjNormalPackagePrefix = bridjPackage.endsWith(Version.VERSION_SPECIFIC_SUB_PACKAGE) ? bridjPackage.substring(0, bridjPackage.length() - Version.VERSION_SPECIFIC_SUB_PACKAGE.length()) : bridjPackage + ".";
049 private static final String bridjVersionSpecificPackagePrefix = bridjPackage + ".";
050
051 static int findLastNonEscapeUnderscore(String s) {
052 int len = s.length(), i = len;
053 do {
054 i = s.lastIndexOf("_", i - 1);
055 if (i >= 0 && (i == len - 1 || !Character.isDigit(s.charAt(i + 1))))
056 return i;
057 } while (i > 0);
058 return -1;
059 }
060 public static String decodeVersionSpecificMethodNameClassAndSignature(String symbolName, Object[] nameAndSigArray) throws NoSuchMethodException, IOException {
061 return decodeMethodNameClassAndSignature(symbolName, nameAndSigArray, bridjNormalPackagePrefix, bridjVersionSpecificPackagePrefix);
062 }
063
064 static String decodeMethodNameClassAndSignature(String symbolName, Object[] nameAndSigArray, String normalClassPrefix, String replacementClassPrefix) throws NoSuchMethodException, IOException {
065 if (symbolName.startsWith("_"))
066 symbolName = symbolName.substring(1);
067 if (symbolName.startsWith("Java_"))
068 symbolName = symbolName.substring("Java_".length());
069
070 int i = findLastNonEscapeUnderscore(symbolName);
071 String className = symbolName.substring(0, i).replace('_', '.');
072 if (normalClassPrefix != null) {
073 if (className.startsWith(normalClassPrefix) && !className.startsWith(replacementClassPrefix))
074 className = replacementClassPrefix + className.substring(normalClassPrefix.length());
075 }
076 String methodName = symbolName.substring(i + 1).replaceAll("_1", "_");
077
078 NativeMethodsCache mc = getNativeMethodsCache(className.replace('.', '/'));
079 String sig = mc.get(methodName);
080 if (sig == null)
081 throw new NoSuchMethodException("Method " + methodName + " not found in class " + className + " : known method names = " + StringUtils.implode(mc.getNames(), ", "));
082
083 nameAndSigArray[0] = methodName;
084 nameAndSigArray[1] = sig;
085
086 String internalClassName = className.replace('.', '/');
087 return internalClassName;//className;
088
089 }
090 public static String getNativeName(Class c) {
091 return c.getName().replace('.', '/');
092 }
093 public static String getNativeSignature(Method m) {
094 StringBuffer b = new StringBuffer();
095 b.append('(');
096 for (Class c : m.getParameterTypes())
097 b.append(getNativeSignature(c));
098 b.append(')');
099 b.append(getNativeSignature(m.getReturnType()));
100 return b.toString();
101 }
102 public static String getNativeSignature(Class c) {
103 if (c.isPrimitive()) {
104 if (c == int.class)
105 return "I";
106 if (c == long.class)
107 return "J";
108 if (c == short.class)
109 return "S";
110 if (c == byte.class)
111 return "B";
112 if (c == boolean.class)
113 return "Z";
114 if (c == double.class)
115 return "D";
116 if (c == float.class)
117 return "F";
118 if (c == char.class)
119 return "C";
120 if (c == void.class)
121 return "V";
122
123 throw new RuntimeException("unexpected case");
124 }
125 if (c.isArray())
126 return "[" + getNativeSignature(c.getComponentType());
127 return "L" + getNativeName(c) + ";";
128 }
129 }