From 2b2249e873c4adfd2dd6e8f1f2489ccd9f6aa021 Mon Sep 17 00:00:00 2001
From: gegy1000
Date: Sat, 19 May 2018 17:02:46 +0200
Subject: Initial port to ASM
---
.../java/cuchaz/enigma/mapping/ArgumentEntry.java | 110 -------
.../cuchaz/enigma/mapping/ArgumentMapping.java | 50 ---
.../java/cuchaz/enigma/mapping/BehaviorEntry.java | 16 -
.../java/cuchaz/enigma/mapping/ClassDefEntry.java | 29 ++
.../java/cuchaz/enigma/mapping/ClassEntry.java | 26 +-
.../java/cuchaz/enigma/mapping/ClassMapping.java | 163 +++++-----
.../cuchaz/enigma/mapping/ClassNameReplacer.java | 16 -
.../cuchaz/enigma/mapping/ConstructorEntry.java | 105 -------
.../enigma/mapping/DirectionalTranslator.java | 319 +++++++++++++++++++
src/main/java/cuchaz/enigma/mapping/Entry.java | 4 +-
.../java/cuchaz/enigma/mapping/EntryFactory.java | 101 +-----
.../java/cuchaz/enigma/mapping/FieldDefEntry.java | 34 ++
.../java/cuchaz/enigma/mapping/FieldEntry.java | 51 ++-
.../java/cuchaz/enigma/mapping/FieldMapping.java | 36 +--
.../enigma/mapping/LocalVariableDefEntry.java | 75 +++++
.../cuchaz/enigma/mapping/LocalVariableEntry.java | 65 ++--
.../enigma/mapping/LocalVariableMapping.java | 50 +++
src/main/java/cuchaz/enigma/mapping/Mappings.java | 45 ++-
.../cuchaz/enigma/mapping/MappingsChecker.java | 10 +-
.../enigma/mapping/MappingsEnigmaReader.java | 18 +-
.../enigma/mapping/MappingsEnigmaWriter.java | 16 +-
.../cuchaz/enigma/mapping/MappingsRenamer.java | 163 +++++-----
.../cuchaz/enigma/mapping/MappingsSRGWriter.java | 6 +-
.../cuchaz/enigma/mapping/MappingsTinyReader.java | 4 +-
.../java/cuchaz/enigma/mapping/MethodDefEntry.java | 35 +++
.../cuchaz/enigma/mapping/MethodDescriptor.java | 113 +++++++
.../java/cuchaz/enigma/mapping/MethodEntry.java | 59 ++--
.../java/cuchaz/enigma/mapping/MethodMapping.java | 130 ++++----
.../java/cuchaz/enigma/mapping/NameValidator.java | 15 +-
.../cuchaz/enigma/mapping/ProcyonEntryFactory.java | 36 ++-
.../cuchaz/enigma/mapping/ReferencedEntryPool.java | 50 +++
src/main/java/cuchaz/enigma/mapping/Signature.java | 106 -------
.../enigma/mapping/TranslationDirection.java | 10 +-
.../java/cuchaz/enigma/mapping/Translator.java | 344 ++-------------------
.../java/cuchaz/enigma/mapping/TypeDescriptor.java | 240 ++++++++++++++
35 files changed, 1410 insertions(+), 1240 deletions(-)
delete mode 100644 src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/ClassDefEntry.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/FieldDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/LocalVariableDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/LocalVariableMapping.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/MethodDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/MethodDescriptor.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/ReferencedEntryPool.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/Signature.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java
(limited to 'src/main/java/cuchaz/enigma/mapping')
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
deleted file mode 100644
index 9154cc2..0000000
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.mapping;
-
-import cuchaz.enigma.utils.Utils;
-
-public class ArgumentEntry implements Entry {
-
- private BehaviorEntry behaviorEntry;
- private int index;
- private String name;
-
- public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) {
- if (behaviorEntry == null) {
- throw new IllegalArgumentException("Behavior cannot be null!");
- }
- if (index < 0) {
- throw new IllegalArgumentException("Index must be non-negative!");
- }
- if (name == null) {
- throw new IllegalArgumentException("Argument name cannot be null!");
- }
-
- this.behaviorEntry = behaviorEntry;
- this.index = index;
- this.name = name;
- }
-
- public ArgumentEntry(ArgumentEntry other) {
- this.behaviorEntry = other.getBehaviorEntry();
- this.index = other.index;
- this.name = other.name;
- }
-
- public ArgumentEntry(ArgumentEntry other, String newClassName) {
- this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(new ClassEntry(newClassName));
- this.index = other.index;
- this.name = other.name;
- }
-
- public ArgumentEntry(ArgumentEntry other, BehaviorEntry entry) {
- this.behaviorEntry = entry;
- this.index = other.index;
- this.name = other.name;
- }
-
- public BehaviorEntry getBehaviorEntry() {
- return this.behaviorEntry;
- }
-
- public int getIndex() {
- return this.index;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public ClassEntry getClassEntry() {
- return this.behaviorEntry.getClassEntry();
- }
-
- @Override
- public String getClassName() {
- return this.behaviorEntry.getClassName();
- }
-
- @Override
- public ArgumentEntry cloneToNewClass(ClassEntry classEntry) {
- return new ArgumentEntry(this, classEntry.getName());
- }
-
- public String getMethodName() {
- return this.behaviorEntry.getName();
- }
-
- public Signature getMethodSignature() {
- return this.behaviorEntry.getSignature();
- }
-
- @Override
- public int hashCode() {
- return Utils.combineHashesOrdered(this.behaviorEntry, Integer.valueOf(this.index).hashCode(), this.name.hashCode());
- }
-
- @Override
- public boolean equals(Object other) {
- return other instanceof ArgumentEntry && equals((ArgumentEntry) other);
- }
-
- public boolean equals(ArgumentEntry other) {
- return this.behaviorEntry.equals(other.behaviorEntry) && this.index == other.index && this.name.equals(other.name);
- }
-
- @Override
- public String toString() {
- return this.behaviorEntry + "(" + this.index + ":" + this.name + ")";
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
deleted file mode 100644
index 91ecd10..0000000
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.mapping;
-
-public class ArgumentMapping implements Comparable {
-
- private int index;
- private String name;
-
- // NOTE: this argument order is important for the MethodReader/MethodWriter
- public ArgumentMapping(int index, String name) {
- this.index = index;
- this.name = NameValidator.validateArgumentName(name);
- }
-
- public ArgumentMapping(ArgumentMapping other) {
- this.index = other.index;
- this.name = other.name;
- }
-
- public int getIndex() {
- return this.index;
- }
-
- public String getName() {
- return this.name;
- }
-
- public void setName(String val) {
- this.name = NameValidator.validateArgumentName(val);
- }
-
- public ArgumentEntry getObfEntry(BehaviorEntry behaviorEntry) {
- return new ArgumentEntry(behaviorEntry, index, name);
- }
-
- @Override
- public int compareTo(ArgumentMapping other) {
- return Integer.compare(this.index, other.index);
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java b/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java
deleted file mode 100644
index 04b4ebc..0000000
--- a/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.mapping;
-
-public interface BehaviorEntry extends Entry {
- Signature getSignature();
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassDefEntry.java b/src/main/java/cuchaz/enigma/mapping/ClassDefEntry.java
new file mode 100644
index 0000000..dc1b02e
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/ClassDefEntry.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import com.google.common.base.Preconditions;
+import cuchaz.enigma.bytecode.AccessFlags;
+
+public class ClassDefEntry extends ClassEntry {
+ private final AccessFlags access;
+
+ public ClassDefEntry(String className, AccessFlags access) {
+ super(className);
+ Preconditions.checkNotNull(access, "Class access cannot be null");
+ this.access = access;
+ }
+
+ public AccessFlags getAccess() {
+ return access;
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
index 788811f..a49f8dd 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
@@ -11,18 +11,18 @@
package cuchaz.enigma.mapping;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
public class ClassEntry implements Entry {
- private String name;
+ private final String name;
public ClassEntry(String className) {
- if (className == null) {
- throw new IllegalArgumentException("Class name cannot be null!");
- }
+ Preconditions.checkNotNull(className, "Class name cannot be null");
+
if (className.indexOf('.') >= 0) {
throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className);
}
@@ -49,12 +49,12 @@ public class ClassEntry implements Entry {
}
@Override
- public ClassEntry getClassEntry() {
+ public ClassEntry getOwnerClassEntry() {
return this;
}
@Override
- public ClassEntry cloneToNewClass(ClassEntry classEntry) {
+ public ClassEntry updateOwnership(ClassEntry classEntry) {
return classEntry;
}
@@ -132,11 +132,7 @@ public class ClassEntry implements Entry {
}
public String getPackageName() {
- int pos = this.name.lastIndexOf('/');
- if (pos > 0) {
- return this.name.substring(0, pos);
- }
- return null;
+ return getPackageName(this.name);
}
public String getSimpleName() {
@@ -147,6 +143,14 @@ public class ClassEntry implements Entry {
return this.name;
}
+ public static String getPackageName(String name) {
+ int pos = name.lastIndexOf('/');
+ if (pos > 0) {
+ return name.substring(0, pos);
+ }
+ return null;
+ }
+
public ClassEntry buildClassEntry(List classChain) {
assert (classChain.contains(this));
StringBuilder buf = new StringBuilder();
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
index 51751ca..c782250 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
@@ -34,7 +34,6 @@ public class ClassMapping implements Comparable {
private Map methodsByDeobf;
private boolean isDirty;
private Mappings.EntryModifier modifier;
- private boolean deobfInner;
public ClassMapping(String obfFullName) {
this(obfFullName, null, Mappings.EntryModifier.UNCHANGED);
@@ -81,6 +80,10 @@ public class ClassMapping implements Comparable {
return deobfName;
}
+ public String getTranslatedName(TranslationDirection direction) {
+ return direction.choose(deobfName, obfFullName);
+ }
+
//// INNER CLASSES ////////
public void setDeobfName(String val) {
@@ -191,21 +194,21 @@ public class ClassMapping implements Comparable {
return fieldsByObf.values();
}
- public boolean containsObfField(String obfName, Type obfType) {
- return fieldsByObf.containsKey(getFieldKey(obfName, obfType));
+ public boolean containsObfField(String obfName, TypeDescriptor obfDesc) {
+ return fieldsByObf.containsKey(getFieldKey(obfName, obfDesc));
}
- public boolean containsDeobfField(String deobfName, Type deobfType) {
- return fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType));
+ public boolean containsDeobfField(String deobfName, TypeDescriptor deobfDesc) {
+ return fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfDesc));
}
public void addFieldMapping(FieldMapping fieldMapping) {
- String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
+ String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc());
if (fieldsByObf.containsKey(obfKey)) {
throw new Error("Already have mapping for " + obfFullName + "." + obfKey);
}
if (fieldMapping.getDeobfName() != null) {
- String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType());
+ String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfDesc());
if (fieldsByDeobf.containsKey(deobfKey)) {
throw new Error("Already have mapping for " + deobfName + "." + deobfKey);
}
@@ -218,63 +221,67 @@ public class ClassMapping implements Comparable {
}
public void removeFieldMapping(FieldMapping fieldMapping) {
- boolean obfWasRemoved = fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType())) != null;
+ boolean obfWasRemoved = fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc())) != null;
assert (obfWasRemoved);
if (fieldMapping.getDeobfName() != null) {
- boolean deobfWasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null;
+ boolean deobfWasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfDesc())) != null;
assert (deobfWasRemoved);
}
this.isDirty = true;
}
- public FieldMapping getFieldByObf(String obfName, Type obfType) {
- return fieldsByObf.get(getFieldKey(obfName, obfType));
+ public FieldMapping getFieldByObf(String obfName, TypeDescriptor obfDesc) {
+ return fieldsByObf.get(getFieldKey(obfName, obfDesc));
+ }
+
+ public FieldMapping getFieldByObf(FieldEntry field) {
+ return getFieldByObf(field.getName(), field.getDesc());
}
- public FieldMapping getFieldByDeobf(String deobfName, Type obfType) {
- return fieldsByDeobf.get(getFieldKey(deobfName, obfType));
+ public FieldMapping getFieldByDeobf(String deobfName, TypeDescriptor obfDesc) {
+ return fieldsByDeobf.get(getFieldKey(deobfName, obfDesc));
}
- public String getObfFieldName(String deobfName, Type obfType) {
- FieldMapping fieldMapping = fieldsByDeobf.get(getFieldKey(deobfName, obfType));
+ public String getObfFieldName(String deobfName, TypeDescriptor obfDesc) {
+ FieldMapping fieldMapping = fieldsByDeobf.get(getFieldKey(deobfName, obfDesc));
if (fieldMapping != null) {
return fieldMapping.getObfName();
}
return null;
}
- public String getDeobfFieldName(String obfName, Type obfType) {
- FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfType));
+ public String getDeobfFieldName(String obfName, TypeDescriptor obfDesc) {
+ FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfDesc));
if (fieldMapping != null) {
return fieldMapping.getDeobfName();
}
return null;
}
- private String getFieldKey(String name, Type type) {
+ private String getFieldKey(String name, TypeDescriptor desc) {
if (name == null) {
throw new IllegalArgumentException("name cannot be null!");
}
- if (type == null) {
- throw new IllegalArgumentException("type cannot be null!");
+ if (desc == null) {
+ throw new IllegalArgumentException("desc cannot be null!");
}
- return name + ":" + type;
+ return name + ":" + desc;
}
- public void setFieldName(String obfName, Type obfType, String deobfName) {
+ public void setFieldName(String obfName, TypeDescriptor obfDesc, String deobfName) {
assert (deobfName != null);
- FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfType));
+ FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfDesc));
if (fieldMapping == null) {
- fieldMapping = new FieldMapping(obfName, obfType, deobfName, Mappings.EntryModifier.UNCHANGED);
- boolean obfWasAdded = fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null;
+ fieldMapping = new FieldMapping(obfName, obfDesc, deobfName, Mappings.EntryModifier.UNCHANGED);
+ boolean obfWasAdded = fieldsByObf.put(getFieldKey(obfName, obfDesc), fieldMapping) == null;
assert (obfWasAdded);
} else {
- boolean wasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfType)) != null;
+ boolean wasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfDesc)) != null;
assert (wasRemoved);
}
fieldMapping.setDeobfName(deobfName);
if (deobfName != null) {
- boolean wasAdded = fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null;
+ boolean wasAdded = fieldsByDeobf.put(getFieldKey(deobfName, obfDesc), fieldMapping) == null;
assert (wasAdded);
}
this.isDirty = true;
@@ -282,13 +289,13 @@ public class ClassMapping implements Comparable {
//// METHODS ////////
- public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) {
+ public void setFieldObfNameAndType(String oldObfName, TypeDescriptor obfDesc, String newObfName, TypeDescriptor newObfDesc) {
assert (newObfName != null);
- FieldMapping fieldMapping = fieldsByObf.remove(getFieldKey(oldObfName, obfType));
+ FieldMapping fieldMapping = fieldsByObf.remove(getFieldKey(oldObfName, obfDesc));
assert (fieldMapping != null);
fieldMapping.setObfName(newObfName);
- fieldMapping.setObfType(newObfType);
- boolean obfWasAdded = fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null;
+ fieldMapping.setObfDesc(newObfDesc);
+ boolean obfWasAdded = fieldsByObf.put(getFieldKey(newObfName, newObfDesc), fieldMapping) == null;
assert (obfWasAdded);
this.isDirty = true;
}
@@ -298,23 +305,23 @@ public class ClassMapping implements Comparable {
return methodsByObf.values();
}
- public boolean containsObfMethod(String obfName, Signature obfSignature) {
- return methodsByObf.containsKey(getMethodKey(obfName, obfSignature));
+ public boolean containsObfMethod(String obfName, MethodDescriptor obfDescriptor) {
+ return methodsByObf.containsKey(getMethodKey(obfName, obfDescriptor));
}
- public boolean containsDeobfMethod(String deobfName, Signature obfSignature) {
- return methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature));
+ public boolean containsDeobfMethod(String deobfName, MethodDescriptor obfDescriptor) {
+ return methodsByDeobf.containsKey(getMethodKey(deobfName, obfDescriptor));
}
public void addMethodMapping(MethodMapping methodMapping) {
- String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
+ String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc());
if (methodsByObf.containsKey(obfKey)) {
throw new Error("Already have mapping for " + obfFullName + "." + obfKey);
}
boolean wasAdded = methodsByObf.put(obfKey, methodMapping) == null;
assert (wasAdded);
if (methodMapping.getDeobfName() != null) {
- String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature());
+ String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc());
if (methodsByDeobf.containsKey(deobfKey)) {
throw new Error("Already have mapping for " + deobfName + "." + deobfKey);
}
@@ -326,44 +333,48 @@ public class ClassMapping implements Comparable {
}
public void removeMethodMapping(MethodMapping methodMapping) {
- boolean obfWasRemoved = methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null;
+ boolean obfWasRemoved = methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc())) != null;
assert (obfWasRemoved);
if (methodMapping.getDeobfName() != null) {
- boolean deobfWasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
+ boolean deobfWasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc())) != null;
assert (deobfWasRemoved);
}
this.isDirty = true;
}
- public MethodMapping getMethodByObf(String obfName, Signature obfSignature) {
- return methodsByObf.get(getMethodKey(obfName, obfSignature));
+ public MethodMapping getMethodByObf(String obfName, MethodDescriptor obfDescriptor) {
+ return methodsByObf.get(getMethodKey(obfName, obfDescriptor));
+ }
+
+ public MethodMapping getMethodByObf(MethodEntry method) {
+ return getMethodByObf(method.getName(), method.getDesc());
}
- public MethodMapping getMethodByDeobf(String deobfName, Signature obfSignature) {
- return methodsByDeobf.get(getMethodKey(deobfName, obfSignature));
+ public MethodMapping getMethodByDeobf(String deobfName, MethodDescriptor obfDescriptor) {
+ return methodsByDeobf.get(getMethodKey(deobfName, obfDescriptor));
}
- private String getMethodKey(String name, Signature signature) {
+ private String getMethodKey(String name, MethodDescriptor descriptor) {
if (name == null) {
throw new IllegalArgumentException("name cannot be null!");
}
- if (signature == null) {
- throw new IllegalArgumentException("signature cannot be null!");
+ if (descriptor == null) {
+ throw new IllegalArgumentException("descriptor cannot be null!");
}
- return name + signature;
+ return name + descriptor;
}
- public void setMethodName(String obfName, Signature obfSignature, String deobfName) {
- MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfName, obfSignature));
+ public void setMethodName(String obfName, MethodDescriptor obfDescriptor, String deobfName) {
+ MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfName, obfDescriptor));
if (methodMapping == null) {
- methodMapping = createMethodMapping(obfName, obfSignature);
+ methodMapping = createMethodMapping(obfName, obfDescriptor);
} else if (methodMapping.getDeobfName() != null) {
- boolean wasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
+ boolean wasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc())) != null;
assert (wasRemoved);
}
methodMapping.setDeobfName(deobfName);
if (deobfName != null) {
- boolean wasAdded = methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null;
+ boolean wasAdded = methodsByDeobf.put(getMethodKey(deobfName, obfDescriptor), methodMapping) == null;
assert (wasAdded);
}
this.isDirty = true;
@@ -371,35 +382,35 @@ public class ClassMapping implements Comparable {
//// ARGUMENTS ////////
- public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) {
+ public void setMethodObfNameAndSignature(String oldObfName, MethodDescriptor obfDescriptor, String newObfName, MethodDescriptor newObfDescriptor) {
assert (newObfName != null);
- MethodMapping methodMapping = methodsByObf.remove(getMethodKey(oldObfName, obfSignature));
+ MethodMapping methodMapping = methodsByObf.remove(getMethodKey(oldObfName, obfDescriptor));
assert (methodMapping != null);
methodMapping.setObfName(newObfName);
- methodMapping.setObfSignature(newObfSignature);
- boolean obfWasAdded = methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null;
+ methodMapping.setObfDescriptor(newObfDescriptor);
+ boolean obfWasAdded = methodsByObf.put(getMethodKey(newObfName, newObfDescriptor), methodMapping) == null;
assert (obfWasAdded);
this.isDirty = true;
}
- public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) {
+ public void setArgumentName(String obfMethodName, MethodDescriptor obfMethodDescriptor, int argumentIndex, String argumentName) {
assert (argumentName != null);
- MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature));
+ MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodName, obfMethodDescriptor));
if (methodMapping == null) {
- methodMapping = createMethodMapping(obfMethodName, obfMethodSignature);
+ methodMapping = createMethodMapping(obfMethodName, obfMethodDescriptor);
}
- methodMapping.setArgumentName(argumentIndex, argumentName);
+ methodMapping.setLocalVariableName(argumentIndex, argumentName);
this.isDirty = true;
}
- public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) {
- methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex);
+ public void removeArgumentName(String obfMethodName, MethodDescriptor obfMethodDescriptor, int argumentIndex) {
+ methodsByObf.get(getMethodKey(obfMethodName, obfMethodDescriptor)).removeLocalVariableName(argumentIndex);
this.isDirty = true;
}
- private MethodMapping createMethodMapping(String obfName, Signature obfSignature) {
- MethodMapping methodMapping = new MethodMapping(obfName, obfSignature);
- boolean wasAdded = methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null;
+ private MethodMapping createMethodMapping(String obfName, MethodDescriptor obfDescriptor) {
+ MethodMapping methodMapping = new MethodMapping(obfName, obfDescriptor);
+ boolean wasAdded = methodsByObf.put(getMethodKey(obfName, obfDescriptor), methodMapping) == null;
assert (wasAdded);
this.isDirty = true;
return methodMapping;
@@ -459,24 +470,24 @@ public class ClassMapping implements Comparable {
// rename field types
for (FieldMapping fieldMapping : new ArrayList<>(fieldsByObf.values())) {
- String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
+ String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc());
if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) {
boolean wasRemoved = fieldsByObf.remove(oldFieldKey) != null;
assert (wasRemoved);
boolean wasAdded = fieldsByObf
- .put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null;
+ .put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc()), fieldMapping) == null;
assert (wasAdded);
}
}
// rename method signatures
for (MethodMapping methodMapping : new ArrayList<>(methodsByObf.values())) {
- String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
+ String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc());
if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) {
boolean wasRemoved = methodsByObf.remove(oldMethodKey) != null;
assert (wasRemoved);
boolean wasAdded = methodsByObf
- .put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null;
+ .put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc()), methodMapping) == null;
assert (wasAdded);
}
}
@@ -490,9 +501,9 @@ public class ClassMapping implements Comparable {
return false;
}
- public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
- MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature()));
- return methodMapping != null && methodMapping.containsArgument(name);
+ public boolean containsArgument(MethodEntry obfMethodEntry, String name) {
+ MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodEntry.getName(), obfMethodEntry.getDesc()));
+ return methodMapping != null && methodMapping.containsLocalVariable(name);
}
public ClassEntry getObfEntry() {
@@ -521,9 +532,9 @@ public class ClassMapping implements Comparable {
this.modifier = modifier;
}
- public void setFieldModifier(String obfName, Type obfType, Mappings.EntryModifier modifier) {
- FieldMapping fieldMapping = fieldsByObf.computeIfAbsent(getFieldKey(obfName, obfType),
- k -> new FieldMapping(obfName, obfType, null, Mappings.EntryModifier.UNCHANGED));
+ public void setFieldModifier(String obfName, TypeDescriptor obfDesc, Mappings.EntryModifier modifier) {
+ FieldMapping fieldMapping = fieldsByObf.computeIfAbsent(getFieldKey(obfName, obfDesc),
+ k -> new FieldMapping(obfName, obfDesc, null, Mappings.EntryModifier.UNCHANGED));
if (fieldMapping.getModifier() != modifier) {
fieldMapping.setModifier(modifier);
@@ -531,7 +542,7 @@ public class ClassMapping implements Comparable {
}
}
- public void setMethodModifier(String obfName, Signature sig, Mappings.EntryModifier modifier) {
+ public void setMethodModifier(String obfName, MethodDescriptor sig, Mappings.EntryModifier modifier) {
MethodMapping methodMapping = methodsByObf.computeIfAbsent(getMethodKey(obfName, sig),
k -> new MethodMapping(obfName, sig, null, Mappings.EntryModifier.UNCHANGED));
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java b/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java
deleted file mode 100644
index 801c410..0000000
--- a/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.mapping;
-
-public interface ClassNameReplacer {
- String replace(String className);
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java b/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java
deleted file mode 100644
index 20e5113..0000000
--- a/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.mapping;
-
-import cuchaz.enigma.utils.Utils;
-
-public class ConstructorEntry implements BehaviorEntry {
-
- private ClassEntry classEntry;
- private Signature signature;
-
- public ConstructorEntry(ClassEntry classEntry) {
- this(classEntry, null);
- }
-
- public ConstructorEntry(ClassEntry classEntry, Signature signature) {
- if (classEntry == null) {
- throw new IllegalArgumentException("Class cannot be null!");
- }
-
- this.classEntry = classEntry;
- this.signature = signature;
- }
-
- public ConstructorEntry(ConstructorEntry other, String newClassName) {
- this.classEntry = new ClassEntry(newClassName);
- this.signature = other.signature;
- }
-
- @Override
- public ClassEntry getClassEntry() {
- return this.classEntry;
- }
-
- @Override
- public String getName() {
- if (isStatic()) {
- return "";
- }
- return "";
- }
-
- public boolean isStatic() {
- return this.signature == null;
- }
-
- @Override
- public Signature getSignature() {
- return this.signature;
- }
-
- @Override
- public String getClassName() {
- return this.classEntry.getName();
- }
-
- @Override
- public ConstructorEntry cloneToNewClass(ClassEntry classEntry) {
- return new ConstructorEntry(this, classEntry.getName());
- }
-
- @Override
- public int hashCode() {
- if (isStatic()) {
- return Utils.combineHashesOrdered(this.classEntry);
- } else {
- return Utils.combineHashesOrdered(this.classEntry, this.signature);
- }
- }
-
- @Override
- public boolean equals(Object other) {
- return other instanceof ConstructorEntry && equals((ConstructorEntry) other);
- }
-
- public boolean equals(ConstructorEntry other) {
- if (isStatic() != other.isStatic()) {
- return false;
- }
-
- if (isStatic()) {
- return this.classEntry.equals(other.classEntry);
- } else {
- return this.classEntry.equals(other.classEntry) && this.signature.equals(other.signature);
- }
- }
-
- @Override
- public String toString() {
- if (isStatic()) {
- return this.classEntry.getName() + "." + getName();
- } else {
- return this.classEntry.getName() + "." + getName() + this.signature;
- }
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
new file mode 100644
index 0000000..1283267
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import cuchaz.enigma.analysis.TranslationIndex;
+import cuchaz.enigma.bytecode.AccessFlags;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class DirectionalTranslator implements Translator {
+
+ private final TranslationDirection direction;
+ private final Map classes;
+ private final TranslationIndex index;
+
+ public DirectionalTranslator(ReferencedEntryPool entryPool) {
+ this.direction = null;
+ this.classes = Maps.newHashMap();
+ this.index = new TranslationIndex(entryPool);
+ }
+
+ public DirectionalTranslator(TranslationDirection direction, Map classes, TranslationIndex index) {
+ this.direction = direction;
+ this.classes = classes;
+ this.index = index;
+ }
+
+ public TranslationDirection getDirection() {
+ return direction;
+ }
+
+ public TranslationIndex getTranslationIndex() {
+ return index;
+ }
+
+ @Override
+ public ClassEntry getTranslatedClass(ClassEntry entry) {
+ String className = entry.isInnerClass() ? translateInnerClassName(entry) : translateClassName(entry);
+ return new ClassEntry(className);
+ }
+
+ @Override
+ public ClassDefEntry getTranslatedClassDef(ClassDefEntry entry) {
+ String className = entry.isInnerClass() ? translateInnerClassName(entry) : translateClassName(entry);
+ return new ClassDefEntry(className, getClassModifier(entry).transform(entry.getAccess()));
+ }
+
+ private String translateClassName(ClassEntry entry) {
+ // normal classes are easy
+ ClassMapping classMapping = this.classes.get(entry.getName());
+ if (classMapping == null) {
+ return entry.getName();
+ }
+ return classMapping.getTranslatedName(direction);
+ }
+
+ private String translateInnerClassName(ClassEntry entry) {
+ // translate as much of the class chain as we can
+ List mappingsChain = getClassMappingChain(entry);
+ String[] obfClassNames = entry.getName().split("\\$");
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < obfClassNames.length; i++) {
+ boolean isFirstClass = buf.length() == 0;
+ String className = null;
+ ClassMapping classMapping = mappingsChain.get(i);
+ if (classMapping != null) {
+ className = this.direction.choose(
+ classMapping.getDeobfName(),
+ isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName()
+ );
+ }
+ if (className == null) {
+ className = obfClassNames[i];
+ }
+ if (!isFirstClass) {
+ buf.append("$");
+ }
+ buf.append(className);
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public FieldDefEntry getTranslatedFieldDef(FieldDefEntry entry) {
+ String translatedName = translateFieldName(entry);
+ if (translatedName == null) {
+ return entry;
+ }
+ ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry());
+ TypeDescriptor translatedDesc = getTranslatedTypeDesc(entry.getDesc());
+ AccessFlags translatedAccess = getFieldModifier(entry).transform(entry.getAccess());
+ return new FieldDefEntry(translatedOwner, translatedName, translatedDesc, translatedAccess);
+ }
+
+ @Override
+ public FieldEntry getTranslatedField(FieldEntry entry) {
+ String translatedName = translateFieldName(entry);
+ if (translatedName == null) {
+ return null;
+ }
+ ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry());
+ TypeDescriptor translatedDesc = getTranslatedTypeDesc(entry.getDesc());
+ return new FieldEntry(translatedOwner, translatedName, translatedDesc);
+ }
+
+ private String translateFieldName(FieldEntry entry) {
+ // resolve the class entry
+ ClassEntry resolvedClassEntry = this.index.resolveEntryOwner(entry);
+ if (resolvedClassEntry != null) {
+ // look for the class
+ ClassMapping classMapping = findClassMapping(resolvedClassEntry);
+ if (classMapping != null) {
+ // look for the field
+ FieldMapping mapping = classMapping.getFieldByObf(entry.getName(), entry.getDesc());
+ if (mapping != null) {
+ return this.direction.choose(mapping.getDeobfName(), mapping.getObfName());
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public MethodDefEntry getTranslatedMethodDef(MethodDefEntry entry) {
+ String translatedName = translateMethodName(entry);
+ if (translatedName == null) {
+ return entry;
+ }
+ ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry());
+ MethodDescriptor translatedDesc = getTranslatedMethodDesc(entry.getDesc());
+ AccessFlags access = getMethodModifier(entry).transform(entry.getAccess());
+ return new MethodDefEntry(translatedOwner, translatedName, translatedDesc, access);
+ }
+
+ @Override
+ public MethodEntry getTranslatedMethod(MethodEntry entry) {
+ String translatedName = translateMethodName(entry);
+ if (translatedName == null) {
+ return null;
+ }
+ ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry());
+ MethodDescriptor translatedDesc = getTranslatedMethodDesc(entry.getDesc());
+ return new MethodEntry(translatedOwner, translatedName, translatedDesc);
+ }
+
+ private String translateMethodName(MethodEntry entry) {
+ // resolve the class entry
+ ClassEntry resolvedOwner = this.index.resolveEntryOwner(entry, true);
+ if (resolvedOwner != null) {
+ // look for class
+ ClassMapping classMapping = findClassMapping(resolvedOwner);
+ if (classMapping != null) {
+ // look for the method
+ MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getDesc());
+ if (mapping != null) {
+ return this.direction.choose(mapping.getDeobfName(), mapping.getObfName());
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public LocalVariableEntry getTranslatedVariable(LocalVariableEntry entry) {
+ String translatedArgumentName = translateLocalVariableName(entry);
+ if (translatedArgumentName == null) {
+ translatedArgumentName = inheritLocalVariableName(entry);
+ }
+ if (translatedArgumentName == null) {
+ return null;
+ }
+ // TODO: Translating arguments calls method translation.. Can we refactor the code in such a way that we don't need this?
+ MethodEntry translatedOwner = getTranslatedMethod(entry.getOwnerEntry());
+ return new LocalVariableEntry(translatedOwner, entry.getIndex(), translatedArgumentName);
+ }
+
+ @Override
+ public LocalVariableDefEntry getTranslatedVariableDef(LocalVariableDefEntry entry) {
+ String translatedArgumentName = translateLocalVariableName(entry);
+ if (translatedArgumentName == null) {
+ translatedArgumentName = inheritLocalVariableName(entry);
+ }
+ if (translatedArgumentName == null) {
+ return entry;
+ }
+ // TODO: Translating arguments calls method translation.. Can we refactor the code in such a way that we don't need this?
+ MethodDefEntry translatedOwner = getTranslatedMethodDef(entry.getOwnerEntry());
+ TypeDescriptor translatedTypeDesc = getTranslatedTypeDesc(entry.getDesc());
+ return new LocalVariableDefEntry(translatedOwner, entry.getIndex(), translatedArgumentName, translatedTypeDesc);
+ }
+
+ // TODO: support not identical behavior (specific to constructor)
+ private String translateLocalVariableName(LocalVariableEntry entry) {
+ // look for identical behavior in superclasses
+ ClassEntry ownerEntry = entry.getOwnerClassEntry();
+ if (ownerEntry != null) {
+ // look for the class
+ ClassMapping classMapping = findClassMapping(ownerEntry);
+ if (classMapping != null) {
+ // look for the method
+ MethodMapping methodMapping = classMapping.getMethodByObf(entry.getMethodName(), entry.getMethodDesc());
+ if (methodMapping != null) {
+ int index = entry.getIndex();
+ return this.direction.choose(
+ methodMapping.getDeobfLocalVariableName(index),
+ methodMapping.getObfLocalVariableName(index)
+ );
+ }
+ }
+ }
+ return null;
+ }
+
+ private String inheritLocalVariableName(LocalVariableEntry entry) {
+ List ancestry = this.index.getAncestry(entry.getOwnerClassEntry());
+ // Check in mother class for the arg
+ for (ClassEntry ancestorEntry : ancestry) {
+ LocalVariableEntry motherArg = entry.updateOwnership(ancestorEntry);
+ if (this.index.entryExists(motherArg)) {
+ String result = translateLocalVariableName(motherArg);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public TypeDescriptor getTranslatedTypeDesc(TypeDescriptor desc) {
+ return desc.remap(name -> getTranslatedClass(new ClassEntry(name)).getName());
+ }
+
+ @Override
+ public MethodDescriptor getTranslatedMethodDesc(MethodDescriptor descriptor) {
+ List arguments = descriptor.getArgumentDescs();
+ List translatedArguments = new ArrayList<>(arguments.size());
+ for (TypeDescriptor argument : arguments) {
+ translatedArguments.add(getTranslatedTypeDesc(argument));
+ }
+ return new MethodDescriptor(translatedArguments, getTranslatedTypeDesc(descriptor.getReturnDesc()));
+ }
+
+ private ClassMapping findClassMapping(ClassEntry entry) {
+ List mappingChain = getClassMappingChain(entry);
+ return mappingChain.get(mappingChain.size() - 1);
+ }
+
+ private List getClassMappingChain(ClassEntry entry) {
+
+ // get a list of all the classes in the hierarchy
+ String[] parts = entry.getName().split("\\$");
+ List mappingsChain = Lists.newArrayList();
+
+ // get mappings for the outer class
+ ClassMapping outerClassMapping = this.classes.get(parts[0]);
+ mappingsChain.add(outerClassMapping);
+
+ for (int i = 1; i < parts.length; i++) {
+
+ // get mappings for the inner class
+ ClassMapping innerClassMapping = null;
+ if (outerClassMapping != null) {
+ innerClassMapping = this.direction.choose(
+ outerClassMapping.getInnerClassByObfSimple(parts[i]),
+ outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i])
+ );
+ }
+ mappingsChain.add(innerClassMapping);
+ outerClassMapping = innerClassMapping;
+ }
+
+ assert (mappingsChain.size() == parts.length);
+ return mappingsChain;
+ }
+
+ private Mappings.EntryModifier getClassModifier(ClassEntry entry) {
+ ClassMapping classMapping = findClassMapping(entry);
+ if (classMapping != null) {
+ return classMapping.getModifier();
+ }
+ return Mappings.EntryModifier.UNCHANGED;
+ }
+
+ private Mappings.EntryModifier getFieldModifier(FieldEntry entry) {
+ ClassMapping classMapping = findClassMapping(entry.getOwnerClassEntry());
+ if (classMapping != null) {
+ FieldMapping fieldMapping = classMapping.getFieldByObf(entry);
+ if (fieldMapping != null) {
+ return fieldMapping.getModifier();
+ }
+ }
+ return Mappings.EntryModifier.UNCHANGED;
+ }
+
+ private Mappings.EntryModifier getMethodModifier(MethodEntry entry) {
+ ClassMapping classMapping = findClassMapping(entry.getOwnerClassEntry());
+ if (classMapping != null) {
+ MethodMapping methodMapping = classMapping.getMethodByObf(entry);
+ if (methodMapping != null) {
+ return methodMapping.getModifier();
+ }
+ }
+ return Mappings.EntryModifier.UNCHANGED;
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/Entry.java b/src/main/java/cuchaz/enigma/mapping/Entry.java
index c79510b..eb783e9 100644
--- a/src/main/java/cuchaz/enigma/mapping/Entry.java
+++ b/src/main/java/cuchaz/enigma/mapping/Entry.java
@@ -16,7 +16,7 @@ public interface Entry {
String getClassName();
- ClassEntry getClassEntry();
+ ClassEntry getOwnerClassEntry();
- Entry cloneToNewClass(ClassEntry classEntry);
+ Entry updateOwnership(ClassEntry classEntry);
}
diff --git a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
index 993bb64..c20f6f5 100644
--- a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
+++ b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
@@ -12,19 +12,8 @@
package cuchaz.enigma.mapping;
import cuchaz.enigma.analysis.JarIndex;
-import javassist.*;
-import javassist.bytecode.Descriptor;
-import javassist.expr.ConstructorCall;
-import javassist.expr.FieldAccess;
-import javassist.expr.MethodCall;
-import javassist.expr.NewExpr;
public class EntryFactory {
-
- public static ClassEntry getClassEntry(CtClass c) {
- return new ClassEntry(Descriptor.toJvmName(c.getName()));
- }
-
public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) {
ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfFullName());
return obfClassEntry.buildClassEntry(jarIndex.getObfClassChain(obfClassEntry));
@@ -38,95 +27,19 @@ public class EntryFactory {
return new ClassEntry(classMapping.getDeobfName());
}
- public static ClassEntry getSuperclassEntry(CtClass c) {
- return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass()));
- }
-
- public static FieldEntry getFieldEntry(CtField field) {
- return new FieldEntry(getClassEntry(field.getDeclaringClass()), field.getName(), new Type(field.getFieldInfo().getDescriptor()));
- }
-
- public static FieldEntry getFieldEntry(FieldAccess call) {
- return new FieldEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getFieldName(), new Type(call.getSignature()));
- }
-
- public static FieldEntry getFieldEntry(String className, String name, String type) {
- return new FieldEntry(new ClassEntry(className), name, new Type(type));
- }
-
public static FieldEntry getObfFieldEntry(ClassMapping classMapping, FieldMapping fieldMapping) {
- return new FieldEntry(getObfClassEntry(classMapping), fieldMapping.getObfName(), fieldMapping.getObfType());
- }
-
- public static MethodEntry getMethodEntry(CtMethod method) {
- return new MethodEntry(getClassEntry(method.getDeclaringClass()), method.getName(), new Signature(method.getMethodInfo().getDescriptor()));
- }
-
- public static MethodEntry getMethodEntry(MethodCall call) {
- return new MethodEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getMethodName(), new Signature(call.getSignature()));
- }
-
- public static ConstructorEntry getConstructorEntry(CtConstructor constructor) {
- if (constructor.isClassInitializer()) {
- return new ConstructorEntry(getClassEntry(constructor.getDeclaringClass()));
- } else {
- return new ConstructorEntry(getClassEntry(constructor.getDeclaringClass()), new Signature(constructor.getMethodInfo().getDescriptor()));
- }
- }
-
- public static ConstructorEntry getConstructorEntry(ConstructorCall call) {
- return new ConstructorEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), new Signature(call.getSignature()));
- }
-
- public static ConstructorEntry getConstructorEntry(NewExpr call) {
- return new ConstructorEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), new Signature(call.getSignature()));
- }
-
- public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) {
- if (behavior instanceof CtMethod) {
- return getMethodEntry((CtMethod) behavior);
- } else if (behavior instanceof CtConstructor) {
- return getConstructorEntry((CtConstructor) behavior);
- }
- throw new Error("behavior is neither Method nor Constructor!");
- }
-
- public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) {
- return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature));
- }
-
- public static BehaviorEntry getBehaviorEntry(String className, String behaviorName) {
- return getBehaviorEntry(new ClassEntry(className), behaviorName);
- }
-
- public static BehaviorEntry getBehaviorEntry(String className) {
- return new ConstructorEntry(new ClassEntry(className));
- }
-
- public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) {
- switch (behaviorName) {
- case "":
- return new ConstructorEntry(classEntry, behaviorSignature);
- case "":
- return new ConstructorEntry(classEntry);
- default:
- return new MethodEntry(classEntry, behaviorName, behaviorSignature);
- }
+ return new FieldEntry(getObfClassEntry(classMapping), fieldMapping.getObfName(), fieldMapping.getObfDesc());
}
- public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName) {
- if (behaviorName.equals("")) {
- return new ConstructorEntry(classEntry);
- } else {
- throw new IllegalArgumentException("Only class initializers don't have signatures");
- }
+ public static MethodEntry getMethodEntry(ClassEntry classEntry, String name, MethodDescriptor desc) {
+ return new MethodEntry(classEntry, name, desc);
}
- public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) {
- return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
+ public static MethodEntry getObfMethodEntry(ClassEntry classEntry, MethodMapping methodMapping) {
+ return getMethodEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfDesc());
}
- public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) {
- return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping);
+ public static MethodEntry getObfMethodEntry(ClassMapping classMapping, MethodMapping methodMapping) {
+ return getObfMethodEntry(getObfClassEntry(classMapping), methodMapping);
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldDefEntry.java b/src/main/java/cuchaz/enigma/mapping/FieldDefEntry.java
new file mode 100644
index 0000000..262c16c
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/FieldDefEntry.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import com.google.common.base.Preconditions;
+import cuchaz.enigma.bytecode.AccessFlags;
+
+public class FieldDefEntry extends FieldEntry {
+ private final AccessFlags access;
+
+ public FieldDefEntry(ClassEntry ownerEntry, String name, TypeDescriptor desc, AccessFlags access) {
+ super(ownerEntry, name, desc);
+ Preconditions.checkNotNull(access, "Field access cannot be null");
+ this.access = access;
+ }
+
+ public AccessFlags getAccess() {
+ return access;
+ }
+
+ @Override
+ public FieldDefEntry updateOwnership(ClassEntry owner) {
+ return new FieldDefEntry(owner, this.name, this.desc, access);
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
index 0f1f506..c118ac0 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
@@ -11,40 +11,29 @@
package cuchaz.enigma.mapping;
+import com.google.common.base.Preconditions;
import cuchaz.enigma.utils.Utils;
public class FieldEntry implements Entry {
- private ClassEntry classEntry;
- private String name;
- private Type type;
+ protected final ClassEntry ownerEntry;
+ protected final String name;
+ protected final TypeDescriptor desc;
// NOTE: this argument order is important for the MethodReader/MethodWriter
- public FieldEntry(ClassEntry classEntry, String name, Type type) {
- if (classEntry == null) {
- throw new IllegalArgumentException("Class cannot be null!");
- }
- if (name == null) {
- throw new IllegalArgumentException("Field name cannot be null!");
- }
- if (type == null) {
- throw new IllegalArgumentException("Field type cannot be null!");
- }
+ public FieldEntry(ClassEntry ownerEntry, String name, TypeDescriptor desc) {
+ Preconditions.checkNotNull(ownerEntry, "Owner cannot be null");
+ Preconditions.checkNotNull(name, "Field name cannot be null");
+ Preconditions.checkNotNull(desc, "Field descriptor cannot be null");
- this.classEntry = classEntry;
+ this.ownerEntry = ownerEntry;
this.name = name;
- this.type = type;
- }
-
- public FieldEntry(FieldEntry other, ClassEntry newClassEntry) {
- this.classEntry = newClassEntry;
- this.name = other.name;
- this.type = other.type;
+ this.desc = desc;
}
@Override
- public ClassEntry getClassEntry() {
- return this.classEntry;
+ public ClassEntry getOwnerClassEntry() {
+ return this.ownerEntry;
}
@Override
@@ -54,21 +43,21 @@ public class FieldEntry implements Entry {
@Override
public String getClassName() {
- return this.classEntry.getName();
+ return this.ownerEntry.getName();
}
- public Type getType() {
- return this.type;
+ public TypeDescriptor getDesc() {
+ return this.desc;
}
@Override
- public FieldEntry cloneToNewClass(ClassEntry classEntry) {
- return new FieldEntry(this, classEntry);
+ public FieldEntry updateOwnership(ClassEntry owner) {
+ return new FieldEntry(owner, this.name, this.desc);
}
@Override
public int hashCode() {
- return Utils.combineHashesOrdered(this.classEntry, this.name, this.type);
+ return Utils.combineHashesOrdered(this.ownerEntry, this.name, this.desc);
}
@Override
@@ -77,11 +66,11 @@ public class FieldEntry implements Entry {
}
public boolean equals(FieldEntry other) {
- return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.type.equals(other.type);
+ return this.ownerEntry.equals(other.ownerEntry) && this.name.equals(other.name) && this.desc.equals(other.desc);
}
@Override
public String toString() {
- return this.classEntry.getName() + "." + this.name + ":" + this.type;
+ return this.ownerEntry.getName() + "." + this.name + ":" + this.desc;
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
index cd761b4..3c46a37 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
@@ -17,26 +17,19 @@ public class FieldMapping implements Comparable, MemberMapping, MemberMapping, MemberMapping
- {
+ // rename obf classes in the desc
+ TypeDescriptor newDesc = this.obfDesc.remap(className -> {
if (className.equals(oldObfClassName)) {
return newObfClassName;
}
- return null;
+ return className;
});
- if (!newType.equals(this.obfType)) {
- this.obfType = newType;
+ if (!newDesc.equals(this.obfDesc)) {
+ this.obfDesc = newDesc;
return true;
}
return false;
diff --git a/src/main/java/cuchaz/enigma/mapping/LocalVariableDefEntry.java b/src/main/java/cuchaz/enigma/mapping/LocalVariableDefEntry.java
new file mode 100644
index 0000000..cc677c5
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/LocalVariableDefEntry.java
@@ -0,0 +1,75 @@
+package cuchaz.enigma.mapping;
+
+import com.google.common.base.Preconditions;
+import cuchaz.enigma.utils.Utils;
+
+/**
+ * TypeDescriptor...
+ * Created by Thog
+ * 19/10/2016
+ */
+public class LocalVariableDefEntry extends LocalVariableEntry {
+
+ protected final MethodDefEntry ownerEntry;
+ protected final TypeDescriptor desc;
+
+ public LocalVariableDefEntry(MethodDefEntry ownerEntry, int index, String name, TypeDescriptor desc) {
+ super(ownerEntry, index, name);
+ Preconditions.checkNotNull(desc, "Variable desc cannot be null");
+
+ this.ownerEntry = ownerEntry;
+ this.desc = desc;
+ }
+
+ public LocalVariableDefEntry(MethodDefEntry ownerEntry, int index, String name) {
+ super(ownerEntry, index, name);
+
+ this.ownerEntry = ownerEntry;
+
+ int namedIndex = getNamedIndex();
+ if (namedIndex < 0) {
+ this.desc = TypeDescriptor.of(ownerEntry.getOwnerClassEntry().getName());
+ } else {
+ this.desc = ownerEntry.getDesc().getArgumentDescs().get(namedIndex);
+ }
+ }
+
+ @Override
+ public MethodDefEntry getOwnerEntry() {
+ return this.ownerEntry;
+ }
+
+ public TypeDescriptor getDesc() {
+ return desc;
+ }
+
+ public int getNamedIndex() {
+ // If we're not static, "this" is bound to index 0
+ int indexOffset = ownerEntry.getAccess().isStatic() ? 0 : 1;
+ return index - indexOffset;
+ }
+
+ @Override
+ public LocalVariableDefEntry updateOwnership(ClassEntry classEntry) {
+ return new LocalVariableDefEntry(ownerEntry.updateOwnership(classEntry), index, name, desc);
+ }
+
+ @Override
+ public int hashCode() {
+ return Utils.combineHashesOrdered(this.ownerEntry, this.desc.hashCode(), this.name.hashCode(), Integer.hashCode(this.index));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof LocalVariableDefEntry && equals((LocalVariableDefEntry) other);
+ }
+
+ public boolean equals(LocalVariableDefEntry other) {
+ return this.ownerEntry.equals(other.ownerEntry) && this.desc.equals(other.desc) && this.name.equals(other.name) && this.index == other.index;
+ }
+
+ @Override
+ public String toString() {
+ return this.ownerEntry + "(" + this.index + ":" + this.name + ":" + this.desc + ")";
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
index 2bb5e3f..dcfd0ff 100644
--- a/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
@@ -1,52 +1,31 @@
package cuchaz.enigma.mapping;
+import com.google.common.base.Preconditions;
import cuchaz.enigma.utils.Utils;
/**
- * Desc...
+ * TypeDescriptor...
* Created by Thog
* 19/10/2016
*/
public class LocalVariableEntry implements Entry {
- protected final BehaviorEntry behaviorEntry;
+ protected final MethodEntry ownerEntry;
protected final String name;
- protected final Type type;
protected final int index;
- public LocalVariableEntry(BehaviorEntry behaviorEntry, int index, String name, Type type) {
- if (behaviorEntry == null) {
- throw new IllegalArgumentException("Behavior cannot be null!");
- }
- if (index < 0) {
- throw new IllegalArgumentException("Index must be non-negative!");
- }
- if (name == null) {
- throw new IllegalArgumentException("Variable name cannot be null!");
- }
- if (type == null) {
- throw new IllegalArgumentException("Variable type cannot be null!");
- }
-
- this.behaviorEntry = behaviorEntry;
+ public LocalVariableEntry(MethodEntry ownerEntry, int index, String name) {
+ Preconditions.checkNotNull(ownerEntry, "Variable owner cannot be null");
+ Preconditions.checkNotNull(name, "Variable name cannot be null");
+ Preconditions.checkArgument(index >= 0, "Index must be positive");
+
+ this.ownerEntry = ownerEntry;
this.name = name;
- this.type = type;
this.index = index;
}
- public LocalVariableEntry(LocalVariableEntry other, ClassEntry newClassEntry) {
- this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(newClassEntry);
- this.name = other.name;
- this.type = other.type;
- this.index = other.index;
- }
-
- public BehaviorEntry getBehaviorEntry() {
- return this.behaviorEntry;
- }
-
- public Type getType() {
- return type;
+ public MethodEntry getOwnerEntry() {
+ return this.ownerEntry;
}
public int getIndex() {
@@ -59,31 +38,31 @@ public class LocalVariableEntry implements Entry {
}
@Override
- public ClassEntry getClassEntry() {
- return this.behaviorEntry.getClassEntry();
+ public ClassEntry getOwnerClassEntry() {
+ return this.ownerEntry.getOwnerClassEntry();
}
@Override
public String getClassName() {
- return this.behaviorEntry.getClassName();
+ return this.ownerEntry.getClassName();
}
@Override
- public LocalVariableEntry cloneToNewClass(ClassEntry classEntry) {
- return new LocalVariableEntry(this, classEntry);
+ public LocalVariableEntry updateOwnership(ClassEntry classEntry) {
+ return new LocalVariableEntry(ownerEntry.updateOwnership(classEntry), index, name);
}
public String getMethodName() {
- return this.behaviorEntry.getName();
+ return this.ownerEntry.getName();
}
- public Signature getMethodSignature() {
- return this.behaviorEntry.getSignature();
+ public MethodDescriptor getMethodDesc() {
+ return this.ownerEntry.getDesc();
}
@Override
public int hashCode() {
- return Utils.combineHashesOrdered(this.behaviorEntry, this.type.hashCode(), this.name.hashCode(), Integer.hashCode(this.index));
+ return Utils.combineHashesOrdered(this.ownerEntry, this.name.hashCode(), Integer.hashCode(this.index));
}
@Override
@@ -92,11 +71,11 @@ public class LocalVariableEntry implements Entry {
}
public boolean equals(LocalVariableEntry other) {
- return this.behaviorEntry.equals(other.behaviorEntry) && this.type.equals(other.type) && this.name.equals(other.name) && this.index == other.index;
+ return this.ownerEntry.equals(other.ownerEntry) && this.name.equals(other.name) && this.index == other.index;
}
@Override
public String toString() {
- return this.behaviorEntry + "(" + this.index + ":" + this.name + ":" + this.type + ")";
+ return this.ownerEntry + "(" + this.index + ":" + this.name + ")";
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/LocalVariableMapping.java b/src/main/java/cuchaz/enigma/mapping/LocalVariableMapping.java
new file mode 100644
index 0000000..193c566
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/LocalVariableMapping.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+public class LocalVariableMapping implements Comparable {
+
+ private int index;
+ private String name;
+
+ // NOTE: this argument order is important for the MethodReader/MethodWriter
+ public LocalVariableMapping(int index, String name) {
+ this.index = index;
+ this.name = NameValidator.validateArgumentName(name);
+ }
+
+ public LocalVariableMapping(LocalVariableMapping other) {
+ this.index = other.index;
+ this.name = other.name;
+ }
+
+ public int getIndex() {
+ return this.index;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String val) {
+ this.name = NameValidator.validateArgumentName(val);
+ }
+
+ public LocalVariableEntry getObfEntry(MethodEntry methodEntry) {
+ return new LocalVariableEntry(methodEntry, index, name);
+ }
+
+ @Override
+ public int compareTo(LocalVariableMapping other) {
+ return Integer.compare(this.index, other.index);
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
index cf78ca3..cc1ec9c 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -15,6 +15,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import cuchaz.enigma.analysis.TranslationIndex;
+import cuchaz.enigma.bytecode.AccessFlags;
import cuchaz.enigma.throwables.MappingConflict;
import java.io.File;
@@ -96,11 +97,11 @@ public class Mappings {
public Translator getTranslator(TranslationDirection direction, TranslationIndex index) {
switch (direction) {
- case Deobfuscating:
+ case DEOBFUSCATING:
- return new Translator(direction, this.classesByObf, index);
+ return new DirectionalTranslator(direction, this.classesByObf, index);
- case Obfuscating:
+ case OBFUSCATING:
// fill in the missing deobf class entries with obf entries
Map classes = Maps.newHashMap();
@@ -114,9 +115,9 @@ public class Mappings {
// translate the translation index
// NOTE: this isn't actually recursive
- TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index));
+ TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.DEOBFUSCATING, index));
- return new Translator(direction, classes, deobfIndex);
+ return new DirectionalTranslator(direction, classes, deobfIndex);
default:
throw new Error("Invalid translation direction!");
@@ -151,9 +152,9 @@ public class Mappings {
// add classes from method signatures
for (MethodMapping methodMapping : classMapping.methods()) {
- for (Type type : methodMapping.getObfSignature().types()) {
- if (type.hasClass()) {
- classNames.add(type.getClassEntry().getClassName());
+ for (TypeDescriptor desc : methodMapping.getObfDesc().types()) {
+ if (desc.containsType()) {
+ classNames.add(desc.getOwnerEntry().getClassName());
}
}
}
@@ -165,9 +166,9 @@ public class Mappings {
return this.classesByDeobf.containsKey(deobfName);
}
- public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, Type obfType) {
+ public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, TypeDescriptor obfDesc) {
ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName());
- return classMapping != null && classMapping.containsDeobfField(deobfName, obfType);
+ return classMapping != null && classMapping.containsDeobfField(deobfName, obfDesc);
}
public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) {
@@ -180,14 +181,14 @@ public class Mappings {
return false;
}
- public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature obfSignature) {
+ public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, MethodDescriptor obfDescriptor) {
ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName());
- return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfSignature);
+ return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfDescriptor);
}
- public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
- ClassMapping classMapping = this.classesByObf.get(obfBehaviorEntry.getClassName());
- return classMapping != null && classMapping.containsArgument(obfBehaviorEntry, name);
+ public boolean containsArgument(MethodEntry obfMethodEntry, String name) {
+ ClassMapping classMapping = this.classesByObf.get(obfMethodEntry.getClassName());
+ return classMapping != null && classMapping.containsArgument(obfMethodEntry, name);
}
public List getClassMappingChain(ClassEntry obfClass) {
@@ -239,5 +240,19 @@ public class Mappings {
public String getFormattedName() {
return " ACC:" + super.toString();
}
+
+ public AccessFlags transform(AccessFlags access) {
+ switch (this) {
+ case PUBLIC:
+ return access.setPublic();
+ case PROTECTED:
+ return access.setProtected();
+ case PRIVATE:
+ return access.setPrivate();
+ case UNCHANGED:
+ default:
+ return access;
+ }
+ }
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
index 172641b..4d5be2f 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
@@ -23,7 +23,7 @@ public class MappingsChecker {
private Map droppedClassMappings;
private Map droppedInnerClassMappings;
private Map droppedFieldMappings;
- private Map droppedMethodMappings;
+ private Map droppedMethodMappings;
public MappingsChecker(JarIndex index) {
this.index = index;
@@ -45,7 +45,7 @@ public class MappingsChecker {
return this.droppedFieldMappings;
}
- public Map getDroppedMethodMappings() {
+ public Map getDroppedMethodMappings() {
return this.droppedMethodMappings;
}
@@ -77,10 +77,10 @@ public class MappingsChecker {
// check methods
for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
- BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping);
- if (!this.index.containsObfBehavior(obfBehaviorEntry)) {
+ MethodEntry obfMethodEntry = EntryFactory.getObfMethodEntry(classEntry, methodMapping);
+ if (!this.index.containsObfMethod(obfMethodEntry)) {
classMapping.removeMethodMapping(methodMapping);
- this.droppedMethodMappings.put(obfBehaviorEntry, methodMapping);
+ this.droppedMethodMappings.put(obfMethodEntry, methodMapping);
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
index a0d4313..d1d5634 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
@@ -123,8 +123,8 @@ public class MappingsEnigmaReader {
return mappings;
}
- private ArgumentMapping readArgument(String[] parts) {
- return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]);
+ private LocalVariableMapping readArgument(String[] parts) {
+ return new LocalVariableMapping(Integer.parseInt(parts[1]), parts[2]);
}
private ClassMapping readClass(String[] parts, boolean makeSimple) {
@@ -150,27 +150,27 @@ public class MappingsEnigmaReader {
if (parts.length == 4) {
boolean access = parts[3].startsWith("ACC:");
if (access)
- mapping = new FieldMapping(parts[1], new Type(parts[2]), null,
+ mapping = new FieldMapping(parts[1], new TypeDescriptor(parts[2]), null,
Mappings.EntryModifier.valueOf(parts[3].substring(4)));
else
- mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.UNCHANGED);
+ mapping = new FieldMapping(parts[1], new TypeDescriptor(parts[3]), parts[2], Mappings.EntryModifier.UNCHANGED);
} else if (parts.length == 5)
- mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.valueOf(parts[4].substring(4)));
+ mapping = new FieldMapping(parts[1], new TypeDescriptor(parts[3]), parts[2], Mappings.EntryModifier.valueOf(parts[4].substring(4)));
return mapping;
}
private MethodMapping readMethod(String[] parts) {
MethodMapping mapping = null;
if (parts.length == 3)
- mapping = new MethodMapping(parts[1], new Signature(parts[2]));
+ mapping = new MethodMapping(parts[1], new MethodDescriptor(parts[2]));
else if (parts.length == 4) {
boolean access = parts[3].startsWith("ACC:");
if (access)
- mapping = new MethodMapping(parts[1], new Signature(parts[2]), null, Mappings.EntryModifier.valueOf(parts[3].substring(4)));
+ mapping = new MethodMapping(parts[1], new MethodDescriptor(parts[2]), null, Mappings.EntryModifier.valueOf(parts[3].substring(4)));
else
- mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2]);
+ mapping = new MethodMapping(parts[1], new MethodDescriptor(parts[3]), parts[2]);
} else if (parts.length == 5)
- mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2],
+ mapping = new MethodMapping(parts[1], new MethodDescriptor(parts[3]), parts[2],
Mappings.EntryModifier.valueOf(parts[4].substring(4)));
return mapping;
}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
index ba1b258..1929977 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
@@ -127,29 +127,29 @@ public class MappingsEnigmaWriter {
private void write(PrintWriter out, FieldMapping fieldMapping, int depth) {
if (fieldMapping.getDeobfName() == null)
- out.format("%sFIELD %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getObfType().toString(),
+ out.format("%sFIELD %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getObfDesc().toString(),
fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName());
else
- out.format("%sFIELD %s %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString(),
+ out.format("%sFIELD %s %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfDesc().toString(),
fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName());
}
private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException {
if (methodMapping.getDeobfName() == null) {
- out.format("%sMETHOD %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature(),
+ out.format("%sMETHOD %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfDesc(),
methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName());
} else {
- out.format("%sMETHOD %s %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature(),
+ out.format("%sMETHOD %s %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfDesc(),
methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName());
}
- for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) {
- write(out, argumentMapping, depth + 1);
+ for (LocalVariableMapping localVariableMapping : sorted(methodMapping.arguments())) {
+ write(out, localVariableMapping, depth + 1);
}
}
- private void write(PrintWriter out, ArgumentMapping argumentMapping, int depth) {
- out.format("%sARG %d %s\n", getIndent(depth), argumentMapping.getIndex(), argumentMapping.getName());
+ private void write(PrintWriter out, LocalVariableMapping localVariableMapping, int depth) {
+ out.format("%sARG %d %s\n", getIndent(depth), localVariableMapping.getIndex(), localVariableMapping.getName());
}
private > List sorted(Iterable classes) {
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
index 7126d2b..e215a0f 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -25,12 +25,14 @@ import java.util.zip.GZIPOutputStream;
public class MappingsRenamer {
- private JarIndex index;
+ private final JarIndex index;
+ private final ReferencedEntryPool entryPool;
private Mappings mappings;
- public MappingsRenamer(JarIndex index, Mappings mappings) {
+ public MappingsRenamer(JarIndex index, Mappings mappings, ReferencedEntryPool entryPool) {
this.index = index;
this.mappings = mappings;
+ this.entryPool = entryPool;
}
public void setMappings(Mappings mappings) {
@@ -46,7 +48,7 @@ public class MappingsRenamer {
if (deobfName != null) {
// make sure we don't rename to an existing obf or deobf class
- if (mappings.containsDeobfClass(deobfName) || index.containsObfClass(new ClassEntry(deobfName))) {
+ if (mappings.containsDeobfClass(deobfName) || index.containsObfClass(entryPool.getClass(deobfName))) {
throw new IllegalNameException(deobfName, "There is already a class with that name");
}
}
@@ -87,13 +89,13 @@ public class MappingsRenamer {
public void setFieldName(FieldEntry obf, String deobfName) {
deobfName = NameValidator.validateFieldName(deobfName);
- FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName, obf.getType());
+ FieldEntry targetEntry = entryPool.getField(obf.getOwnerClassEntry(), deobfName, obf.getDesc());
ClassEntry definedClass = null;
- if (mappings.containsDeobfField(obf.getClassEntry(), deobfName) || index.containsEntryWithSameName(targetEntry))
- definedClass = obf.getClassEntry();
+ if (mappings.containsDeobfField(obf.getOwnerClassEntry(), deobfName) || index.containsEntryWithSameName(targetEntry))
+ definedClass = obf.getOwnerClassEntry();
else {
- for (ClassEntry ancestorEntry : this.index.getTranslationIndex().getAncestry(obf.getClassEntry())) {
- if (mappings.containsDeobfField(ancestorEntry, deobfName) || index.containsEntryWithSameName(targetEntry.cloneToNewClass(ancestorEntry))) {
+ for (ClassEntry ancestorEntry : this.index.getTranslationIndex().getAncestry(obf.getOwnerClassEntry())) {
+ if (mappings.containsDeobfField(ancestorEntry, deobfName) || index.containsEntryWithSameName(targetEntry.updateOwnership(ancestorEntry))) {
definedClass = ancestorEntry;
break;
}
@@ -101,42 +103,44 @@ public class MappingsRenamer {
}
if (definedClass != null) {
- String className = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(definedClass.getClassName());
+ Translator translator = mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index.getTranslationIndex());
+ String className = translator.getTranslatedClass(entryPool.getClass(definedClass.getClassName())).getName();
if (className == null)
className = definedClass.getClassName();
throw new IllegalNameException(deobfName, "There is already a field with that name in " + className);
}
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.setFieldName(obf.getName(), obf.getType(), deobfName);
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.setFieldName(obf.getName(), obf.getDesc(), deobfName);
}
public void removeFieldMapping(FieldEntry obf) {
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getType()));
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getDesc()));
}
public void markFieldAsDeobfuscated(FieldEntry obf) {
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.setFieldName(obf.getName(), obf.getType(), obf.getName());
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.setFieldName(obf.getName(), obf.getDesc(), obf.getName());
}
private void validateMethodTreeName(MethodEntry entry, String deobfName) {
- MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, entry.getSignature());
+ MethodEntry targetEntry = entryPool.getMethod(entry.getOwnerClassEntry(), deobfName, entry.getDesc());
// TODO: Verify if I don't break things
- ClassMapping classMapping = mappings.getClassByObf(entry.getClassEntry());
- if ((classMapping != null && classMapping.containsDeobfMethod(deobfName, entry.getSignature()) && classMapping.getMethodByObf(entry.getName(), entry.getSignature()) != classMapping.getMethodByDeobf(deobfName, entry.getSignature()))
- || index.containsObfBehavior(targetEntry)) {
- String deobfClassName = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(entry.getClassName());
+ ClassMapping classMapping = mappings.getClassByObf(entry.getOwnerClassEntry());
+ if ((classMapping != null && classMapping.containsDeobfMethod(deobfName, entry.getDesc()) && classMapping.getMethodByObf(entry.getName(), entry.getDesc()) != classMapping.getMethodByDeobf(deobfName, entry.getDesc()))
+ || index.containsObfMethod(targetEntry)) {
+ Translator translator = mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index.getTranslationIndex());
+ String deobfClassName = translator.getTranslatedClass(entryPool.getClass(entry.getClassName())).getClassName();
if (deobfClassName == null) {
deobfClassName = entry.getClassName();
}
throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
}
- for (ClassEntry child : index.getTranslationIndex().getSubclass(entry.getClassEntry())) {
- validateMethodTreeName(entry.cloneToNewClass(child), deobfName);
+ for (ClassEntry child : index.getTranslationIndex().getSubclass(entry.getOwnerClassEntry())) {
+ validateMethodTreeName(entry.updateOwnership(child), deobfName);
}
}
@@ -155,20 +159,21 @@ public class MappingsRenamer {
public void setMethodName(MethodEntry obf, String deobfName) {
deobfName = NameValidator.validateMethodName(deobfName);
- MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature());
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
+ MethodEntry targetEntry = entryPool.getMethod(obf.getOwnerClassEntry(), deobfName, obf.getDesc());
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
// TODO: Verify if I don't break things
- if ((mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) && classMapping.getMethodByObf(obf.getName(), obf.getSignature()) != classMapping.getMethodByDeobf(deobfName, obf.getSignature()))
- || index.containsObfBehavior(targetEntry)) {
- String deobfClassName = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(obf.getClassName());
+ if ((mappings.containsDeobfMethod(obf.getOwnerClassEntry(), deobfName, obf.getDesc()) && classMapping.getMethodByObf(obf.getName(), obf.getDesc()) != classMapping.getMethodByDeobf(deobfName, obf.getDesc()))
+ || index.containsObfMethod(targetEntry)) {
+ Translator translator = mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index.getTranslationIndex());
+ String deobfClassName = translator.getTranslatedClass(entryPool.getClass(obf.getClassName())).getClassName();
if (deobfClassName == null) {
deobfClassName = obf.getClassName();
}
throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
}
- classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName);
+ classMapping.setMethodName(obf.getName(), obf.getDesc(), deobfName);
}
public void removeMethodTreeMapping(MethodEntry obf) {
@@ -176,8 +181,8 @@ public class MappingsRenamer {
}
public void removeMethodMapping(MethodEntry obf) {
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.setMethodName(obf.getName(), obf.getSignature(), null);
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.setMethodName(obf.getName(), obf.getDesc(), null);
}
public void markMethodTreeAsDeobfuscated(MethodEntry obf) {
@@ -185,30 +190,25 @@ public class MappingsRenamer {
}
public void markMethodAsDeobfuscated(MethodEntry obf) {
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName());
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.setMethodName(obf.getName(), obf.getDesc(), obf.getName());
}
- public void setArgumentTreeName(ArgumentEntry obf, String deobfName) {
- if (!(obf.getBehaviorEntry() instanceof MethodEntry)) {
- setArgumentName(obf, deobfName);
- return;
- }
-
- MethodEntry obfMethod = (MethodEntry) obf.getBehaviorEntry();
+ public void setLocalVariableTreeName(LocalVariableEntry obf, String deobfName) {
+ MethodEntry obfMethod = obf.getOwnerEntry();
Set implementations = index.getRelatedMethodImplementations(obfMethod);
for (MethodEntry entry : implementations) {
- ClassMapping classMapping = mappings.getClassByObf(entry.getClassEntry());
+ ClassMapping classMapping = mappings.getClassByObf(entry.getOwnerClassEntry());
if (classMapping != null) {
- MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getSignature());
+ MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getDesc());
// NOTE: don't need to check arguments for name collisions with names determined by Procyon
// TODO: Verify if I don't break things
if (mapping != null) {
- for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) {
- if (argumentMapping.getIndex() != obf.getIndex()) {
- if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName)
- || argumentMapping.getName().equals(deobfName)) {
+ for (LocalVariableMapping localVariableMapping : Lists.newArrayList(mapping.arguments())) {
+ if (localVariableMapping.getIndex() != obf.getIndex()) {
+ if (mapping.getDeobfLocalVariableName(localVariableMapping.getIndex()).equals(deobfName)
+ || localVariableMapping.getName().equals(deobfName)) {
throw new IllegalNameException(deobfName, "There is already an argument with that name");
}
}
@@ -218,45 +218,45 @@ public class MappingsRenamer {
}
for (MethodEntry entry : implementations) {
- setArgumentName(new ArgumentEntry(obf, entry), deobfName);
+ setLocalVariableName(new LocalVariableEntry(entry, obf.getIndex(), obf.getName()), deobfName);
}
}
- public void setArgumentName(ArgumentEntry obf, String deobfName) {
+ public void setLocalVariableName(LocalVariableEntry obf, String deobfName) {
deobfName = NameValidator.validateArgumentName(deobfName);
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- MethodMapping mapping = classMapping.getMethodByObf(obf.getMethodName(), obf.getMethodSignature());
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ MethodMapping mapping = classMapping.getMethodByObf(obf.getMethodName(), obf.getMethodDesc());
// NOTE: don't need to check arguments for name collisions with names determined by Procyon
// TODO: Verify if I don't break things
if (mapping != null) {
- for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) {
- if (argumentMapping.getIndex() != obf.getIndex()) {
- if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName)
- || argumentMapping.getName().equals(deobfName)) {
+ for (LocalVariableMapping localVariableMapping : Lists.newArrayList(mapping.arguments())) {
+ if (localVariableMapping.getIndex() != obf.getIndex()) {
+ if (mapping.getDeobfLocalVariableName(localVariableMapping.getIndex()).equals(deobfName)
+ || localVariableMapping.getName().equals(deobfName)) {
throw new IllegalNameException(deobfName, "There is already an argument with that name");
}
}
}
}
- classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName);
+ classMapping.setArgumentName(obf.getMethodName(), obf.getMethodDesc(), obf.getIndex(), deobfName);
}
- public void removeArgumentMapping(ArgumentEntry obf) {
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex());
+ public void removeLocalVariableMapping(LocalVariableEntry obf) {
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodDesc(), obf.getIndex());
}
- public void markArgumentAsDeobfuscated(ArgumentEntry obf) {
- ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
- classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName());
+ public void markArgumentAsDeobfuscated(LocalVariableEntry obf) {
+ ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry());
+ classMapping.setArgumentName(obf.getMethodName(), obf.getMethodDesc(), obf.getIndex(), obf.getName());
}
public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) {
classMapping.removeFieldMapping(fieldMapping);
ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
- if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfType())) {
- if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfType())) {
+ if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfDesc())) {
+ if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfDesc())) {
targetClassMapping.addFieldMapping(fieldMapping);
return true;
} else {
@@ -269,12 +269,12 @@ public class MappingsRenamer {
public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) {
classMapping.removeMethodMapping(methodMapping);
ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
- if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) {
- if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) {
+ if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfDesc())) {
+ if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfDesc())) {
targetClassMapping.addMethodMapping(methodMapping);
return true;
} else {
- System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature());
+ System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfDesc());
}
}
return false;
@@ -326,12 +326,35 @@ public class MappingsRenamer {
}
public void setFieldModifier(FieldEntry obEntry, Mappings.EntryModifier modifier) {
- ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
- classMapping.setFieldModifier(obEntry.getName(), obEntry.getType(), modifier);
+ ClassMapping classMapping = getOrCreateClassMapping(obEntry.getOwnerClassEntry());
+ classMapping.setFieldModifier(obEntry.getName(), obEntry.getDesc(), modifier);
+ }
+
+ public void setMethodModifier(MethodEntry obEntry, Mappings.EntryModifier modifier) {
+ ClassMapping classMapping = getOrCreateClassMapping(obEntry.getOwnerClassEntry());
+ classMapping.setMethodModifier(obEntry.getName(), obEntry.getDesc(), modifier);
+ }
+
+ public Mappings.EntryModifier getClassModifier(ClassEntry obfEntry) {
+ ClassMapping classMapping = getOrCreateClassMapping(obfEntry);
+ return classMapping.getModifier();
}
- public void setMethodModifier(BehaviorEntry obEntry, Mappings.EntryModifier modifier) {
- ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
- classMapping.setMethodModifier(obEntry.getName(), obEntry.getSignature(), modifier);
+ public Mappings.EntryModifier getFieldModifier(FieldEntry obfEntry) {
+ ClassMapping classMapping = getOrCreateClassMapping(obfEntry.getOwnerClassEntry());
+ FieldMapping fieldMapping = classMapping.getFieldByObf(obfEntry);
+ if (fieldMapping == null) {
+ return Mappings.EntryModifier.UNCHANGED;
+ }
+ return fieldMapping.getModifier();
+ }
+
+ public Mappings.EntryModifier getMethodModfifier(MethodEntry obfEntry) {
+ ClassMapping classMapping = getOrCreateClassMapping(obfEntry.getOwnerClassEntry());
+ MethodMapping methodMapping = classMapping.getMethodByObf(obfEntry);
+ if (methodMapping == null) {
+ return Mappings.EntryModifier.UNCHANGED;
+ }
+ return methodMapping.getModifier();
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java
index b0eb826..95daa73 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java
@@ -19,7 +19,7 @@ public class MappingsSRGWriter {
}
file.createNewFile();
- TranslationIndex index = new TranslationIndex();
+ TranslationIndex index = new TranslationIndex(new ReferencedEntryPool());
PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8));
List fieldMappings = new ArrayList<>();
@@ -43,7 +43,7 @@ public class MappingsSRGWriter {
}
for (MethodMapping methodMapping : sorted(innerClassMapping.methods())) {
- methodMappings.add("MD: " + innerClassName + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature() + " " + innerDeobfClassName + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature()));
+ methodMappings.add("MD: " + innerClassName + "/" + methodMapping.getObfName() + " " + methodMapping.getObfDesc() + " " + innerDeobfClassName + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index).getTranslatedMethodDesc(methodMapping.getObfDesc()));
}
}
@@ -52,7 +52,7 @@ public class MappingsSRGWriter {
}
for (MethodMapping methodMapping : sorted(classMapping.methods())) {
- methodMappings.add("MD: " + classMapping.getObfFullName() + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature() + " " + classMapping.getDeobfName() + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature()));
+ methodMappings.add("MD: " + classMapping.getObfFullName() + "/" + methodMapping.getObfName() + " " + methodMapping.getObfDesc() + " " + classMapping.getDeobfName() + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index).getTranslatedMethodDesc(methodMapping.getObfDesc()));
}
}
for (String fd : fieldMappings) {
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java
index dfe9e88..e635fa1 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java
@@ -20,11 +20,11 @@ public class MappingsTinyReader {
}
public FieldMapping readField(String[] parts) {
- return new FieldMapping(parts[3], new Type(parts[2]), parts[4], Mappings.EntryModifier.UNCHANGED);
+ return new FieldMapping(parts[3], new TypeDescriptor(parts[2]), parts[4], Mappings.EntryModifier.UNCHANGED);
}
public MethodMapping readMethod(String[] parts) {
- return new MethodMapping(parts[3], new Signature(parts[2]), parts[4]);
+ return new MethodMapping(parts[3], new MethodDescriptor(parts[2]), parts[4]);
}
public Mappings read(File file) throws IOException, MappingParseException {
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodDefEntry.java b/src/main/java/cuchaz/enigma/mapping/MethodDefEntry.java
new file mode 100644
index 0000000..d6a160d
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/MethodDefEntry.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import com.google.common.base.Preconditions;
+import cuchaz.enigma.bytecode.AccessFlags;
+
+public class MethodDefEntry extends MethodEntry {
+
+ private final AccessFlags access;
+
+ public MethodDefEntry(ClassEntry classEntry, String name, MethodDescriptor descriptor, AccessFlags access) {
+ super(classEntry, name, descriptor);
+ Preconditions.checkNotNull(access, "Method access cannot be null");
+ this.access = access;
+ }
+
+ public AccessFlags getAccess() {
+ return access;
+ }
+
+ @Override
+ public MethodDefEntry updateOwnership(ClassEntry classEntry) {
+ return new MethodDefEntry(new ClassEntry(classEntry.getName()), name, descriptor, access);
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodDescriptor.java b/src/main/java/cuchaz/enigma/mapping/MethodDescriptor.java
new file mode 100644
index 0000000..210ada0
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/MethodDescriptor.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import com.google.common.collect.Lists;
+import cuchaz.enigma.utils.Utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public class MethodDescriptor {
+
+ private List argumentDescs;
+ private TypeDescriptor returnDesc;
+
+ public MethodDescriptor(String desc) {
+ try {
+ this.argumentDescs = Lists.newArrayList();
+ int i = 0;
+ while (i < desc.length()) {
+ char c = desc.charAt(i);
+ if (c == '(') {
+ assert (this.argumentDescs.isEmpty());
+ assert (this.returnDesc == null);
+ i++;
+ } else if (c == ')') {
+ i++;
+ break;
+ } else {
+ String type = TypeDescriptor.parseFirst(desc.substring(i));
+ this.argumentDescs.add(new TypeDescriptor(type));
+ i += type.length();
+ }
+ }
+ this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i)));
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex);
+ }
+ }
+
+ public MethodDescriptor(List argumentDescs, TypeDescriptor returnDesc) {
+ this.argumentDescs = argumentDescs;
+ this.returnDesc = returnDesc;
+ }
+
+ public List getArgumentDescs() {
+ return this.argumentDescs;
+ }
+
+ public TypeDescriptor getReturnDesc() {
+ return this.returnDesc;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("(");
+ for (TypeDescriptor desc : this.argumentDescs) {
+ buf.append(desc);
+ }
+ buf.append(")");
+ buf.append(this.returnDesc);
+ return buf.toString();
+ }
+
+ public Iterable types() {
+ List descs = Lists.newArrayList();
+ descs.addAll(this.argumentDescs);
+ descs.add(this.returnDesc);
+ return descs;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof MethodDescriptor && equals((MethodDescriptor) other);
+ }
+
+ public boolean equals(MethodDescriptor other) {
+ return this.argumentDescs.equals(other.argumentDescs) && this.returnDesc.equals(other.returnDesc);
+ }
+
+ @Override
+ public int hashCode() {
+ return Utils.combineHashesOrdered(this.argumentDescs.hashCode(), this.returnDesc.hashCode());
+ }
+
+ public boolean hasClass(ClassEntry classEntry) {
+ for (TypeDescriptor desc : types()) {
+ if (desc.containsType() && desc.getOwnerEntry().equals(classEntry)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public MethodDescriptor remap(Function remapper) {
+ List argumentDescs = new ArrayList<>(this.argumentDescs.size());
+ for (TypeDescriptor desc : this.argumentDescs) {
+ argumentDescs.add(desc.remap(remapper));
+ }
+ return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper));
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodEntry.java b/src/main/java/cuchaz/enigma/mapping/MethodEntry.java
index 9c3058c..f8a5ff1 100644
--- a/src/main/java/cuchaz/enigma/mapping/MethodEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/MethodEntry.java
@@ -11,41 +11,27 @@
package cuchaz.enigma.mapping;
+import com.google.common.base.Preconditions;
import cuchaz.enigma.utils.Utils;
-public class MethodEntry implements BehaviorEntry {
-
- private ClassEntry classEntry;
- private String name;
- private Signature signature;
-
- public MethodEntry(ClassEntry classEntry, String name, Signature signature) {
- if (classEntry == null) {
- throw new IllegalArgumentException("Class cannot be null!");
- }
- if (name == null) {
- throw new IllegalArgumentException("Method name cannot be null!");
- }
- if (signature == null) {
- throw new IllegalArgumentException("Method signature cannot be null!");
- }
- if (name.startsWith("<")) {
- throw new IllegalArgumentException("Don't use MethodEntry for a constructor!");
- }
+public class MethodEntry implements Entry {
+
+ protected final ClassEntry classEntry;
+ protected final String name;
+ protected final MethodDescriptor descriptor;
+
+ public MethodEntry(ClassEntry classEntry, String name, MethodDescriptor descriptor) {
+ Preconditions.checkNotNull(classEntry, "Class cannot be null");
+ Preconditions.checkNotNull(name, "Method name cannot be null");
+ Preconditions.checkNotNull(descriptor, "Method descriptor cannot be null");
this.classEntry = classEntry;
this.name = name;
- this.signature = signature;
- }
-
- public MethodEntry(MethodEntry other, String newClassName) {
- this.classEntry = new ClassEntry(newClassName);
- this.name = other.name;
- this.signature = other.signature;
+ this.descriptor = descriptor;
}
@Override
- public ClassEntry getClassEntry() {
+ public ClassEntry getOwnerClassEntry() {
return this.classEntry;
}
@@ -54,9 +40,12 @@ public class MethodEntry implements BehaviorEntry {
return this.name;
}
- @Override
- public Signature getSignature() {
- return this.signature;
+ public MethodDescriptor getDesc() {
+ return this.descriptor;
+ }
+
+ public boolean isConstructor() {
+ return name.equals("") || name.equals("");
}
@Override
@@ -65,13 +54,13 @@ public class MethodEntry implements BehaviorEntry {
}
@Override
- public MethodEntry cloneToNewClass(ClassEntry classEntry) {
- return new MethodEntry(this, classEntry.getName());
+ public MethodEntry updateOwnership(ClassEntry classEntry) {
+ return new MethodEntry(new ClassEntry(classEntry.getName()), name, descriptor);
}
@Override
public int hashCode() {
- return Utils.combineHashesOrdered(this.classEntry, this.name, this.signature);
+ return Utils.combineHashesOrdered(this.classEntry, this.name, this.descriptor);
}
@Override
@@ -80,11 +69,11 @@ public class MethodEntry implements BehaviorEntry {
}
public boolean equals(MethodEntry other) {
- return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.signature.equals(other.signature);
+ return this.classEntry.equals(other.getOwnerClassEntry()) && this.name.equals(other.getName()) && this.descriptor.equals(other.getDesc());
}
@Override
public String toString() {
- return this.classEntry.getName() + "." + this.name + this.signature;
+ return this.classEntry.getName() + "." + this.name + this.descriptor;
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
index 1524ce6..2f7fe53 100644
--- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
@@ -11,50 +11,47 @@
package cuchaz.enigma.mapping;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import cuchaz.enigma.throwables.IllegalNameException;
import cuchaz.enigma.throwables.MappingConflict;
import java.util.Map;
-public class MethodMapping implements Comparable, MemberMapping {
+public class MethodMapping implements Comparable, MemberMapping {
private String obfName;
private String deobfName;
- private Signature obfSignature;
- private Map arguments;
+ private MethodDescriptor obfDescriptor;
+ private Map localVariables;
private Mappings.EntryModifier modifier;
- public MethodMapping(String obfName, Signature obfSignature) {
- this(obfName, obfSignature, null, Mappings.EntryModifier.UNCHANGED);
+ public MethodMapping(String obfName, MethodDescriptor obfDescriptor) {
+ this(obfName, obfDescriptor, null, Mappings.EntryModifier.UNCHANGED);
}
- public MethodMapping(String obfName, Signature obfSignature, String deobfName) {
- this(obfName, obfSignature, deobfName, Mappings.EntryModifier.UNCHANGED);
+ public MethodMapping(String obfName, MethodDescriptor obfDescriptor, String deobfName) {
+ this(obfName, obfDescriptor, deobfName, Mappings.EntryModifier.UNCHANGED);
}
- public MethodMapping(String obfName, Signature obfSignature, String deobfName, Mappings.EntryModifier modifier) {
- if (obfName == null) {
- throw new IllegalArgumentException("obf name cannot be null!");
- }
- if (obfSignature == null) {
- throw new IllegalArgumentException("obf signature cannot be null!");
- }
+ public MethodMapping(String obfName, MethodDescriptor obfDescriptor, String deobfName, Mappings.EntryModifier modifier) {
+ Preconditions.checkNotNull(obfName, "Method obf name cannot be null");
+ Preconditions.checkNotNull(obfDescriptor, "Method obf desc cannot be null");
this.obfName = obfName;
this.deobfName = NameValidator.validateMethodName(deobfName);
- this.obfSignature = obfSignature;
- this.arguments = Maps.newTreeMap();
+ this.obfDescriptor = obfDescriptor;
+ this.localVariables = Maps.newTreeMap();
this.modifier = modifier;
}
- public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) {
+ public MethodMapping(MethodMapping other, Translator translator) {
this.obfName = other.obfName;
this.deobfName = other.deobfName;
this.modifier = other.modifier;
- this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer);
- this.arguments = Maps.newTreeMap();
- for (Map.Entry entry : other.arguments.entrySet()) {
- this.arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue()));
+ this.obfDescriptor = translator.getTranslatedMethodDesc(other.obfDescriptor);
+ this.localVariables = Maps.newTreeMap();
+ for (Map.Entry entry : other.localVariables.entrySet()) {
+ this.localVariables.put(entry.getKey(), new LocalVariableMapping(entry.getValue()));
}
}
@@ -84,56 +81,56 @@ public class MethodMapping implements Comparable, MemberMapping arguments() {
- return this.arguments.values();
+ public Iterable arguments() {
+ return this.localVariables.values();
}
- public void addArgumentMapping(ArgumentMapping argumentMapping) throws MappingConflict {
- if (this.arguments.containsKey(argumentMapping.getIndex())) {
- throw new MappingConflict("argument", argumentMapping.getName(), this.arguments.get(argumentMapping.getIndex()).getName());
+ public void addArgumentMapping(LocalVariableMapping localVariableMapping) throws MappingConflict {
+ if (this.localVariables.containsKey(localVariableMapping.getIndex())) {
+ throw new MappingConflict("argument", localVariableMapping.getName(), this.localVariables.get(localVariableMapping.getIndex()).getName());
}
- this.arguments.put(argumentMapping.getIndex(), argumentMapping);
+ this.localVariables.put(localVariableMapping.getIndex(), localVariableMapping);
}
- public String getObfArgumentName(int index) {
- ArgumentMapping argumentMapping = this.arguments.get(index);
- if (argumentMapping != null) {
- return argumentMapping.getName();
+ public String getObfLocalVariableName(int index) {
+ LocalVariableMapping localVariableMapping = this.localVariables.get(index);
+ if (localVariableMapping != null) {
+ return localVariableMapping.getName();
}
return null;
}
- public String getDeobfArgumentName(int index) {
- ArgumentMapping argumentMapping = this.arguments.get(index);
- if (argumentMapping != null) {
- return argumentMapping.getName();
+ public String getDeobfLocalVariableName(int index) {
+ LocalVariableMapping localVariableMapping = this.localVariables.get(index);
+ if (localVariableMapping != null) {
+ return localVariableMapping.getName();
}
return null;
}
- public void setArgumentName(int index, String name) {
- ArgumentMapping argumentMapping = this.arguments.get(index);
- if (argumentMapping == null) {
- argumentMapping = new ArgumentMapping(index, name);
- boolean wasAdded = this.arguments.put(index, argumentMapping) == null;
+ public void setLocalVariableName(int index, String name) {
+ LocalVariableMapping localVariableMapping = this.localVariables.get(index);
+ if (localVariableMapping == null) {
+ localVariableMapping = new LocalVariableMapping(index, name);
+ boolean wasAdded = this.localVariables.put(index, localVariableMapping) == null;
assert (wasAdded);
} else {
- argumentMapping.setName(name);
+ localVariableMapping.setName(name);
}
}
- public void removeArgumentName(int index) {
- boolean wasRemoved = this.arguments.remove(index) != null;
+ public void removeLocalVariableName(int index) {
+ boolean wasRemoved = this.localVariables.remove(index) != null;
assert (wasRemoved);
}
@@ -146,14 +143,14 @@ public class MethodMapping implements Comparable, MemberMapping ");
- buf.append(argumentMapping.getName());
+ buf.append(localVariableMapping.getName());
buf.append("\n");
}
return buf.toString();
@@ -161,12 +158,12 @@ public class MethodMapping implements Comparable, MemberMapping, MemberMapping
- {
+ MethodDescriptor newDescriptor = obfDescriptor.remap(className -> {
if (className.equals(oldObfClassName)) {
return newObfClassName;
}
- return null;
+ return className;
});
- if (!newSignature.equals(this.obfSignature)) {
- this.obfSignature = newSignature;
+ if (!newDescriptor.equals(this.obfDescriptor)) {
+ this.obfDescriptor = newDescriptor;
return true;
}
return false;
}
- public boolean isConstructor() {
- return this.obfName.startsWith("<");
- }
-
@Override
- public BehaviorEntry getObfEntry(ClassEntry classEntry) {
- if (isConstructor()) {
- return new ConstructorEntry(classEntry, this.obfSignature);
- } else {
- return new MethodEntry(classEntry, this.obfName, this.obfSignature);
- }
+ public MethodEntry getObfEntry(ClassEntry classEntry) {
+ return new MethodEntry(classEntry, this.obfName, this.obfDescriptor);
}
public Mappings.EntryModifier getModifier() {
diff --git a/src/main/java/cuchaz/enigma/mapping/NameValidator.java b/src/main/java/cuchaz/enigma/mapping/NameValidator.java
index aa3dc4d..f178093 100644
--- a/src/main/java/cuchaz/enigma/mapping/NameValidator.java
+++ b/src/main/java/cuchaz/enigma/mapping/NameValidator.java
@@ -12,7 +12,6 @@
package cuchaz.enigma.mapping;
import cuchaz.enigma.throwables.IllegalNameException;
-import javassist.bytecode.Descriptor;
import java.util.Arrays;
import java.util.List;
@@ -23,11 +22,11 @@ public class NameValidator {
private static final Pattern IdentifierPattern;
private static final Pattern ClassPattern;
private static final List ReservedWords = Arrays.asList(
- "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized",
- "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte",
- "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch",
- "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
- "long", "strictfp", "volatile", "const", "float", "native", "super", "while"
+ "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized",
+ "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte",
+ "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch",
+ "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
+ "long", "strictfp", "volatile", "const", "float", "native", "super", "while"
);
static {
@@ -43,10 +42,10 @@ public class NameValidator {
if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) {
throw new IllegalNameException(name, "This doesn't look like a legal class name");
}
- if (packageRequired && new ClassEntry(name).getPackageName() == null) {
+ if (packageRequired && ClassEntry.getPackageName(name) == null) {
throw new IllegalNameException(name, "Class must be in a package");
}
- return Descriptor.toJvmName(name);
+ return name;
}
public static String validateFieldName(String name) {
diff --git a/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java b/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
index 33d930d..9300656 100644
--- a/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
+++ b/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
@@ -12,12 +12,18 @@
package cuchaz.enigma.mapping;
import com.strobel.assembler.metadata.*;
+import cuchaz.enigma.bytecode.AccessFlags;
import java.util.List;
public class ProcyonEntryFactory {
+ private final ReferencedEntryPool entryPool;
- private static String getErasedSignature(MemberReference def) {
+ public ProcyonEntryFactory(ReferencedEntryPool entryPool) {
+ this.entryPool = entryPool;
+ }
+
+ private String getErasedSignature(MemberReference def) {
if (!(def instanceof MethodReference))
return def.getErasedSignature();
MethodReference methodReference = (MethodReference) def;
@@ -41,27 +47,23 @@ public class ProcyonEntryFactory {
return builder.toString();
}
- public static FieldEntry getFieldEntry(MemberReference def) {
- return new FieldEntry(new ClassEntry(def.getDeclaringType().getInternalName()), def.getName(), new Type(def.getErasedSignature()));
+ public FieldEntry getFieldEntry(MemberReference def) {
+ ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
+ return entryPool.getField(classEntry, def.getName(), def.getErasedSignature());
}
- public static MethodEntry getMethodEntry(MemberReference def) {
- return new MethodEntry(new ClassEntry(def.getDeclaringType().getInternalName()), def.getName(), new Signature(getErasedSignature(def)));
+ public FieldDefEntry getFieldDefEntry(FieldDefinition def) {
+ ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
+ return new FieldDefEntry(classEntry, def.getName(), new TypeDescriptor(def.getErasedSignature()), new AccessFlags(def.getModifiers()));
}
- public static ConstructorEntry getConstructorEntry(MethodReference def) {
- if (def.isTypeInitializer()) {
- return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName()));
- } else {
- return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName()), new Signature(def.getErasedSignature()));
- }
+ public MethodEntry getMethodEntry(MemberReference def) {
+ ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
+ return entryPool.getMethod(classEntry, def.getName(), getErasedSignature(def));
}
- public static BehaviorEntry getBehaviorEntry(MethodReference def) {
- if (def.isConstructor() || def.isTypeInitializer()) {
- return getConstructorEntry(def);
- } else {
- return getMethodEntry(def);
- }
+ public MethodDefEntry getMethodDefEntry(MethodDefinition def) {
+ ClassEntry classEntry = entryPool.getClass(def.getDeclaringType().getInternalName());
+ return new MethodDefEntry(classEntry, def.getName(), new MethodDescriptor(def.getErasedSignature()), new AccessFlags(def.getModifiers()));
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/ReferencedEntryPool.java b/src/main/java/cuchaz/enigma/mapping/ReferencedEntryPool.java
new file mode 100644
index 0000000..2abc76c
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/ReferencedEntryPool.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ReferencedEntryPool {
+ private final Map classEntries = new HashMap<>();
+ private final Map> methodEntries = new HashMap<>();
+ private final Map> fieldEntries = new HashMap<>();
+
+ public ClassEntry getClass(String name) {
+ return this.classEntries.computeIfAbsent(name, s -> new ClassEntry(name));
+ }
+
+ public MethodEntry getMethod(ClassEntry ownerEntry, String name, String desc) {
+ return getMethod(ownerEntry, name, new MethodDescriptor(desc));
+ }
+
+ public MethodEntry getMethod(ClassEntry ownerEntry, String name, MethodDescriptor desc) {
+ String key = name + desc.toString();
+ return getClassMethods(ownerEntry.getName()).computeIfAbsent(key, s -> new MethodEntry(ownerEntry, name, desc));
+ }
+
+ public FieldEntry getField(ClassEntry ownerEntry, String name, String desc) {
+ return getField(ownerEntry, name, new TypeDescriptor(desc));
+ }
+
+ public FieldEntry getField(ClassEntry ownerEntry, String name, TypeDescriptor desc) {
+ return getClassFields(ownerEntry.getName()).computeIfAbsent(name, s -> new FieldEntry(ownerEntry, name, desc));
+ }
+
+ private Map getClassMethods(String name) {
+ return methodEntries.computeIfAbsent(name, s -> new HashMap<>());
+ }
+
+ private Map getClassFields(String name) {
+ return fieldEntries.computeIfAbsent(name, s -> new HashMap<>());
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/Signature.java b/src/main/java/cuchaz/enigma/mapping/Signature.java
deleted file mode 100644
index 78130d6..0000000
--- a/src/main/java/cuchaz/enigma/mapping/Signature.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Jeff Martin.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Lesser General Public
- * License v3.0 which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/lgpl.html
- *
- * Contributors:
- * Jeff Martin - initial API and implementation
- ******************************************************************************/
-
-package cuchaz.enigma.mapping;
-
-import com.google.common.collect.Lists;
-import cuchaz.enigma.utils.Utils;
-
-import java.util.List;
-
-public class Signature {
-
- private List argumentTypes;
- private Type returnType;
-
- public Signature(String signature) {
- try {
- this.argumentTypes = Lists.newArrayList();
- int i = 0;
- while (i < signature.length()) {
- char c = signature.charAt(i);
- if (c == '(') {
- assert (this.argumentTypes.isEmpty());
- assert (this.returnType == null);
- i++;
- } else if (c == ')') {
- i++;
- break;
- } else {
- String type = Type.parseFirst(signature.substring(i));
- this.argumentTypes.add(new Type(type));
- i += type.length();
- }
- }
- this.returnType = new Type(Type.parseFirst(signature.substring(i)));
- } catch (Exception ex) {
- throw new IllegalArgumentException("Unable to parse signature: " + signature, ex);
- }
- }
-
- public Signature(Signature other, ClassNameReplacer replacer) {
- this.argumentTypes = Lists.newArrayList(other.argumentTypes);
- for (int i = 0; i < this.argumentTypes.size(); i++) {
- this.argumentTypes.set(i, new Type(this.argumentTypes.get(i), replacer));
- }
- this.returnType = new Type(other.returnType, replacer);
- }
-
- public List getArgumentTypes() {
- return this.argumentTypes;
- }
-
- public Type getReturnType() {
- return this.returnType;
- }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
- buf.append("(");
- for (Type type : this.argumentTypes) {
- buf.append(type);
- }
- buf.append(")");
- buf.append(this.returnType);
- return buf.toString();
- }
-
- public Iterable types() {
- List types = Lists.newArrayList();
- types.addAll(this.argumentTypes);
- types.add(this.returnType);
- return types;
- }
-
- @Override
- public boolean equals(Object other) {
- return other instanceof Signature && equals((Signature) other);
- }
-
- public boolean equals(Signature other) {
- return this.argumentTypes.equals(other.argumentTypes) && this.returnType.equals(other.returnType);
- }
-
- @Override
- public int hashCode() {
- return Utils.combineHashesOrdered(this.argumentTypes.hashCode(), this.returnType.hashCode());
- }
-
- public boolean hasClass(ClassEntry classEntry) {
- for (Type type : types()) {
- if (type.hasClass() && type.getClassEntry().equals(classEntry)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java b/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java
index 17e3187..4bbde54 100644
--- a/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java
+++ b/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java
@@ -13,15 +13,21 @@ package cuchaz.enigma.mapping;
public enum TranslationDirection {
- Deobfuscating {
+ DEOBFUSCATING {
@Override
public T choose(T deobfChoice, T obfChoice) {
+ if (deobfChoice == null) {
+ return obfChoice;
+ }
return deobfChoice;
}
},
- Obfuscating {
+ OBFUSCATING {
@Override
public T choose(T deobfChoice, T obfChoice) {
+ if (obfChoice == null) {
+ return deobfChoice;
+ }
return obfChoice;
}
};
diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java
index 8d464fc..59bdf1a 100644
--- a/src/main/java/cuchaz/enigma/mapping/Translator.java
+++ b/src/main/java/cuchaz/enigma/mapping/Translator.java
@@ -11,332 +11,50 @@
package cuchaz.enigma.mapping;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import cuchaz.enigma.analysis.TranslationIndex;
+public interface Translator {
+ ClassEntry getTranslatedClass(ClassEntry entry);
-import java.util.List;
-import java.util.Map;
+ ClassDefEntry getTranslatedClassDef(ClassDefEntry entry);
-public class Translator {
+ FieldEntry getTranslatedField(FieldEntry entry);
- private TranslationDirection direction;
- private Map classes;
- private TranslationIndex index;
+ FieldDefEntry getTranslatedFieldDef(FieldDefEntry entry);
- private ClassNameReplacer classNameReplacer = className -> translateEntry(new ClassEntry(className)).getName();
+ MethodEntry getTranslatedMethod(MethodEntry entry);
- public Translator() {
- this.direction = null;
- this.classes = Maps.newHashMap();
- this.index = new TranslationIndex();
- }
+ MethodDefEntry getTranslatedMethodDef(MethodDefEntry entry);
- public Translator(TranslationDirection direction, Map classes, TranslationIndex index) {
- this.direction = direction;
- this.classes = classes;
- this.index = index;
- }
+ LocalVariableEntry getTranslatedVariable(LocalVariableEntry entry);
- public TranslationDirection getDirection() {
- return direction;
- }
+ LocalVariableDefEntry getTranslatedVariableDef(LocalVariableDefEntry entry);
- public TranslationIndex getTranslationIndex() {
- return index;
- }
+ TypeDescriptor getTranslatedTypeDesc(TypeDescriptor desc);
- @SuppressWarnings("unchecked")
- public T translateEntry(T entry) {
- if (entry instanceof ClassEntry) {
- return (T) translateEntry((ClassEntry) entry);
- } else if (entry instanceof FieldEntry) {
- return (T) translateEntry((FieldEntry) entry);
- } else if (entry instanceof MethodEntry) {
- return (T) translateEntry((MethodEntry) entry);
- } else if (entry instanceof ConstructorEntry) {
- return (T) translateEntry((ConstructorEntry) entry);
- } else if (entry instanceof ArgumentEntry) {
- return (T) translateEntry((ArgumentEntry) entry);
- } else if (entry instanceof LocalVariableEntry) {
- return (T) translateEntry((LocalVariableEntry) entry);
- } else {
- throw new Error("Unknown entry type: " + entry.getClass().getName());
- }
- }
+ MethodDescriptor getTranslatedMethodDesc(MethodDescriptor descriptor);
- public String translate(T entry) {
- if (entry instanceof ClassEntry) {
- return translate((ClassEntry) entry);
+ @SuppressWarnings("unchecked")
+ default T getTranslatedEntry(T entry) {
+ if (entry instanceof ClassDefEntry) {
+ return (T) getTranslatedClassDef((ClassDefEntry) entry);
+ } else if (entry instanceof ClassEntry) {
+ return (T) getTranslatedClass((ClassEntry) entry);
+ } else if (entry instanceof FieldDefEntry) {
+ return (T) getTranslatedFieldDef((FieldDefEntry) entry);
+ } else if (entry instanceof MethodDefEntry) {
+ return (T) getTranslatedMethodDef((MethodDefEntry) entry);
} else if (entry instanceof FieldEntry) {
- return translate((FieldEntry) entry);
+ return (T) getTranslatedField((FieldEntry) entry);
} else if (entry instanceof MethodEntry) {
- return translate((MethodEntry) entry);
- } else if (entry instanceof ConstructorEntry) {
- return translate(entry);
- } else if (entry instanceof ArgumentEntry) {
- return translate((ArgumentEntry) entry);
+ return (T) getTranslatedMethod((MethodEntry) entry);
+ } else if (entry instanceof LocalVariableDefEntry) {
+ return (T) getTranslatedVariableDef((LocalVariableDefEntry) entry);
} else if (entry instanceof LocalVariableEntry) {
- return translate((LocalVariableEntry) entry);
- } else {
- throw new Error("Unknown entry type: " + entry.getClass().getName());
- }
- }
-
- public String translate(LocalVariableEntry in) {
- LocalVariableEntry translated = translateEntry(in);
- if (translated.equals(in)) {
- return null;
- }
- return translated.getName();
- }
-
- public LocalVariableEntry translateEntry(LocalVariableEntry in) {
- // TODO: Implement it
- return in;
- }
-
- public String translate(ClassEntry in) {
- ClassEntry translated = translateEntry(in);
- if (translated.equals(in)) {
- return null;
- }
- return translated.getName();
- }
-
- public String translateClass(String className) {
- return translate(new ClassEntry(className));
- }
-
- public ClassEntry translateEntry(ClassEntry in) {
-
- if (in.isInnerClass()) {
-
- // translate as much of the class chain as we can
- List mappingsChain = getClassMappingChain(in);
- String[] obfClassNames = in.getName().split("\\$");
- StringBuilder buf = new StringBuilder();
- for (int i = 0; i < obfClassNames.length; i++) {
- boolean isFirstClass = buf.length() == 0;
- String className = null;
- ClassMapping classMapping = mappingsChain.get(i);
- if (classMapping != null) {
- className = this.direction.choose(
- classMapping.getDeobfName(),
- isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName()
- );
- }
- if (className == null) {
- className = obfClassNames[i];
- }
- if (!isFirstClass) {
- buf.append("$");
- }
- buf.append(className);
- }
- return new ClassEntry(buf.toString());
-
- } else {
-
- // normal classes are easy
- ClassMapping classMapping = this.classes.get(in.getName());
- if (classMapping == null) {
- return in;
- }
- return this.direction.choose(
- classMapping.getDeobfName() != null ? new ClassEntry(classMapping.getDeobfName()) : in,
- new ClassEntry(classMapping.getObfFullName())
- );
- }
- }
-
- public String translate(FieldEntry in) {
-
- // resolve the class entry
- ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in);
- if (resolvedClassEntry != null) {
-
- // look for the class
- ClassMapping classMapping = findClassMapping(resolvedClassEntry);
- if (classMapping != null) {
-
- // look for the field
- String translatedName = this.direction.choose(
- classMapping.getDeobfFieldName(in.getName(), in.getType()),
- classMapping.getObfFieldName(in.getName(), translateType(in.getType()))
- );
- if (translatedName != null) {
- return translatedName;
- }
- }
- }
- return null;
- }
-
- public FieldEntry translateEntry(FieldEntry in) {
- String name = translate(in);
- if (name == null) {
- name = in.getName();
- }
- return new FieldEntry(translateEntry(in.getClassEntry()), name, translateType(in.getType()));
- }
-
- public String translate(MethodEntry in) {
- // resolve the class entry
- ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in, true);
- if (resolvedClassEntry != null) {
-
- // look for class
- ClassMapping classMapping = findClassMapping(resolvedClassEntry);
- if (classMapping != null) {
-
- // look for the method
- MethodMapping methodMapping = this.direction.choose(
- classMapping.getMethodByObf(in.getName(), in.getSignature()),
- classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))
- );
- if (methodMapping != null) {
- return this.direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName());
- }
- }
- }
- return null;
- }
-
- public MethodEntry translateEntry(MethodEntry in) {
- String name = translate(in);
- if (name == null) {
- name = in.getName();
- }
- return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature()));
- }
-
- public ConstructorEntry translateEntry(ConstructorEntry in) {
- if (in.isStatic()) {
- return new ConstructorEntry(translateEntry(in.getClassEntry()));
- } else {
- return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature()));
- }
- }
-
- public BehaviorEntry translateEntry(BehaviorEntry in) {
- if (in instanceof MethodEntry) {
- return translateEntry((MethodEntry) in);
- } else if (in instanceof ConstructorEntry) {
- return translateEntry((ConstructorEntry) in);
- }
- throw new Error("Wrong entry type!");
- }
-
- // TODO: support not identical behavior (specific to constructor)
- public String translate(ArgumentEntry in) {
- String classTranslate = translateArgument(in);
-
- // Not found in this class
- if (classTranslate == null) {
- List ancestry = this.index.getAncestry(in.getClassEntry());
-
- // Check in mother class for the arg
- for (ClassEntry entry : ancestry) {
- ArgumentEntry motherArg = in.cloneToNewClass(entry);
- if (this.index.entryExists(motherArg)) {
- String result = translateArgument(motherArg);
- if (result != null)
- return result;
- }
- }
- }
- return classTranslate;
- }
-
- public String translateArgument(ArgumentEntry in) {
- // look for identical behavior in superclasses
- ClassEntry entry = in.getClassEntry();
-
- if (entry != null) {
- // look for the class
- ClassMapping classMapping = findClassMapping(entry);
- if (classMapping != null) {
-
- // look for the method
- MethodMapping methodMapping = this.direction.choose(
- classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()),
- classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature()))
- );
- if (methodMapping != null) {
- return this.direction.choose(
- methodMapping.getDeobfArgumentName(in.getIndex()),
- methodMapping.getObfArgumentName(in.getIndex())
- );
- }
- }
- }
- return null;
- }
-
- public ArgumentEntry translateEntry(ArgumentEntry in) {
- String name = translate(in);
- if (name == null) {
- name = in.getName();
- }
- return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name);
- }
-
- public Type translateType(Type type) {
- return new Type(type, this.classNameReplacer);
- }
-
- public Signature translateSignature(Signature signature) {
- return new Signature(signature, this.classNameReplacer);
- }
-
- private ClassMapping findClassMapping(ClassEntry in) {
- List mappingChain = getClassMappingChain(in);
- return mappingChain.get(mappingChain.size() - 1);
- }
-
- private List getClassMappingChain(ClassEntry in) {
-
- // get a list of all the classes in the hierarchy
- String[] parts = in.getName().split("\\$");
- List mappingsChain = Lists.newArrayList();
-
- // get mappings for the outer class
- ClassMapping outerClassMapping = this.classes.get(parts[0]);
- mappingsChain.add(outerClassMapping);
-
- for (int i = 1; i < parts.length; i++) {
-
- // get mappings for the inner class
- ClassMapping innerClassMapping = null;
- if (outerClassMapping != null) {
- innerClassMapping = this.direction.choose(
- outerClassMapping.getInnerClassByObfSimple(parts[i]),
- outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i])
- );
- }
- mappingsChain.add(innerClassMapping);
- outerClassMapping = innerClassMapping;
- }
-
- assert (mappingsChain.size() == parts.length);
- return mappingsChain;
- }
-
- public Mappings.EntryModifier getModifier(Entry entry) {
- ClassMapping classMapping = findClassMapping(entry.getClassEntry());
- if (classMapping != null && !entry.getName().equals("")) {
- if (entry instanceof ClassEntry)
- return classMapping.getModifier();
- else if (entry instanceof FieldEntry) {
- FieldMapping fieldMapping = classMapping.getFieldByObf(entry.getName(), ((FieldEntry) entry).getType());
- return fieldMapping != null ? fieldMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
- } else if (entry instanceof BehaviorEntry) {
- MethodMapping methodMapping = classMapping.getMethodByObf(entry.getName(), ((BehaviorEntry) entry).getSignature());
- return methodMapping != null ? methodMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
- } else
- throw new Error("Unknown entry type: " + entry.getClass().getName());
+ return (T) getTranslatedVariable((LocalVariableEntry) entry);
+ } else if (entry instanceof TypeDescriptor) {
+ return (T) getTranslatedTypeDesc((TypeDescriptor) entry);
+ } else if (entry instanceof MethodDescriptor) {
+ return (T) getTranslatedMethodDesc((MethodDescriptor) entry);
}
- return Mappings.EntryModifier.UNCHANGED;
+ throw new IllegalArgumentException("Cannot translate unknown entry type");
}
}
diff --git a/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java b/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java
new file mode 100644
index 0000000..9c0fe6d
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Jeff Martin.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public
+ * License v3.0 which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Jeff Martin - initial API and implementation
+ ******************************************************************************/
+
+package cuchaz.enigma.mapping;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.function.Function;
+
+public class TypeDescriptor {
+
+ protected final String desc;
+
+ public TypeDescriptor(String desc) {
+ // don't deal with generics
+ // this is just for raw jvm types
+ if (desc.charAt(0) == 'T' || desc.indexOf('<') >= 0 || desc.indexOf('>') >= 0) {
+ throw new IllegalArgumentException("don't use with generic types or templates: " + desc);
+ }
+
+ this.desc = desc;
+ }
+
+ public static String parseFirst(String in) {
+
+ if (in == null || in.length() <= 0) {
+ throw new IllegalArgumentException("No desc to parse, input is empty!");
+ }
+
+ // read one desc from the input
+
+ char c = in.charAt(0);
+
+ // first check for void
+ if (c == 'V') {
+ return "V";
+ }
+
+ // then check for primitives
+ Primitive primitive = Primitive.get(c);
+ if (primitive != null) {
+ return in.substring(0, 1);
+ }
+
+ // then check for classes
+ if (c == 'L') {
+ return readClass(in);
+ }
+
+ // then check for templates
+ if (c == 'T') {
+ return readClass(in);
+ }
+
+ // then check for arrays
+ int dim = countArrayDimension(in);
+ if (dim > 0) {
+ String arrayType = TypeDescriptor.parseFirst(in.substring(dim));
+ return in.substring(0, dim + arrayType.length());
+ }
+
+ throw new IllegalArgumentException("don't know how to parse: " + in);
+ }
+
+ private static int countArrayDimension(String in) {
+ int i = 0;
+ while (i < in.length() && in.charAt(i) == '[')
+ i++;
+ return i;
+ }
+
+ private static String readClass(String in) {
+ // read all the characters in the buffer until we hit a ';'
+ // include the parameters too
+ StringBuilder buf = new StringBuilder();
+ int depth = 0;
+ for (int i = 0; i < in.length(); i++) {
+ char c = in.charAt(i);
+ buf.append(c);
+
+ if (c == '<') {
+ depth++;
+ } else if (c == '>') {
+ depth--;
+ } else if (depth == 0 && c == ';') {
+ return buf.toString();
+ }
+ }
+ return null;
+ }
+
+ public static TypeDescriptor of(String name) {
+ return new TypeDescriptor("L" + name + ";");
+ }
+
+ @Override
+ public String toString() {
+ return this.desc;
+ }
+
+ public boolean isVoid() {
+ return this.desc.length() == 1 && this.desc.charAt(0) == 'V';
+ }
+
+ public boolean isPrimitive() {
+ return this.desc.length() == 1 && Primitive.get(this.desc.charAt(0)) != null;
+ }
+
+ public Primitive getPrimitive() {
+ if (!isPrimitive()) {
+ throw new IllegalStateException("not a primitive");
+ }
+ return Primitive.get(this.desc.charAt(0));
+ }
+
+ public boolean isType() {
+ return this.desc.charAt(0) == 'L' && this.desc.charAt(this.desc.length() - 1) == ';';
+ }
+
+ public ClassEntry getOwnerEntry() {
+ if (isType()) {
+ String name = this.desc.substring(1, this.desc.length() - 1);
+
+ int pos = name.indexOf('<');
+ if (pos >= 0) {
+ // remove the parameters from the class name
+ name = name.substring(0, pos);
+ }
+
+ return new ClassEntry(name);
+
+ } else if (isArray() && getArrayType().isType()) {
+ return getArrayType().getOwnerEntry();
+ } else {
+ throw new IllegalStateException("desc doesn't have a class");
+ }
+ }
+
+ public boolean isArray() {
+ return this.desc.charAt(0) == '[';
+ }
+
+ public int getArrayDimension() {
+ if (!isArray()) {
+ throw new IllegalStateException("not an array");
+ }
+ return countArrayDimension(this.desc);
+ }
+
+ public TypeDescriptor getArrayType() {
+ if (!isArray()) {
+ throw new IllegalStateException("not an array");
+ }
+ return new TypeDescriptor(this.desc.substring(getArrayDimension(), this.desc.length()));
+ }
+
+ public boolean containsType() {
+ return isType() || (isArray() && getArrayType().containsType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof TypeDescriptor && equals((TypeDescriptor) other);
+ }
+
+ public boolean equals(TypeDescriptor other) {
+ return this.desc.equals(other.desc);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.desc.hashCode();
+ }
+
+ public TypeDescriptor remap(Function remapper) {
+ String desc = this.desc;
+ if (isType() || (isArray() && containsType())) {
+ String replacedName = remapper.apply(this.getOwnerEntry().getName());
+ if (replacedName != null) {
+ if (this.isType()) {
+ desc = "L" + replacedName + ";";
+ } else {
+ desc = getArrayPrefix(this.getArrayDimension()) + "L" + replacedName + ";";
+ }
+ }
+ }
+ return new TypeDescriptor(desc);
+ }
+
+ private static String getArrayPrefix(int dimension) {
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < dimension; i++) {
+ buf.append("[");
+ }
+ return buf.toString();
+ }
+
+ public enum Primitive {
+ Byte('B'),
+ Character('C'),
+ Short('S'),
+ Integer('I'),
+ Long('J'),
+ Float('F'),
+ Double('D'),
+ Boolean('Z');
+
+ private static final Map lookup;
+
+ static {
+ lookup = Maps.newTreeMap();
+ for (Primitive val : values()) {
+ lookup.put(val.getCode(), val);
+ }
+ }
+
+ private char code;
+
+ Primitive(char code) {
+ this.code = code;
+ }
+
+ public static Primitive get(char code) {
+ return lookup.get(code);
+ }
+
+ public char getCode() {
+ return this.code;
+ }
+ }
+}
--
cgit v1.2.3