From a88175ffc95792b88a8724f66db6dda2b8cc32ee Mon Sep 17 00:00:00 2001
From: gegy1000
Date: Tue, 17 Jul 2018 19:14:08 +0200
Subject: ASM Based Class Translator (#1)
* Initial port to ASM
* Package updates
* Annotation + inner class translation
* Fix inner class mapping
* More bytecode translation
* Signature refactoring
* Fix highlighting of mapped names
* Fix parameter name offset
* Fix anonymous class generation
* Fix issues with inner class signature transformation
* Fix bridged method detection
* Fix compile issues
* Resolve all failed tests
* Apply deobfuscated name to transformed classes
* Fix class signatures not being translated
* Fix frame array type translation
* Fix frame array type translation
* Fix array translation in method calls
* Fix method reference and bridge detection
* Fix handling of null deobf mappings
* Parameter translation in interfaces
* Fix enum parameter index offset
* Fix parsed local variable indexing
* Fix stackoverflow on rebuilding method names
* Ignore invalid decompiled variable indices
* basic source jar
* Output directly to file on source export
* Make decompile parallel
* fix incorrect super calls
* Use previous save state to delete old mapping files
* Fix old mappings not properly being removed
* Fix old mappings not properly being removed
* make isMethodProvider public
(cherry picked from commit ebad6a9)
* speed up Deobfuscator's getSources by using a single TranslatingTypeloader and caching the ClassLoaderTypeloader
* ignore .idea project folders
* move SynchronizedTypeLoader to a non-inner
* fix signature remap of inners for now
* index & resolve method/field references for usages view
* Allow reader/writer subclasses to provide the underlying file operations
* fix giving obf classes a name not removing them from the panel
* buffer the ParsedJar class entry inputstream, allow use with a jarinputstream
* make CachingClasspathTypeLoader public
* make CachingClasspathTypeLoader public
* support enum switches with obfuscated SwitchMaps
---
.../java/cuchaz/enigma/mapping/ArgumentEntry.java | 110 ------
.../cuchaz/enigma/mapping/ArgumentMapping.java | 50 ---
.../java/cuchaz/enigma/mapping/BehaviorEntry.java | 16 -
.../java/cuchaz/enigma/mapping/ClassEntry.java | 167 ----------
.../java/cuchaz/enigma/mapping/ClassMapping.java | 210 +++++++-----
.../cuchaz/enigma/mapping/ClassNameReplacer.java | 16 -
.../cuchaz/enigma/mapping/ConstructorEntry.java | 105 ------
.../enigma/mapping/DirectionalTranslator.java | 370 +++++++++++++++++++++
src/main/java/cuchaz/enigma/mapping/Entry.java | 22 --
.../java/cuchaz/enigma/mapping/EntryFactory.java | 132 --------
.../java/cuchaz/enigma/mapping/FieldEntry.java | 87 -----
.../java/cuchaz/enigma/mapping/FieldMapping.java | 38 +--
.../cuchaz/enigma/mapping/LocalVariableEntry.java | 102 ------
.../enigma/mapping/LocalVariableMapping.java | 53 +++
src/main/java/cuchaz/enigma/mapping/Mappings.java | 58 +++-
.../cuchaz/enigma/mapping/MappingsChecker.java | 14 +-
.../enigma/mapping/MappingsEnigmaReader.java | 167 +++++-----
.../enigma/mapping/MappingsEnigmaWriter.java | 124 +++----
.../cuchaz/enigma/mapping/MappingsRenamer.java | 164 +++++----
.../cuchaz/enigma/mapping/MappingsSRGWriter.java | 7 +-
.../cuchaz/enigma/mapping/MappingsTinyReader.java | 7 +-
.../java/cuchaz/enigma/mapping/MemberMapping.java | 3 +
.../cuchaz/enigma/mapping/MethodDescriptor.java | 114 +++++++
.../java/cuchaz/enigma/mapping/MethodEntry.java | 90 -----
.../java/cuchaz/enigma/mapping/MethodMapping.java | 139 ++++----
.../java/cuchaz/enigma/mapping/NameValidator.java | 16 +-
.../cuchaz/enigma/mapping/ProcyonEntryFactory.java | 67 ----
src/main/java/cuchaz/enigma/mapping/Signature.java | 128 +++----
.../enigma/mapping/TranslationDirection.java | 10 +-
.../java/cuchaz/enigma/mapping/Translator.java | 365 ++++----------------
src/main/java/cuchaz/enigma/mapping/Type.java | 235 -------------
.../java/cuchaz/enigma/mapping/TypeDescriptor.java | 244 ++++++++++++++
.../cuchaz/enigma/mapping/entry/ClassDefEntry.java | 37 +++
.../cuchaz/enigma/mapping/entry/ClassEntry.java | 175 ++++++++++
.../java/cuchaz/enigma/mapping/entry/Entry.java | 22 ++
.../cuchaz/enigma/mapping/entry/EntryFactory.java | 49 +++
.../cuchaz/enigma/mapping/entry/FieldDefEntry.java | 43 +++
.../cuchaz/enigma/mapping/entry/FieldEntry.java | 77 +++++
.../mapping/entry/LocalVariableDefEntry.java | 57 ++++
.../enigma/mapping/entry/LocalVariableEntry.java | 82 +++++
.../enigma/mapping/entry/MethodDefEntry.java | 54 +++
.../cuchaz/enigma/mapping/entry/MethodEntry.java | 80 +++++
.../enigma/mapping/entry/ProcyonEntryFactory.java | 48 +++
.../enigma/mapping/entry/ReferencedEntryPool.java | 53 +++
44 files changed, 2203 insertions(+), 2004 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
delete mode 100644 src/main/java/cuchaz/enigma/mapping/ClassEntry.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
delete mode 100644 src/main/java/cuchaz/enigma/mapping/Entry.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/EntryFactory.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/FieldEntry.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/LocalVariableMapping.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/MethodDescriptor.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/MethodEntry.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
delete mode 100644 src/main/java/cuchaz/enigma/mapping/Type.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/TypeDescriptor.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/ClassDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/ClassEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/Entry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/EntryFactory.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/FieldDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/FieldEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/LocalVariableDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/LocalVariableEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/MethodDefEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/MethodEntry.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/ProcyonEntryFactory.java
create mode 100644 src/main/java/cuchaz/enigma/mapping/entry/ReferencedEntryPool.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/ClassEntry.java b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
deleted file mode 100644
index 788811f..0000000
--- a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
+++ /dev/null
@@ -1,167 +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 java.util.List;
-
-public class ClassEntry implements Entry {
-
- private String name;
-
- public ClassEntry(String className) {
- if (className == null) {
- throw new IllegalArgumentException("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);
- }
-
- this.name = className;
-
- if (isInnerClass() && getInnermostClassName().indexOf('/') >= 0) {
- throw new IllegalArgumentException("Inner class must not have a package: " + className);
- }
- }
-
- public ClassEntry(ClassEntry other) {
- this.name = other.name;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public String getClassName() {
- return this.name;
- }
-
- @Override
- public ClassEntry getClassEntry() {
- return this;
- }
-
- @Override
- public ClassEntry cloneToNewClass(ClassEntry classEntry) {
- return classEntry;
- }
-
- @Override
- public int hashCode() {
- return this.name.hashCode();
- }
-
- @Override
- public boolean equals(Object other) {
- return other instanceof ClassEntry && equals((ClassEntry) other);
- }
-
- public boolean equals(ClassEntry other) {
- return other != null && this.name.equals(other.name);
- }
-
- @Override
- public String toString() {
- return this.name;
- }
-
- public boolean isInnerClass() {
- return this.name.lastIndexOf('$') >= 0;
- }
-
- public List getClassChainNames() {
- return Lists.newArrayList(this.name.split("\\$"));
- }
-
- public List getClassChain() {
- List entries = Lists.newArrayList();
- StringBuilder buf = new StringBuilder();
- for (String name : getClassChainNames()) {
- if (buf.length() > 0) {
- buf.append("$");
- }
- buf.append(name);
- entries.add(new ClassEntry(buf.toString()));
- }
- return entries;
- }
-
- public String getOutermostClassName() {
- if (isInnerClass()) {
- return this.name.substring(0, this.name.indexOf('$'));
- }
- return this.name;
- }
-
- public ClassEntry getOutermostClassEntry() {
- return new ClassEntry(getOutermostClassName());
- }
-
- public String getOuterClassName() {
- if (!isInnerClass()) {
- throw new Error("This is not an inner class!");
- }
- return this.name.substring(0, this.name.lastIndexOf('$'));
- }
-
- public ClassEntry getOuterClassEntry() {
- return new ClassEntry(getOuterClassName());
- }
-
- public String getInnermostClassName() {
- if (!isInnerClass()) {
- throw new Error("This is not an inner class!");
- }
- return this.name.substring(this.name.lastIndexOf('$') + 1);
- }
-
- public boolean isInDefaultPackage() {
- return this.name.indexOf('/') < 0;
- }
-
- public String getPackageName() {
- int pos = this.name.lastIndexOf('/');
- if (pos > 0) {
- return this.name.substring(0, pos);
- }
- return null;
- }
-
- public String getSimpleName() {
- int pos = this.name.lastIndexOf('/');
- if (pos > 0) {
- return this.name.substring(pos + 1);
- }
- return this.name;
- }
-
- public ClassEntry buildClassEntry(List classChain) {
- assert (classChain.contains(this));
- StringBuilder buf = new StringBuilder();
- for (ClassEntry chainEntry : classChain) {
- if (buf.length() == 0) {
- buf.append(chainEntry.getName());
- } else {
- buf.append("$");
- buf.append(chainEntry.isInnerClass() ? chainEntry.getInnermostClassName() : chainEntry.getSimpleName());
- }
-
- if (chainEntry == this) {
- break;
- }
- }
- return new ClassEntry(buf.toString());
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
index 51751ca..8f3f2b2 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
@@ -12,6 +12,9 @@
package cuchaz.enigma.mapping;
import com.google.common.collect.Maps;
+import cuchaz.enigma.mapping.entry.ClassEntry;
+import cuchaz.enigma.mapping.entry.FieldEntry;
+import cuchaz.enigma.mapping.entry.MethodEntry;
import cuchaz.enigma.throwables.MappingConflict;
import java.util.ArrayList;
@@ -34,7 +37,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 +83,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 +197,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 +224,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 +292,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 +308,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());
+ if (!methodMapping.isObfuscated()) {
+ String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc());
if (methodsByDeobf.containsKey(deobfKey)) {
throw new Error("Already have mapping for " + deobfName + "." + deobfKey);
}
@@ -326,44 +336,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;
+ if (!methodMapping.isObfuscated()) {
+ 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);
- } else if (methodMapping.getDeobfName() != null) {
- boolean wasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
+ methodMapping = createMethodMapping(obfName, obfDescriptor);
+ } else if (!methodMapping.isObfuscated()) {
+ 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 +385,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 +473,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 +504,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() {
@@ -503,6 +517,14 @@ public class ClassMapping implements Comparable {
return deobfFullName != null ? new ClassEntry(deobfFullName) : null;
}
+ public boolean isObfuscated() {
+ return this.deobfName == null || this.deobfName.equals(this.obfFullName);
+ }
+
+ public String getSaveName() {
+ return this.isObfuscated() ? this.obfFullName : this.deobfName;
+ }
+
public boolean isDirty() {
return isDirty;
}
@@ -511,6 +533,10 @@ public class ClassMapping implements Comparable {
this.isDirty = false;
}
+ public void markDirty() {
+ this.isDirty = true;
+ }
+
public Mappings.EntryModifier getModifier() {
return modifier;
}
@@ -521,9 +547,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 +557,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));
@@ -546,4 +572,30 @@ public class ClassMapping implements Comparable {
this.deobfFullName = deobName;
return this;
}
+
+ public ClassMapping copy() {
+ ClassMapping copied = new ClassMapping(this.obfFullName);
+ copied.obfSimpleName= this.obfSimpleName;
+ copied.modifier = this.modifier;
+ copied.deobfFullName = this.deobfFullName;
+ copied.deobfName = this.deobfName;
+ copied.innerClassesByDeobf = this.innerClassesByDeobf;
+ copied.innerClassesByObfFull = this.innerClassesByObfFull;
+ copied.innerClassesByObfSimple = this.innerClassesByObfSimple;
+ copied.fieldsByObf = this.fieldsByObf;
+ copied.fieldsByDeobf = this.fieldsByDeobf;
+ copied.methodsByObf = this.methodsByObf;
+ copied.methodsByDeobf = this.methodsByDeobf;
+ return copied;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.obfFullName.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ClassMapping && ((ClassMapping) obj).obfFullName.equals(this.obfFullName);
+ }
}
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..b0bb129
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * 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 cuchaz.enigma.mapping.entry.*;
+
+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;
+ if (entry.isArray()) {
+ className = this.getTranslatedTypeDesc(new TypeDescriptor(entry.getName())).toString();
+ } else {
+ className = entry.isInnerClass() ? translateInnerClassName(entry) : translateClassName(entry);
+ }
+ return new ClassEntry(className);
+ }
+
+ @Override
+ public ClassDefEntry getTranslatedClassDef(ClassDefEntry entry) {
+ String className;
+ if (entry.isArray()) {
+ className = this.getTranslatedTypeDesc(new TypeDescriptor(entry.getName())).toString();
+ } else {
+ className = entry.isInnerClass() ? translateInnerClassName(entry) : translateClassName(entry);
+ }
+ Signature translatedSignature = this.getTranslatedSignature(entry.getSignature());
+ return new ClassDefEntry(className, translatedSignature, 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) {
+ translatedName = entry.getName();
+ }
+ ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry());
+ TypeDescriptor translatedDesc = getTranslatedTypeDesc(entry.getDesc());
+ Signature translatedSignature = getTranslatedSignature(entry.getSignature());
+ AccessFlags translatedAccess = getFieldModifier(entry).transform(entry.getAccess());
+ return new FieldDefEntry(translatedOwner, translatedName, translatedDesc, translatedSignature, translatedAccess);
+ }
+
+ @Override
+ public FieldEntry getTranslatedField(FieldEntry entry) {
+ String translatedName = translateFieldName(entry);
+ if (translatedName == null) {
+ translatedName = entry.getName();
+ }
+ 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, true);
+ if (resolvedClassEntry != null) {
+ // look for the class
+ ClassMapping classMapping = findClassMapping(resolvedClassEntry);
+ if (classMapping != null) {
+ // look for the field
+ FieldMapping mapping = this.direction.choose(
+ classMapping.getFieldByObf(entry.getName(), entry.getDesc()),
+ classMapping.getFieldByDeobf(entry.getName(), getTranslatedTypeDesc(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) {
+ translatedName = entry.getName();
+ }
+ ClassEntry translatedOwner = getTranslatedClass(entry.getOwnerClassEntry());
+ MethodDescriptor translatedDesc = getTranslatedMethodDesc(entry.getDesc());
+ Signature translatedSignature = getTranslatedSignature(entry.getSignature());
+ AccessFlags access = getMethodModifier(entry).transform(entry.getAccess());
+ return new MethodDefEntry(translatedOwner, translatedName, translatedDesc, translatedSignature, access);
+ }
+
+ @Override
+ public MethodEntry getTranslatedMethod(MethodEntry entry) {
+ String translatedName = translateMethodName(entry);
+ if (translatedName == null) {
+ translatedName = entry.getName();
+ }
+ 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 = this.direction.choose(
+ classMapping.getMethodByObf(entry.getName(), entry.getDesc()),
+ classMapping.getMethodByDeobf(entry.getName(), getTranslatedMethodDesc(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) {
+ translatedArgumentName = entry.getName();
+ }
+ // 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);
+ }
+ // 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 != null ? translatedArgumentName : entry.getName(), translatedTypeDesc);
+ }
+
+ @Override
+ public boolean hasClassMapping(ClassEntry entry) {
+ return classes.containsKey(entry.getName());
+ }
+
+ @Override
+ public boolean hasFieldMapping(FieldEntry entry) {
+ return translateFieldName(entry) != null;
+ }
+
+ @Override
+ public boolean hasMethodMapping(MethodEntry entry) {
+ return translateMethodName(entry) != null;
+ }
+
+ @Override
+ public boolean hasLocalVariableMapping(LocalVariableEntry entry) {
+ return translateLocalVariableName(entry) != null || inheritLocalVariableName(entry) != null;
+ }
+
+ // 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 = this.direction.choose(
+ classMapping.getMethodByObf(entry.getMethodName(), entry.getMethodDesc()),
+ classMapping.getMethodByDeobf(entry.getMethodName(), getTranslatedMethodDesc(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(this::remapClass);
+ }
+
+ @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()));
+ }
+
+ @Override
+ public Signature getTranslatedSignature(Signature signature) {
+ if (signature == null) {
+ return null;
+ }
+ return signature.remap(this::remapClass);
+ }
+
+ 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;
+ }
+
+ private String remapClass(String name) {
+ return getTranslatedClass(new ClassEntry(name)).getName();
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/mapping/Entry.java b/src/main/java/cuchaz/enigma/mapping/Entry.java
deleted file mode 100644
index c79510b..0000000
--- a/src/main/java/cuchaz/enigma/mapping/Entry.java
+++ /dev/null
@@ -1,22 +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 Entry {
- String getName();
-
- String getClassName();
-
- ClassEntry getClassEntry();
-
- Entry cloneToNewClass(ClassEntry classEntry);
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
deleted file mode 100644
index 993bb64..0000000
--- a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
+++ /dev/null
@@ -1,132 +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.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));
- }
-
- private static ClassEntry getObfClassEntry(ClassMapping classMapping) {
- return new ClassEntry(classMapping.getObfFullName());
- }
-
- public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) {
- 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);
- }
- }
-
- 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 BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) {
- return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
- }
-
- public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) {
- return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping);
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
deleted file mode 100644
index 0f1f506..0000000
--- a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
+++ /dev/null
@@ -1,87 +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 FieldEntry implements Entry {
-
- private ClassEntry classEntry;
- private String name;
- private Type type;
-
- // 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!");
- }
-
- this.classEntry = classEntry;
- this.name = name;
- this.type = type;
- }
-
- public FieldEntry(FieldEntry other, ClassEntry newClassEntry) {
- this.classEntry = newClassEntry;
- this.name = other.name;
- this.type = other.type;
- }
-
- @Override
- public ClassEntry getClassEntry() {
- return this.classEntry;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public String getClassName() {
- return this.classEntry.getName();
- }
-
- public Type getType() {
- return this.type;
- }
-
- @Override
- public FieldEntry cloneToNewClass(ClassEntry classEntry) {
- return new FieldEntry(this, classEntry);
- }
-
- @Override
- public int hashCode() {
- return Utils.combineHashesOrdered(this.classEntry, this.name, this.type);
- }
-
- @Override
- public boolean equals(Object other) {
- return other instanceof FieldEntry && equals((FieldEntry) other);
- }
-
- public boolean equals(FieldEntry other) {
- return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.type.equals(other.type);
- }
-
- @Override
- public String toString() {
- return this.classEntry.getName() + "." + this.name + ":" + this.type;
- }
-}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
index cd761b4..8fbe095 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
@@ -11,32 +11,27 @@
package cuchaz.enigma.mapping;
+import cuchaz.enigma.mapping.entry.ClassEntry;
+import cuchaz.enigma.mapping.entry.FieldEntry;
import cuchaz.enigma.throwables.IllegalNameException;
public class FieldMapping implements Comparable, MemberMapping {
private String obfName;
private String deobfName;
- private Type obfType;
+ private TypeDescriptor obfDesc;
private Mappings.EntryModifier modifier;
- public FieldMapping(String obfName, Type obfType, String deobfName, Mappings.EntryModifier modifier) {
+ public FieldMapping(String obfName, TypeDescriptor obfDesc, String deobfName, Mappings.EntryModifier modifier) {
this.obfName = obfName;
this.deobfName = NameValidator.validateFieldName(deobfName);
- this.obfType = obfType;
+ this.obfDesc = obfDesc;
this.modifier = modifier;
}
- public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) {
- this.obfName = other.obfName;
- this.deobfName = other.deobfName;
- this.modifier = other.modifier;
- this.obfType = new Type(other.obfType, obfClassNameReplacer);
- }
-
@Override
public FieldEntry getObfEntry(ClassEntry classEntry) {
- return new FieldEntry(classEntry, this.obfName, this.obfType);
+ return new FieldEntry(classEntry, this.obfName, this.obfDesc);
}
@Override
@@ -65,12 +60,12 @@ public class FieldMapping implements Comparable, 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/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
deleted file mode 100644
index 2bb5e3f..0000000
--- a/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package cuchaz.enigma.mapping;
-
-import cuchaz.enigma.utils.Utils;
-
-/**
- * Desc...
- * Created by Thog
- * 19/10/2016
- */
-public class LocalVariableEntry implements Entry {
-
- protected final BehaviorEntry behaviorEntry;
- 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;
- 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 int getIndex() {
- return 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 LocalVariableEntry cloneToNewClass(ClassEntry classEntry) {
- return new LocalVariableEntry(this, classEntry);
- }
-
- public String getMethodName() {
- return this.behaviorEntry.getName();
- }
-
- public Signature getMethodSignature() {
- return this.behaviorEntry.getSignature();
- }
-
- @Override
- public int hashCode() {
- return Utils.combineHashesOrdered(this.behaviorEntry, this.type.hashCode(), this.name.hashCode(), Integer.hashCode(this.index));
- }
-
- @Override
- public boolean equals(Object other) {
- return other instanceof LocalVariableEntry && equals((LocalVariableEntry) other);
- }
-
- 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;
- }
-
- @Override
- public String toString() {
- return this.behaviorEntry + "(" + this.index + ":" + this.name + ":" + this.type + ")";
- }
-}
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..62dbcf3
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/LocalVariableMapping.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.mapping.entry.LocalVariableEntry;
+import cuchaz.enigma.mapping.entry.MethodEntry;
+
+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..3ef1be5 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -15,11 +15,15 @@ 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.mapping.entry.ClassEntry;
+import cuchaz.enigma.mapping.entry.MethodEntry;
import cuchaz.enigma.throwables.MappingConflict;
import java.io.File;
import java.io.IOException;
import java.util.*;
+import java.util.stream.Collectors;
public class Mappings {
@@ -96,11 +100,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 +118,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 +155,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.getTypeEntry().getClassName());
}
}
}
@@ -165,9 +169,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 +184,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) {
@@ -210,8 +214,14 @@ public class Mappings {
public void savePreviousState() {
this.previousState = new Mappings(this.originMapping);
- this.previousState.classesByDeobf = Maps.newHashMap(this.classesByDeobf);
- this.previousState.classesByObf = Maps.newHashMap(this.classesByObf);
+ this.previousState.classesByDeobf = new HashMap<>();
+ for (Map.Entry entry : this.classesByDeobf.entrySet()) {
+ this.previousState.classesByDeobf.put(entry.getKey(), entry.getValue().copy());
+ }
+ this.previousState.classesByObf = new HashMap<>();
+ for (Map.Entry entry : this.classesByObf.entrySet()) {
+ this.previousState.classesByObf.put(entry.getKey(), entry.getValue().copy());
+ }
classesByDeobf.values().forEach(ClassMapping::resetDirty);
classesByObf.values().forEach(ClassMapping::resetDirty);
}
@@ -239,5 +249,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..a42f255 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
@@ -14,6 +14,10 @@ package cuchaz.enigma.mapping;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import cuchaz.enigma.analysis.JarIndex;
+import cuchaz.enigma.mapping.entry.ClassEntry;
+import cuchaz.enigma.mapping.entry.EntryFactory;
+import cuchaz.enigma.mapping.entry.FieldEntry;
+import cuchaz.enigma.mapping.entry.MethodEntry;
import java.util.Map;
@@ -23,7 +27,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 +49,7 @@ public class MappingsChecker {
return this.droppedFieldMappings;
}
- public Map getDroppedMethodMappings() {
+ public Map getDroppedMethodMappings() {
return this.droppedMethodMappings;
}
@@ -77,10 +81,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..ddbee76 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
@@ -5,8 +5,14 @@ import com.google.common.collect.Queues;
import cuchaz.enigma.throwables.MappingConflict;
import cuchaz.enigma.throwables.MappingParseException;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.Deque;
+import java.util.function.Supplier;
public class MappingsEnigmaReader {
@@ -39,92 +45,95 @@ public class MappingsEnigmaReader {
}
public Mappings readFile(Mappings mappings, File file) throws IOException, MappingParseException {
+ return readFileStream(mappings, new FileInputStream(file), file::getAbsolutePath);
+ }
- BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8));
- Deque