aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/glavo/javah/Utils.java
blob: cb1ceef8b5d4508b8d15094db998c007934b1c1c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package org.glavo.javah;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;

import java.io.IOException;
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.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 {
    public static final int MAX_SUPPORTED_VERSION = 13;

    public static final List<String> MULTI_RELEASE_VERSIONS =
            IntStream.rangeClosed(9, MAX_SUPPORTED_VERSION).mapToObj(Integer::toString).collect(Collectors.toList());

    public static final Pattern SIMPLE_NAME_PATTERN = Pattern.compile("[^.;\\[/]+");
    public static final Pattern FULL_NAME_PATTERN =
            Pattern.compile("[^.;\\[/]+(\\.[^.;\\[/]+)*");

    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[^.;\\[/]+(/[^.;\\[/]+)*;))");

    public static final PrintWriter NOOP_WRITER = new PrintWriter(new Writer() {
        @Override
        public void write(char[] cbuf, int off, int len) throws IOException {
        }

        @Override
        public void flush() throws IOException {
        }

        @Override
        public void close() throws IOException {
        }
    });

    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 builder.toString();
    }

    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));
            }
        }
        return builder.toString();
    }

    public static Path classPathRoot(Path p) {
        Objects.requireNonNull(p);
        p = p.toAbsolutePath();

        if (Files.notExists(p)) {
            return null;
        }
        if (Files.isDirectory(p)) {
            return p;
        }

        try {
            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;
        }
        return null;
    }

    public static ClassName superClassOf(ClassReader reader) {
        Objects.requireNonNull(reader);
        class V extends ClassVisitor {
            V() {
                super(Opcodes.ASM7);
            }

            ClassName superName = null;

            @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('/', '.'));
                }
            }
        }
        V v = new V();
        reader.accept(v, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
        return v.superName;
    }
}