From f829582ae418504ff6685eeb14fad5a67916c6f9 Mon Sep 17 00:00:00 2001 From: Thog Date: Fri, 24 Mar 2017 01:28:34 +0100 Subject: Implement experimental Tiny mappings loader ~ This will need some tests and more security checks --- .../java/cuchaz/enigma/mapping/ClassMapping.java | 13 +++ src/main/java/cuchaz/enigma/mapping/Mappings.java | 2 +- .../cuchaz/enigma/mapping/MappingsTinyReader.java | 99 ++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java (limited to 'src/main/java/cuchaz/enigma/mapping') diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java index 178dd3c..1d1f558 100644 --- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java @@ -23,6 +23,7 @@ public class ClassMapping implements Comparable { private String obfFullName; private String obfSimpleName; private String deobfName; + private String deobfFullName; private String previousDeobfName; private Map innerClassesByObfSimple; private Map innerClassesByObfFull; @@ -33,6 +34,7 @@ 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); @@ -497,6 +499,10 @@ public class ClassMapping implements Comparable { return new ClassEntry(obfFullName); } + public ClassEntry getDeObfEntry() { + return deobfFullName != null ? new ClassEntry(deobfFullName) : null; + } + public boolean isDirty() { return isDirty; } @@ -534,4 +540,11 @@ public class ClassMapping implements Comparable { this.isDirty = true; } } + + // Used for tiny parsing to keep track of deobfuscate inner classes + public ClassMapping setDeobInner(String deobName) + { + this.deobfFullName = deobName; + return this; + } } diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java index 8aa463f..cf78ca3 100644 --- a/src/main/java/cuchaz/enigma/mapping/Mappings.java +++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java @@ -230,7 +230,7 @@ public class Mappings { } public enum FormatType { - ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE + ENIGMA_FILE, ENIGMA_DIRECTORY, TINY_FILE, SRG_FILE } public enum EntryModifier { diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java new file mode 100644 index 0000000..b2ba191 --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/MappingsTinyReader.java @@ -0,0 +1,99 @@ +package cuchaz.enigma.mapping; + +import com.google.common.base.Charsets; +import com.google.common.collect.Maps; +import cuchaz.enigma.throwables.MappingConflict; +import cuchaz.enigma.throwables.MappingParseException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class MappingsTinyReader { + public ClassMapping readClass(String[] parts) { + // Extract the inner naming of the deob form if it have one + String deobName = parts[2].contains("$") ? parts[2].substring(parts[2].lastIndexOf('$') + 1) : parts[2]; + return new ClassMapping(parts[1], deobName).setDeobInner(parts[2]); + } + + public FieldMapping readField(String[] parts) { + return new FieldMapping(parts[3], new Type(parts[2]), parts[4], Mappings.EntryModifier.UNCHANGED); + } + + public MethodMapping readMethod(String[] parts) { + return new MethodMapping(parts[3], new Signature(parts[2]), parts[4]); + } + + public Mappings read(File file) throws IOException, MappingParseException { + Mappings mappings = new Mappings(Mappings.FormatType.TINY_FILE); + System.out.println(file); + List lines = Files.readAllLines(file.toPath(), Charsets.UTF_8); + Map classMappingMap = Maps.newHashMap(); + String header = lines.remove(0); + for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { + String line = lines.get(lineNumber); + String[] parts = line.split("\\s"); + try { + String token = parts[0]; + ClassMapping classMapping; + switch (token) { + case "CLASS": + if (classMappingMap.containsKey(parts[1])) { + classMapping = classMappingMap.get(parts[1]); + String deobName = parts[2].contains("$") ? + parts[2].substring(parts[2].lastIndexOf('$') + 1) : + parts[2]; + classMappingMap.put(parts[2], classMapping.setDeobInner(parts[2])); + classMapping.setDeobfName(deobName); + classMapping.resetDirty(); + } else + classMapping = readClass(parts); + classMappingMap.put(parts[1], classMapping); + break; + case "FIELD": + classMapping = classMappingMap.computeIfAbsent(parts[1], k -> new ClassMapping(parts[1])); + //throw new MappingParseException(file, lineNumber, "Cannot find class '" + parts[1] + "' declaration!"); + classMapping.addFieldMapping(readField(parts)); + break; + case "METHOD": + classMapping = classMappingMap.computeIfAbsent(parts[1], k -> new ClassMapping(parts[1])); + //throw new MappingParseException(file, lineNumber, "Cannot find class '" + parts[1] + "' declaration!"); + classMapping.addMethodMapping(readMethod(parts)); + break; + default: + throw new MappingParseException(file, lineNumber, "Unknown token '" + token + "' !"); + } + } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException ex) { + throw new MappingParseException(file, lineNumber, "Malformed line:\n" + line); + } + } + + List toRegister = new ArrayList<>(classMappingMap.values()); + for (ClassMapping classMapping : toRegister) { + ClassEntry obEntry = classMapping.getObfEntry(); + ClassEntry deobEntry = classMapping.getDeObfEntry(); + try { + if (obEntry.isInnerClass()) { + ClassMapping parent = classMappingMap.get(obEntry.getOuterClassName()); + if (parent == null) { + parent = new ClassMapping(obEntry.getOuterClassName()); + classMappingMap.put(obEntry.getOuterClassName(), parent); + mappings.addClassMapping(parent); + } + parent.addInnerClassMapping(classMapping); + } else if (deobEntry != null && deobEntry.isInnerClass()) + classMappingMap.get(deobEntry.getOuterClassName()).addInnerClassMapping(classMapping); + else + mappings.addClassMapping(classMapping); + } catch (MappingConflict e) { + throw new MappingParseException(file, -1, e.getMessage()); + } + } + lines.clear(); + classMappingMap.clear(); + return mappings; + } +} -- cgit v1.2.3