From 4c0edeb4fc0ab85bae4bd41dfbf6a0089dfbf467 Mon Sep 17 00:00:00 2001 From: Glavo Date: Fri, 29 Nov 2019 03:30:24 +0800 Subject: update --- src/main/java/org/glavo/javah/HeaderGenerator.java | 529 --------------------- 1 file changed, 529 deletions(-) delete mode 100644 src/main/java/org/glavo/javah/HeaderGenerator.java (limited to 'src/main/java/org/glavo/javah/HeaderGenerator.java') diff --git a/src/main/java/org/glavo/javah/HeaderGenerator.java b/src/main/java/org/glavo/javah/HeaderGenerator.java deleted file mode 100644 index 6c585ec..0000000 --- a/src/main/java/org/glavo/javah/HeaderGenerator.java +++ /dev/null @@ -1,529 +0,0 @@ -package org.glavo.javah; - -import org.objectweb.asm.*; - -import java.io.*; -import java.nio.file.*; -import java.util.*; - -public final class HeaderGenerator { - private static final Path[] EMPTY_PATH_ARRAY = new Path[0]; - private static final List THROWABLE_NAME_LIST = Arrays.asList("Ljava/lang/Throwable;", "Ljava/lang/Error;", "Ljava/lang/Exception"); - private static final HeaderGenerator generator = new HeaderGenerator(); - public static final String VERSION = "0.1.1"; - private static final String message = "Usage: \n" + - " javah [options] \n" + - "where [options] include:\n" + - " -o Output file (only one of -d or -o may be used)\n" + - " -d Output directory\n" + - " -h -help --help -? Print this message\n" + - " -version Print version information\n" + - " -classpath Path from which to load classes\n" + - " -cp Path from which to load classes\n" + - " are specified with their fully qualified names\n" + - "(for example, java.lang.Object)."; - - private static String escape(String source) { - StringBuilder builder = new StringBuilder(); - char ch; - for (int i = 0; i < source.length(); i++) { - switch (ch = source.charAt(i)) { - case '_': - builder.append("_1"); - break; - case ';': - builder.append("_2"); - break; - case '[': - builder.append("_3"); - break; - case '/': - builder.append('.'); - break; - default: - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { - builder.append(ch); - } else { - builder.append("_0").append(String.format("%04x", (int) ch)); - } - } - } - return builder.toString(); - } - - public static void generateFunctionDeclarations(ClassReader reader, PrintWriter output) { - getGenerator().classGenerateFunctionDeclarations(reader, output); - } - - public static void generateHeader(ClassReader reader, PrintWriter output) { - getGenerator().classGenerateHeader(reader, output); - } - - public static void generateHeader(byte[] classFile, PrintWriter output) { - getGenerator().classGenerateHeader(classFile, output); - } - - public static void generateHeader(byte[] classFileBuffer, int classFileOffset, int classFileLength, PrintWriter output) { - getGenerator().classGenerateHeader(classFileBuffer, classFileOffset, classFileLength, output); - } - - public static void generateHeader(String className, PrintWriter output) throws IOException { - getGenerator().classGenerateHeader(className, output); - } - - public static void generateHeader(InputStream input, PrintWriter output) throws IOException { - getGenerator().classGenerateHeader(input, output); - } - - public static HeaderGenerator getGenerator() { - return generator; - } - - private Path[] classPaths; - private boolean useRuntimeClassPath; - - public HeaderGenerator() { - this(EMPTY_PATH_ARRAY, true); - } - - public HeaderGenerator(boolean useRuntimeClassPath) { - this(EMPTY_PATH_ARRAY, useRuntimeClassPath); - } - - public HeaderGenerator(Path[] classPaths) { - this(classPaths, true); - } - - public HeaderGenerator(Path[] classPaths, boolean useRuntimeClassPath) { - Objects.requireNonNull(classPaths); - this.classPaths = classPaths; - this.useRuntimeClassPath = useRuntimeClassPath; - } - - private boolean isThrowable(Type type) { - String desc = type.getDescriptor(); - if (!desc.startsWith("L")) { - return false; - } - if (classPaths.length == 0 && !useRuntimeClassPath) { - return THROWABLE_NAME_LIST.contains(type.getDescriptor()); - } - String className = type.getInternalName(); - while (true) { - if (className == null) { - return false; - } - if (className.equals("java/lang/Throwable")) { - return true; - } - try { - ClassReader reader = findClass(className); - if (reader == null) { - return false; - } - className = reader.getSuperName(); - } catch (Exception ignored) { - return false; - } - } - } - - private String typeToNative(Type tpe) { - if (tpe == Type.BOOLEAN_TYPE) { - return "jboolean"; - } else if (tpe == Type.BYTE_TYPE) { - return "jbyte"; - } else if (tpe == Type.CHAR_TYPE) { - return "jchar"; - } else if (tpe == Type.SHORT_TYPE) { - return "jshort"; - } else if (tpe == Type.INT_TYPE) { - return "jint"; - } else if (tpe == Type.LONG_TYPE) { - return "jlong"; - } else if (tpe == Type.FLOAT_TYPE) { - return "jfloat"; - } else if (tpe == Type.DOUBLE_TYPE) { - return "jdouble"; - } else if (tpe == Type.VOID_TYPE) { - return "void"; - } else { - String desc = tpe.getDescriptor(); - if (desc.startsWith("[")) { - Type elemTpe = tpe.getElementType(); - String descriptor = elemTpe.getDescriptor(); - if (descriptor.startsWith("[") || descriptor.startsWith("L")) { - return "jobjectArray"; - } - return typeToNative(elemTpe) + "Array"; - } - if (desc.equals("Ljava/lang/String;")) { - return "jstring"; - } - if (desc.equals("Ljava/lang/Class;")) { - return "jclass"; - } - if (isThrowable(tpe)) { - return "jthrowable"; - } - return "jobject"; - } - } - - private ClassReader findClass(String name) { - loop: - for (Path path : classPaths) { - path = path.toAbsolutePath(); - if (!Files.exists(path)) { - continue; - } - String[] ps = name.split("/|\\."); - if (ps.length == 0) { - continue; - } - ps[ps.length - 1] += ".class"; - for (String p : ps) { - path = path.resolve(p); - if (!Files.exists(path)) { - continue loop; - } - } - try { - return new ClassReader(Files.newInputStream(path)); - } catch (IOException ignored) { - } - } - try { - return new ClassReader(name.replace('/', '.')); - } catch (IOException e) { - return null; - } - } - - private void classGenerateFunctionDeclarations(Generator generator, PrintWriter output) { - String className = escape(generator.getClassName()); - - for (Map.Entry> entry : generator.getMethods().entrySet()) { - boolean overload = entry.getValue().size() > 1; - for (MethodDesc desc : entry.getValue()) { - String methodName = escape(entry.getKey()); - output.println("/*" + "\n" + - " * Class: " + className + "\n" + - " * Method: " + entry.getKey() + "\n" + - " * Signature: " + desc.descriptor + "\n" + - " */" - ); - - Type[] argTypes = Type.getArgumentTypes(desc.descriptor); - Type retType = Type.getReturnType(desc.descriptor); - - output.print( - "JNIEXPORT " + typeToNative(retType) + " JNICALL Java_" + className + "_" + methodName - ); - - if (overload) { - output.print("__"); - for (Type tpe : argTypes) { - output.print(escape(tpe.toString())); - } - } - output.println(); - - output.print(" (JNIEnv *, "); - if (desc.isStatic) { - output.print("jclass"); - } else { - output.print("jobject"); - } - for (Type tpe : argTypes) { - output.print(", " + typeToNative(tpe)); - } - output.println(");\n"); - } - - } - } - - public void classGenerateFunctionDeclarations(ClassReader reader, PrintWriter output) { - Generator generator = new Generator(); - reader.accept(generator, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - classGenerateFunctionDeclarations(generator, output); - } - - private void classGenerateHeaderWithoutInclude(Generator generator, PrintWriter output) { - StringBuilder builder = new StringBuilder(); - String className = escape(generator.getClassName()); - - output.println("/* Header for class " + className + " */"); - - String includeHeader = "_Include_" + className; - output.println("#ifndef " + includeHeader); - output.println("#define " + includeHeader); - - output.println("#ifdef __cplusplus\n" + - "extern \"C\" {\n" + - "#endif"); - - classGenerateFunctionDeclarations(generator, output); - - output.println("#ifdef __cplusplus\n" + - "}\n" + - "#endif\n" + - "#endif\n"); - } - - private void classGenerateHeaderWithoutInclude(ClassReader reader, PrintWriter output) { - Generator generator = new Generator(); - reader.accept(generator, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - classGenerateHeaderWithoutInclude(generator, output); - } - - private void classGenerateHeader(Generator generator, PrintWriter output) { - output.println("/* DO NOT EDIT THIS FILE - it is machine generated */"); - output.println("#include "); - - classGenerateHeaderWithoutInclude(generator, output); - } - - public void classGenerateHeader(ClassReader reader, PrintWriter output) { - Generator generator = new Generator(); - reader.accept(generator, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - classGenerateHeader(generator, output); - } - - public void classGenerateHeader(byte[] classFile, PrintWriter output) { - classGenerateHeader(new ClassReader(classFile), output); - } - - public void classGenerateHeader(byte[] classFileBuffer, int classFileOffset, int classFileLength, PrintWriter output) { - classGenerateHeader(new ClassReader(classFileBuffer, classFileOffset, classFileLength), output); - } - - public void classGenerateHeader(String className, PrintWriter output) throws IOException { - ClassReader reader = findClass(className); - if (reader == null) { - throw new IOException(); - } - classGenerateHeader(reader, output); - } - - public void classGenerateHeader(InputStream input, PrintWriter output) throws IOException { - classGenerateHeader(new ClassReader(input), output); - } - - public Path[] getClassPaths() { - return classPaths; - } - - public void setClassPaths(Path[] classPaths) { - Objects.requireNonNull(classPaths); - this.classPaths = classPaths; - } - - public boolean isUseRuntimeClassPath() { - return useRuntimeClassPath; - } - - public void setUseRuntimeClassPath(boolean useRuntimeClassPath) { - this.useRuntimeClassPath = useRuntimeClassPath; - } - - public static void main(String[] args) throws IOException { - boolean isWindows = System.getProperty("os.name", "").toLowerCase().contains("windows"); - ArrayList cps = new ArrayList<>(); - Path outputFile = null; - Path outputDir = null; - ArrayList classNames = new ArrayList<>(); - - if (args.length == 0) { - System.out.println(message); - return; - } - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.startsWith("-")) { - switch (arg) { - case "-h": - case "-help": - case "--help": - case "-?": - System.out.println(message); - return; - case "-version": - System.out.println(VERSION); - return; - case "-cp": - case "-classpath": - i++; - if (i == args.length) { - System.err.println("javah: " + arg + " requires an argument."); - return; - } - String[] s = args[i].split(isWindows ? ";" : ":"); - for (String ss : s) { - Path p = Paths.get(ss); - if (Files.exists(p)) { - if (Files.isDirectory(p)) { - cps.add(p); - } else if (ss.toLowerCase().endsWith(".jar") || ss.toLowerCase().endsWith(".zip")) { - try { - cps.add(FileSystems.newFileSystem(p, null).getPath("/")); - } catch (Exception ignored) { - } - } - } - } - break; - case "-o": - i++; - if (i == args.length) { - System.err.println("javah: " + arg + " requires an argument."); - return; - } - if (outputDir != null) { - System.err.println("Error: Can't mix options -d and -o. Try -help."); - return; - } - outputFile = Paths.get(args[i]); - break; - - case "-d": - i++; - if (i == args.length) { - System.err.println("javah: " + arg + " requires an argument."); - return; - } - if (outputFile != null) { - System.err.println("Error: Can't mix options -d and -o. Try -help."); - return; - } - outputDir = Paths.get(args[i]); - - break; - default: - System.err.println("Error: unknown option: " + arg); - return; - } - - } else { - if (arg.contains("/")) { - int idx = arg.indexOf('/'); - if (idx != arg.lastIndexOf('/')) { - System.err.println("Not a valid class name: " + arg); - } - arg = arg.substring(idx + 1); - } - classNames.add(arg); - } - - if (outputDir == null && outputFile == null) { - outputDir = Paths.get(System.getProperty("user.dir", ".")); - } - if (cps.isEmpty()) { - cps.add(Paths.get(System.getProperty("user.dir", "."))); - } - - if (outputDir != null && Files.notExists(outputDir)) { - Files.createDirectories(outputDir); - } - - if (outputFile != null && Files.notExists(outputFile)) { - if (Files.notExists(outputFile.getParent())) { - Files.createDirectories(outputFile.getParent()); - } - } - - HeaderGenerator generator = new HeaderGenerator(cps.toArray(new Path[0])); - if (outputFile != null) { - if (Files.notExists(outputFile.getParent())) { - Files.createDirectories(outputFile.getParent()); - } - try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(outputFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) { - boolean first = true; - for (String name : classNames) { - ClassReader reader = generator.findClass(name); - if (reader == null) { - System.err.println("Error: Could not find class file for '" + name + "'."); - return; - } - Generator g = new Generator(); - reader.accept(g, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - if (first) { - generator.classGenerateHeader(g, writer); - first = false; - } else { - generator.classGenerateHeaderWithoutInclude(g, writer); - } - } - } - } - if (outputDir != null) { - if (Files.notExists(outputDir)) { - Files.createDirectories(outputDir); - } - for (String name : classNames) { - ClassReader reader = generator.findClass(name); - if (reader == null) { - System.err.println("Error: Could not find class file for '" + name + "'."); - return; - } - Generator g = new Generator(); - reader.accept(g, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - - try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(outputDir.resolve(name.replace('.', '_') + ".h"), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) { - generator.classGenerateHeader(g, writer); - } - } - } - - } - } -} - -class MethodDesc { - public final boolean isStatic; - public final String descriptor; - - public MethodDesc(boolean isStatic, String descriptor) { - this.isStatic = isStatic; - this.descriptor = descriptor; - } -} - -class Generator extends ClassVisitor { - private String className; - - private Map constants = new LinkedHashMap<>(); - private Map> methods = new LinkedHashMap>(); - - public Generator() { - super(Opcodes.ASM5); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - className = name; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - if ((access & Opcodes.ACC_NATIVE) != 0) { - if (methods.containsKey(name)) { - methods.get(name).add(new MethodDesc((access & Opcodes.ACC_STATIC) != 0, descriptor)); - } else { - LinkedHashSet set = new LinkedHashSet<>(); - set.add(new MethodDesc((access & Opcodes.ACC_STATIC) != 0, descriptor)); - methods.put(name, set); - } - } - return null; - } - - public String getClassName() { - return className; - } - - public Map> getMethods() { - return methods; - } -} \ No newline at end of file -- cgit v1.2.3