summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/mapping/BehaviorSignature.java96
-rw-r--r--src/cuchaz/enigma/mapping/Type.java179
2 files changed, 275 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/mapping/BehaviorSignature.java b/src/cuchaz/enigma/mapping/BehaviorSignature.java
new file mode 100644
index 00000000..a6371f85
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/BehaviorSignature.java
@@ -0,0 +1,96 @@
1package cuchaz.enigma.mapping;
2
3import java.util.List;
4
5import com.beust.jcommander.internal.Lists;
6
7public class BehaviorSignature {
8
9 public static interface ClassReplacer {
10 ClassEntry replace(ClassEntry entry);
11 }
12
13 private List<Type> m_argumentTypes;
14 private Type m_returnType;
15
16 public BehaviorSignature(String signature) {
17 m_argumentTypes = Lists.newArrayList();
18 int i=0;
19 while (i<signature.length()) {
20 char c = signature.charAt(i);
21 if (c == '(') {
22 assert(m_argumentTypes.isEmpty());
23 assert(m_returnType == null);
24 i++;
25 } else if (c == ')') {
26 i++;
27 break;
28 } else {
29 String type = Type.parseFirst(signature.substring(i));
30 m_argumentTypes.add(new Type(type));
31 i += type.length();
32 }
33 }
34 m_returnType = new Type(Type.parseFirst(signature.substring(i)));
35 }
36
37 public BehaviorSignature(BehaviorSignature other, ClassReplacer replacer) {
38 m_argumentTypes = Lists.newArrayList(other.m_argumentTypes);
39 for (int i=0; i<m_argumentTypes.size(); i++) {
40 Type type = m_argumentTypes.get(i);
41 if (type.isClass()) {
42 ClassEntry newClassEntry = replacer.replace(type.getClassEntry());
43 if (newClassEntry != null) {
44 m_argumentTypes.set(i, new Type(newClassEntry));
45 }
46 }
47 }
48 m_returnType = other.m_returnType;
49 if (other.m_returnType.isClass()) {
50 ClassEntry newClassEntry = replacer.replace(m_returnType.getClassEntry());
51 if (newClassEntry != null) {
52 m_returnType = new Type(newClassEntry);
53 }
54 }
55 }
56
57 public List<Type> getArgumentTypes() {
58 return m_argumentTypes;
59 }
60
61 public Type getReturnType() {
62 return m_returnType;
63 }
64
65 @Override
66 public String toString() {
67 StringBuilder buf = new StringBuilder();
68 buf.append("(");
69 for (int i=0; i<m_argumentTypes.size(); i++) {
70 if (i > 0) {
71 buf.append(",");
72 }
73 buf.append(m_argumentTypes.get(i).toString());
74 }
75 buf.append(")");
76 buf.append(m_returnType.toString());
77 return buf.toString();
78 }
79
80 public Iterable<Type> types() {
81 List<Type> types = Lists.newArrayList();
82 types.addAll(m_argumentTypes);
83 types.add(m_returnType);
84 return types;
85 }
86
87 public Iterable<ClassEntry> classes() {
88 List<ClassEntry> out = Lists.newArrayList();
89 for (Type type : types()) {
90 if (type.isClass()) {
91 out.add(type.getClassEntry());
92 }
93 }
94 return out;
95 }
96}
diff --git a/src/cuchaz/enigma/mapping/Type.java b/src/cuchaz/enigma/mapping/Type.java
new file mode 100644
index 00000000..2273e21b
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Type.java
@@ -0,0 +1,179 @@
1package cuchaz.enigma.mapping;
2
3import java.util.Map;
4
5import com.google.common.collect.Maps;
6
7public class Type {
8
9 public enum Primitive {
10 Byte('B'),
11 Character('C'),
12 Short('S'),
13 Integer('I'),
14 Long('J'),
15 Float('F'),
16 Double('D'),
17 Boolean('Z');
18
19 private static final Map<Character,Primitive> m_lookup;
20
21 static {
22 m_lookup = Maps.newTreeMap();
23 for (Primitive val : values()) {
24 m_lookup.put(val.getCode(), val);
25 }
26 }
27
28 public static Primitive get(char code) {
29 return m_lookup.get(code);
30 }
31
32 private char m_code;
33
34 private Primitive(char code) {
35 m_code = code;
36 }
37
38 public char getCode() {
39 return m_code;
40 }
41 }
42
43 public static String parseFirst(String in) {
44
45 // read one type from the input
46
47 char c = in.charAt(0);
48
49 // first check for void
50 if (c == 'V') {
51 return "V";
52 }
53
54 // then check for primitives
55 Primitive primitive = Primitive.get(c);
56 if (primitive != null) {
57 return in.substring(0, 1);
58 }
59
60 // then check for classes
61 if (c == 'L') {
62 return readClass(in);
63 }
64
65 // then check for arrays
66 int dim = countArrayDimension(in);
67 if (dim > 0) {
68 String arrayType = Type.parseFirst(in.substring(dim));
69 return in.substring(0, dim + arrayType.length());
70 }
71
72 throw new IllegalArgumentException("don't know how to parse: " + in);
73 }
74
75 private String m_name;
76
77 public Type(String name) {
78 m_name = name;
79 }
80
81 public Type(ClassEntry classEntry) {
82 m_name = "L" + classEntry.getClassName() + ";";
83 }
84
85 @Override
86 public String toString() {
87 return m_name;
88 }
89
90 public boolean isVoid() {
91 return m_name.length() == 1 && m_name.charAt(0) == 'V';
92 }
93
94 public boolean isPrimitive() {
95 return m_name.length() == 1 && Primitive.get(m_name.charAt(0)) != null;
96 }
97
98 public Primitive getPrimitive() {
99 if (!isPrimitive()) {
100 throw new IllegalStateException("not a primitive");
101 }
102 return Primitive.get(m_name.charAt(0));
103 }
104
105 public boolean isClass() {
106 return m_name.charAt(0) == 'L' && m_name.charAt(m_name.length() - 1) == ';';
107 }
108
109 public ClassEntry getClassEntry() {
110 if (!isClass()) {
111 throw new IllegalStateException("not a class");
112 }
113 String name = m_name.substring(1, m_name.length() - 1);
114
115 int pos = name.indexOf('<');
116 if (pos >= 0) {
117 // remove the parameters from the class name
118 name = name.substring(0, pos);
119 }
120
121 return new ClassEntry(name);
122 }
123
124 public boolean isArray() {
125 return m_name.charAt(0) == '[';
126 }
127
128 public int getArrayDimension() {
129 if (!isArray()) {
130 throw new IllegalStateException("not an array");
131 }
132 return countArrayDimension(m_name);
133 }
134
135 public Type getArrayType() {
136 if (!isArray()) {
137 throw new IllegalStateException("not an array");
138 }
139 return new Type(m_name.substring(getArrayDimension(), m_name.length()));
140 }
141
142 @Override
143 public boolean equals(Object other) {
144 if (other instanceof Type) {
145 return equals((Type)other);
146 }
147 return false;
148 }
149
150 public boolean equals(Type other) {
151 return m_name.equals(other.m_name);
152 }
153
154 private static int countArrayDimension(String in) {
155 int i=0;
156 for(; i < in.length() && in.charAt(i) == '['; i++);
157 return i;
158 }
159
160 private static String readClass(String in) {
161 // read all the characters in the buffer until we hit a ';'
162 // remember to treat parameters correctly
163 StringBuilder buf = new StringBuilder();
164 int depth = 0;
165 for (int i=0; i<in.length(); i++) {
166 char c = in.charAt(i);
167 buf.append(c);
168
169 if (c == '<') {
170 depth++;
171 } else if (c == '>') {
172 depth--;
173 } else if (depth == 0 && c == ';') {
174 return buf.toString();
175 }
176 }
177 return null;
178 }
179}