aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/glavo/javah/Utils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/glavo/javah/Utils.java')
-rw-r--r--src/main/java/org/glavo/javah/Utils.java271
1 files changed, 92 insertions, 179 deletions
diff --git a/src/main/java/org/glavo/javah/Utils.java b/src/main/java/org/glavo/javah/Utils.java
index e9043ea..cb1ceef 100644
--- a/src/main/java/org/glavo/javah/Utils.java
+++ b/src/main/java/org/glavo/javah/Utils.java
@@ -1,221 +1,134 @@
package org.glavo.javah;
-import org.objectweb.asm.Type;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
import java.io.IOException;
-import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.*;
-import java.util.jar.Manifest;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
class Utils {
- static String encode(String str) {
- StringBuilder buffer = new StringBuilder(str.length());
+ public static final int MAX_SUPPORTED_VERSION = 13;
- int len = str.length();
- for (int i = 0; i < len; i++) {
- char ch = str.charAt(i);
- if (ch == '_') {
- buffer.append("_1");
- } else if (ch == ';') {
- buffer.append("_2");
- } else if (ch == '[') {
- buffer.append("_3");
- } else if ((ch >= '0' && ch <= '9')
- || (ch >= 'a' && ch <= 'z')
- || (ch >= 'A' && ch <= 'Z')
- || ch == '/'
- || ch == '.') {
- buffer.append(ch);
- } else {
- buffer.append(String.format("_0%04x", (int) ch));
- }
- }
- return buffer.toString();
- }
+ public static final List<String> MULTI_RELEASE_VERSIONS =
+ IntStream.rangeClosed(9, MAX_SUPPORTED_VERSION).mapToObj(Integer::toString).collect(Collectors.toList());
- static String mapToNativeType(Type jt) {
- switch (jt.toString()) {
- case "Z":
- return "jboolean";
- case "B":
- return "jbyte";
- case "C":
- return "jchar";
- case "S":
- return "jshort";
- case "I":
- return "jint";
- case "J":
- return "jlong";
- case "F":
- return "jfloat";
- case "D":
- return "jdouble";
- case "V":
- return "void";
- case "Ljava/lang/Class;":
- return "jclass";
- case "Ljava/lang/String;":
- return "jstring";
- case "Ljava/lang/Throwable ;":
- return "jthrowable";
- case "[Z":
- return "jbooleanArray";
- case "[B":
- return "jbyteArray";
- case "[C":
- return "jcharArray";
- case "[S":
- return "jshortArray";
- case "[I":
- return "jintArray";
- case "[J":
- return "jlongArray";
- case "[F":
- return "jfloatArray";
- case "[D":
- return "jdoubleArray";
- }
+ public static final Pattern SIMPLE_NAME_PATTERN = Pattern.compile("[^.;\\[/]+");
+ public static final Pattern FULL_NAME_PATTERN =
+ Pattern.compile("[^.;\\[/]+(\\.[^.;\\[/]+)*");
- if (jt.toString().startsWith("[")) {
- return "jobjectArray";
- }
-
- return "jobject";
- }
+ public static final Pattern METHOD_NAME_PATTERN = Pattern.compile("(<init>)|(<cinit>)|([^.;\\[/<>]+)");
+ public static final Pattern METHOD_TYPE_PATTERN =
+ Pattern.compile("\\((?<args>(\\[*([BCDFIJSZ]|L[^.;\\[/]+(/[^.;\\\\\\[/]+)*;))*)\\)(?<ret>\\[*([BCDFIJSZV]|L[^.;\\[/]+(/[^.;\\[/]+)*;))");
- static String mangledArgSignature(Type methodType) {
- Objects.requireNonNull(methodType);
- String str = methodType.toString();
- int idx = str.indexOf(')');
- if (idx == -1) {
- throw new IllegalArgumentException(methodType.toString() + "is not a method type");
+ public static final PrintWriter NOOP_WRITER = new PrintWriter(new Writer() {
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
}
- return encode(str.substring(1, idx));
- }
-
- static boolean isRegularClassName(String name) {
- Objects.requireNonNull(name);
- return !name.contains("//")
- && !name.contains("..")
- && name.indexOf('\\') == -1
- && name.indexOf(';') == -1
- && name.indexOf('[') == -1;
- }
- static String fullClassNameOf(String name) {
- Objects.requireNonNull(name);
- int idx = name.indexOf('/');
- if (idx == -1) {
- return name;
+ @Override
+ public void flush() throws IOException {
}
- String cn = name.substring(idx + 1);
- if (cn.isEmpty() || cn.indexOf('/') == -1) {
- throw new IllegalArgumentException("Illegal class name: " + name);
- }
- return cn;
- }
- static String simpleNameOf(String name) {
- int idx = name.lastIndexOf('.');
- return name.substring(idx + 1);
- }
+ @Override
+ public void close() throws IOException {
+ }
+ });
- static Path searchFromPathList(List<Path> paths, String className) {
- Objects.requireNonNull(paths);
- Objects.requireNonNull(className);
- String fp = fullClassNameOf(className).replace('.', '/') + ".class";
- for (Path path : paths) {
- Objects.requireNonNull(path);
- Path p = path.resolve(fp);
- if (Files.isRegularFile(p)) {
- return p;
+ public static String mangleName(String name) {
+ StringBuilder builder = new StringBuilder(name.length() * 2);
+ int len = name.length();
+ for (int i = 0; i < len; i++) {
+ char ch = name.charAt(i);
+ if (ch == '.') {
+ builder.append('_');
+ } else if (ch == '_') {
+ builder.append("_1");
+ } else if (ch == ';') {
+ builder.append("_2");
+ } else if (ch == '[') {
+ builder.append("_3");
+ } else if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && (ch <= 'Z'))) {
+ builder.append(ch);
+ } else {
+ builder.append(String.format("_0%04x", (int) ch));
}
}
- return null;
+ return builder.toString();
}
- static List<Path> getPathsFrom(Path root) {
- Objects.requireNonNull(root);
- root = root.toAbsolutePath();
- if (Files.isRegularFile(root)) {
- String name = root.toString().toLowerCase();
- try {
- FileSystem fs = FileSystems.newFileSystem(root, (ClassLoader) null);
- if (name.endsWith(".jar")) {
- root = fs.getPath("/");
- } else if (name.endsWith(".jmod")) {
- root = fs.getPath("/classes");
- } else {
- return Collections.emptyList();
- }
- } catch (IOException e) {
- return Collections.emptyList();
+ public static String escape(String unicode) {
+ Objects.requireNonNull(unicode);
+ int len = unicode.length();
+ StringBuilder builder = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char ch = unicode.charAt(i);
+ if (ch >= ' ' && ch <= '~') {
+ builder.append(ch);
+ } else {
+ builder.append(String.format("\\u%04x", (int) ch));
}
}
- if (!Files.isDirectory(root)) {
- return Collections.emptyList();
- }
+ return builder.toString();
+ }
- boolean isMultiRelease = false;
- Path manifest = root.resolve("META-INF").resolve("MANIFEST.MF");
- if (Files.exists(manifest) && Files.isRegularFile(manifest)) {
- try (InputStream input = Files.newInputStream(manifest)) {
- isMultiRelease = Boolean.parseBoolean(
- new Manifest(input).getMainAttributes().getOrDefault("Multi-Release", "false").toString()
- );
+ public static Path classPathRoot(Path p) {
+ Objects.requireNonNull(p);
+ p = p.toAbsolutePath();
- } catch (Exception ignored) {
- }
+ if (Files.notExists(p)) {
+ return null;
}
-
- if (!isMultiRelease) {
- return Collections.singletonList(root);
+ if (Files.isDirectory(p)) {
+ return p;
}
- LinkedList<Path> list = new LinkedList<>();
- Path mr = root.resolve("META-INF").resolve("versions");
+
try {
- Files.list(mr)
- .filter(Utils::checkMultiReleaseVersion)
- .sorted(Comparator.comparingInt(a -> Integer.parseInt(a.getFileName().toString())))
- .forEachOrdered(list::addFirst);
+ FileSystem fs = FileSystems.newFileSystem(p, (ClassLoader) null);
+ String name = p.getFileName().toString().toLowerCase();
+ if (name.endsWith(".jar") || name.endsWith(".zip")) {
+ return fs.getPath("/");
+ }
+ if (name.endsWith(".jmod")) {
+ return fs.getPath("/", "classes");
+ }
+ fs.close();
} catch (IOException ignored) {
+ return null;
}
-
- list.add(root);
- return list;
+ return null;
}
- private static final String[] MULTI_VERSIONS = {"9", "10", "11", "12", "13"};
-
- private static boolean checkMultiReleaseVersion(Path p) {
- Objects.requireNonNull(p);
- String n = p.getFileName().toString();
- for (String version : MULTI_VERSIONS) {
- if (version.equals(n)) {
- return true;
+ public static ClassName superClassOf(ClassReader reader) {
+ Objects.requireNonNull(reader);
+ class V extends ClassVisitor {
+ V() {
+ super(Opcodes.ASM7);
}
- }
- return false;
- }
-
- static Path searchFrom(List<Path> searchPaths, String name) {
- Objects.requireNonNull(searchPaths);
- Objects.requireNonNull(name);
- name = simpleNameOf(name).replace('.', '/') + ".class";
+ ClassName superName = null;
- for (Path searchPath : searchPaths) {
- Path p = searchPath.resolve(name);
- if (Files.isRegularFile(p)) {
- return p;
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ if (superName != null) {
+ this.superName = ClassName.of(superName.replace('/', '.'));
+ }
}
}
- return null;
+ V v = new V();
+ reader.accept(v, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
+ return v.superName;
}
}