From 5540c815de36e316d0749ce2163f12c61895b327 Mon Sep 17 00:00:00 2001 From: asiekierka Date: Wed, 17 Aug 2016 18:35:12 +0200 Subject: Revert "Removed unused methods" This reverts commit 1742190f784d0d62e7cc869eebafdfe1927e448f. --- .../java/cuchaz/enigma/mapping/ArgumentEntry.java | 6 ++ .../cuchaz/enigma/mapping/ArgumentMapping.java | 5 ++ .../java/cuchaz/enigma/mapping/ClassMapping.java | 87 +++++++++++++++++++++ .../java/cuchaz/enigma/mapping/EntryFactory.java | 20 +++++ src/main/java/cuchaz/enigma/mapping/EntryPair.java | 22 ++++++ .../java/cuchaz/enigma/mapping/FieldMapping.java | 39 ++++++++++ src/main/java/cuchaz/enigma/mapping/Mappings.java | 44 +++++++++++ .../enigma/mapping/MappingsEnigmaReader.java | 6 +- .../cuchaz/enigma/mapping/MappingsRenamer.java | 40 ++++++++++ .../java/cuchaz/enigma/mapping/MemberMapping.java | 2 + .../java/cuchaz/enigma/mapping/MethodMapping.java | 50 ++++++++++++ .../java/cuchaz/enigma/mapping/NameValidator.java | 11 +++ .../cuchaz/enigma/mapping/SignatureUpdater.java | 91 ++++++++++++++++++++++ .../java/cuchaz/enigma/mapping/Translator.java | 8 ++ 14 files changed, 428 insertions(+), 3 deletions(-) create mode 100644 src/main/java/cuchaz/enigma/mapping/EntryPair.java create mode 100644 src/main/java/cuchaz/enigma/mapping/SignatureUpdater.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 index 1409fc4..741849a 100644 --- a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java @@ -34,6 +34,12 @@ public class ArgumentEntry implements Entry { 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; diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java index 918395f..d117de0 100644 --- a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java @@ -21,6 +21,11 @@ public class ArgumentMapping implements Comparable { this.name = NameValidator.validateArgumentName(name); } + public ArgumentMapping(ArgumentMapping other) { + this.index = other.index; + this.name = other.name; + } + public int getIndex() { return this.index; } diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java index b2c076a..36b35f7 100644 --- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java @@ -12,6 +12,7 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Maps; +import java.util.ArrayList; import java.util.Map; import cuchaz.enigma.throwables.MappingConflict; @@ -119,6 +120,15 @@ public class ClassMapping implements Comparable { return classMapping; } + public String getDeobfInnerClassName(String obfSimpleName) { + assert (isSimpleClassName(obfSimpleName)); + ClassMapping classMapping = m_innerClassesByObfSimple.get(obfSimpleName); + if (classMapping != null) { + return classMapping.getDeobfName(); + } + return null; + } + public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) { ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass); if (classMapping.getDeobfName() != null) { @@ -149,6 +159,10 @@ public class ClassMapping implements Comparable { return m_fieldsByObf.values(); } + public boolean containsObfField(String obfName, Type obfType) { + return m_fieldsByObf.containsKey(getFieldKey(obfName, obfType)); + } + public boolean containsDeobfField(String deobfName, Type deobfType) { return m_fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType)); } @@ -182,6 +196,10 @@ public class ClassMapping implements Comparable { return m_fieldsByObf.get(getFieldKey(obfName, obfType)); } + public FieldMapping getFieldByDeobf(String deobfName, Type obfType) { + return m_fieldsByDeobf.get(getFieldKey(deobfName, obfType)); + } + public String getObfFieldName(String deobfName, Type obfType) { FieldMapping fieldMapping = m_fieldsByDeobf.get(getFieldKey(deobfName, obfType)); if (fieldMapping != null) { @@ -227,6 +245,16 @@ public class ClassMapping implements Comparable { } } + public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) { + assert(newObfName != null); + FieldMapping fieldMapping = m_fieldsByObf.remove(getFieldKey(oldObfName, obfType)); + assert(fieldMapping != null); + fieldMapping.setObfName(newObfName); + fieldMapping.setObfType(newObfType); + boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null; + assert(obfWasAdded); + } + //// METHODS //////// public Iterable methods() { @@ -234,6 +262,10 @@ public class ClassMapping implements Comparable { return m_methodsByObf.values(); } + public boolean containsObfMethod(String obfName, Signature obfSignature) { + return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature)); + } + public boolean containsDeobfMethod(String deobfName, Signature obfSignature) { return m_methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature)); } @@ -298,6 +330,16 @@ public class ClassMapping implements Comparable { } } + public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) { + assert(newObfName != null); + MethodMapping methodMapping = m_methodsByObf.remove(getMethodKey(oldObfName, obfSignature)); + assert(methodMapping != null); + methodMapping.setObfName(newObfName); + methodMapping.setObfSignature(newObfSignature); + boolean obfWasAdded = m_methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null; + assert(obfWasAdded); + } + //// ARGUMENTS //////// public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) { @@ -360,6 +402,48 @@ public class ClassMapping implements Comparable { return m_obfFullName.compareTo(other.m_obfFullName); } + public boolean renameObfClass(String oldObfClassName, String newObfClassName) { + + // rename inner classes + for (ClassMapping innerClassMapping : new ArrayList<>(m_innerClassesByObfSimple.values())) { + if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { + boolean wasRemoved = m_innerClassesByObfSimple.remove(oldObfClassName) != null; + assert (wasRemoved); + boolean wasAdded = m_innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null; + assert (wasAdded); + } + } + + // rename field types + for (FieldMapping fieldMapping : new ArrayList<>(m_fieldsByObf.values())) { + String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()); + if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) { + boolean wasRemoved = m_fieldsByObf.remove(oldFieldKey) != null; + assert (wasRemoved); + boolean wasAdded = m_fieldsByObf.put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null; + assert (wasAdded); + } + } + + // rename method signatures + for (MethodMapping methodMapping : new ArrayList<>(m_methodsByObf.values())) { + String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); + if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) { + boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null; + assert (wasRemoved); + boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null; + assert (wasAdded); + } + } + + if (m_obfFullName.equals(oldObfClassName)) { + // rename this class + m_obfFullName = newObfClassName; + return true; + } + return false; + } + public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature())); return methodMapping != null && methodMapping.containsArgument(name); @@ -369,4 +453,7 @@ public class ClassMapping implements Comparable { return name.indexOf('/') < 0 && name.indexOf('$') < 0; } + public ClassEntry getObfEntry() { + return new ClassEntry(m_obfFullName); + } } diff --git a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java index 2351dcf..ce4b948 100644 --- a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java +++ b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java @@ -33,6 +33,10 @@ public class EntryFactory { 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())); } @@ -90,6 +94,10 @@ public class EntryFactory { 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)); } @@ -105,7 +113,19 @@ public class EntryFactory { } } + 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/EntryPair.java b/src/main/java/cuchaz/enigma/mapping/EntryPair.java new file mode 100644 index 0000000..1c93d53 --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/EntryPair.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * 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 EntryPair { + + public T obf; + public T deobf; + + public EntryPair(T obf, T deobf) { + this.obf = obf; + this.deobf = deobf; + } +} diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java index 3ec1af0..1b59660 100644 --- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java @@ -22,6 +22,17 @@ public class FieldMapping implements Comparable, MemberMapping, MemberMapping(classes()).stream().filter(classMapping -> classMapping.renameObfClass(oldObfName, newObfName)).forEach(classMapping -> { + boolean wasRemoved = this.classesByObf.remove(oldObfName) != null; + assert (wasRemoved); + boolean wasAdded = this.classesByObf.put(newObfName, classMapping) == null; + assert (wasAdded); + }); + } + + public Set getAllObfClassNames() { + final Set classNames = Sets.newHashSet(); + for (ClassMapping classMapping : classes()) { + + // add the class name + classNames.add(classMapping.getObfFullName()); + + // add classes from method signatures + for (MethodMapping methodMapping : classMapping.methods()) { + for (Type type : methodMapping.getObfSignature().types()) { + if (type.hasClass()) { + classNames.add(type.getClassEntry().getClassName()); + } + } + } + } + return classNames; + } + public boolean containsDeobfClass(String deobfName) { return this.classesByDeobf.containsKey(deobfName); } diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java index 70f3f18..a27f72e 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java @@ -85,7 +85,7 @@ public class MappingsEnigmaReader ClassMapping classMapping; if (indent <= 0) { // outer class - classMapping = readClass(parts); + classMapping = readClass(parts, false); mappings.addClassMapping(classMapping); } else { @@ -94,7 +94,7 @@ public class MappingsEnigmaReader throw new MappingParseException(lineNumber, "Unexpected CLASS entry here!"); } - classMapping = readClass(parts); + classMapping = readClass(parts, true); ((ClassMapping) mappingStack.peek()).addInnerClassMapping(classMapping); } mappingStack.push(classMapping); @@ -130,7 +130,7 @@ public class MappingsEnigmaReader return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]); } - private ClassMapping readClass(String[] parts) { + private ClassMapping readClass(String[] parts, boolean makeSimple) { if (parts.length == 2) { return new ClassMapping(parts[1]); } else { diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java index afb8c97..8002813 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java @@ -10,8 +10,12 @@ ******************************************************************************/ package cuchaz.enigma.mapping; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.util.List; import java.util.Set; +import java.util.zip.GZIPOutputStream; import cuchaz.enigma.analysis.JarIndex; import cuchaz.enigma.throwables.IllegalNameException; @@ -165,6 +169,42 @@ public class MappingsRenamer { classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), 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())) { + targetClassMapping.addFieldMapping(fieldMapping); + return true; + } else { + System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName()); + } + } + return false; + } + + 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())) { + targetClassMapping.addMethodMapping(methodMapping); + return true; + } else { + System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature()); + } + } + return false; + } + + public void write(OutputStream out) throws IOException { + // TEMP: just use the object output for now. We can find a more efficient storage format later + GZIPOutputStream gzipout = new GZIPOutputStream(out); + ObjectOutputStream oout = new ObjectOutputStream(gzipout); + oout.writeObject(this); + gzipout.finish(); + } + private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { List mappingChain = getOrCreateClassMappingChain(obfClassEntry); return mappingChain.get(mappingChain.size() - 1); diff --git a/src/main/java/cuchaz/enigma/mapping/MemberMapping.java b/src/main/java/cuchaz/enigma/mapping/MemberMapping.java index 590c830..90c096f 100644 --- a/src/main/java/cuchaz/enigma/mapping/MemberMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/MemberMapping.java @@ -12,5 +12,7 @@ package cuchaz.enigma.mapping; public interface MemberMapping { + T getObfEntry(ClassEntry classEntry); + String getObfName(); } diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java index 6e7c1ef..99b9c88 100644 --- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java @@ -39,6 +39,16 @@ public class MethodMapping implements Comparable, MemberMapping entry : other.arguments.entrySet()) { + this.arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue())); + } + } @Override public String getObfName() { @@ -57,6 +67,14 @@ public class MethodMapping implements Comparable, MemberMapping arguments() { return this.arguments.values(); } @@ -137,4 +155,36 @@ public class MethodMapping implements Comparable, MemberMapping + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.mapping; + +import com.google.common.collect.Lists; + +import java.io.IOException; +import java.io.StringReader; +import java.util.List; + +public class SignatureUpdater { + + public interface ClassNameUpdater { + String update(String className); + } + + public static String update(String signature, ClassNameUpdater updater) { + try { + StringBuilder buf = new StringBuilder(); + + // read the signature character-by-character + StringReader reader = new StringReader(signature); + int i; + while ((i = reader.read()) != -1) { + char c = (char) i; + + // does this character start a class name? + if (c == 'L') { + // update the class name and add it to the buffer + buf.append('L'); + String className = readClass(reader); + if (className == null) { + throw new IllegalArgumentException("Malformed signature: " + signature); + } + buf.append(updater.update(className)); + buf.append(';'); + } else { + // copy the character into the buffer + buf.append(c); + } + } + + return buf.toString(); + } catch (IOException ex) { + // I'm pretty sure a StringReader will never throw one of these + throw new Error(ex); + } + } + + private static String readClass(StringReader reader) throws IOException { + // read all the characters in the buffer until we hit a ';' + // remember to treat generics correctly + StringBuilder buf = new StringBuilder(); + int depth = 0; + int i; + while ((i = reader.read()) != -1) { + char c = (char) i; + + if (c == '<') { + depth++; + } else if (c == '>') { + depth--; + } else if (depth == 0) { + if (c == ';') { + return buf.toString(); + } else { + buf.append(c); + } + } + } + + return null; + } + + public static List getClasses(String signature) { + final List classNames = Lists.newArrayList(); + update(signature, className -> { + classNames.add(className); + return className; + }); + return classNames; + } +} diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java index 125e03f..bebac4e 100644 --- a/src/main/java/cuchaz/enigma/mapping/Translator.java +++ b/src/main/java/cuchaz/enigma/mapping/Translator.java @@ -38,6 +38,14 @@ public class Translator { this.index = index; } + public TranslationDirection getDirection() { + return direction; + } + + public TranslationIndex getTranslationIndex() { + return index; + } + @SuppressWarnings("unchecked") public T translateEntry(T entry) { if (entry instanceof ClassEntry) { -- cgit v1.2.3