summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Thog2016-10-30 23:37:29 +0100
committerGravatar Thog2016-10-30 23:37:29 +0100
commit6235bfc5ab85cdd471e315c52c413991fb9dbddf (patch)
treef8d726850a60786176f999952c2e9f7c83e5ccbd
parentFix order of packages, hanging of Enigma and classes nodes not renamed when p... (diff)
downloadenigma-6235bfc5ab85cdd471e315c52c413991fb9dbddf.tar.gz
enigma-6235bfc5ab85cdd471e315c52c413991fb9dbddf.tar.xz
enigma-6235bfc5ab85cdd471e315c52c413991fb9dbddf.zip
BREAKING CHANGE: Implement modifier transformer
Known Bugs: - Inner class modifier isn't saved to mapping - Inner class modifier isn't applied to bytecode
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java21
-rw-r--r--src/main/java/cuchaz/enigma/TranslatingTypeLoader.java2
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java42
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java25
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java39
-rw-r--r--src/main/java/cuchaz/enigma/gui/Gui.java24
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java16
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ClassMapping.java71
-rw-r--r--src/main/java/cuchaz/enigma/mapping/FieldMapping.java15
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Mappings.java10
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java46
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java13
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java18
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MethodMapping.java19
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Translator.java23
15 files changed, 339 insertions, 45 deletions
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index ca387541..fe0e31dc 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -607,4 +607,25 @@ public class Deobfuscator {
607 // clear caches 607 // clear caches
608 this.translatorCache.clear(); 608 this.translatorCache.clear();
609 } 609 }
610
611 public void changeModifier(Entry entry, Mappings.EntryModifier modifierEntry)
612 {
613 Entry obfEntry = obfuscateEntry(entry);
614 if (obfEntry instanceof ClassEntry)
615 this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry);
616 else if (obfEntry instanceof FieldEntry)
617 this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry);
618 else if (obfEntry instanceof BehaviorEntry)
619 this.renamer.setMethodModifier((BehaviorEntry) obfEntry, modifierEntry);
620 else
621 throw new Error("Unknown entry type: " + obfEntry);
622 }
623
624 public Mappings.EntryModifier getModifier(Entry obEntry)
625 {
626 Entry entry = obfuscateEntry(obEntry);
627 if (entry != null)
628 obEntry = entry;
629 return getTranslator(TranslationDirection.Deobfuscating).getModifier(obEntry);
630 }
610} 631}
diff --git a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java
index e4c162da..73405662 100644
--- a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java
@@ -198,7 +198,7 @@ public class TranslatingTypeLoader implements ITypeLoader {
198 throws IOException, NotFoundException, CannotCompileException { 198 throws IOException, NotFoundException, CannotCompileException {
199 199
200 // reconstruct inner classes 200 // reconstruct inner classes
201 new InnerClassWriter(this.jarIndex).write(c); 201 new InnerClassWriter(this.jarIndex, this.deobfuscatingTranslator).write(c);
202 202
203 // re-get the javassist handle since we changed class names 203 // re-get the javassist handle since we changed class names
204 ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); 204 ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
index eb7e9a17..d49f13ab 100644
--- a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
+++ b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
@@ -19,8 +19,9 @@ import java.util.Map;
19 19
20import cuchaz.enigma.mapping.ClassEntry; 20import cuchaz.enigma.mapping.ClassEntry;
21import cuchaz.enigma.mapping.ClassNameReplacer; 21import cuchaz.enigma.mapping.ClassNameReplacer;
22import cuchaz.enigma.mapping.Mappings;
22import cuchaz.enigma.mapping.Translator; 23import cuchaz.enigma.mapping.Translator;
23import javassist.CtClass; 24import javassist.*;
24import javassist.bytecode.*; 25import javassist.bytecode.*;
25import javassist.bytecode.SignatureAttribute.*; 26import javassist.bytecode.SignatureAttribute.*;
26 27
@@ -70,6 +71,41 @@ public class ClassRenamer {
70 } 71 }
71 } 72 }
72 73
74 public static void applyModifier(Object obj, Mappings.EntryModifier modifier)
75 {
76 int mod = -1;
77 if (obj instanceof CtField)
78 mod = ((CtField) obj).getModifiers();
79 else if (obj instanceof CtBehavior)
80 mod = ((CtBehavior) obj).getModifiers();
81 else if (obj instanceof CtClass)
82 mod = ((CtClass) obj).getModifiers();
83
84 if (mod != -1)
85 {
86 switch (modifier)
87 {
88 case PRIVATE:
89 mod = Modifier.setPrivate(mod);
90 break;
91 case PROTECTED:
92 mod = Modifier.setProtected(mod);
93 break;
94 case PUBLIC:
95 mod = Modifier.setPublic(mod);
96 break;
97 default:
98 break;
99 }
100 if (obj instanceof CtField)
101 ((CtField) obj).setModifiers(mod);
102 else if (obj instanceof CtBehavior)
103 ((CtBehavior) obj).setModifiers(mod);
104 else
105 ((CtClass) obj).setModifiers(mod);
106 }
107 }
108
73 public static void renameClasses(CtClass c, final Translator translator) { 109 public static void renameClasses(CtClass c, final Translator translator) {
74 renameClasses(c, className -> { 110 renameClasses(c, className -> {
75 ClassEntry entry = translator.translateEntry(new ClassEntry(className)); 111 ClassEntry entry = translator.translateEntry(new ClassEntry(className));
@@ -110,6 +146,7 @@ public class ClassRenamer {
110 146
111 // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo) 147 // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo)
112 ConstPool constPool = c.getClassFile().getConstPool(); 148 ConstPool constPool = c.getClassFile().getConstPool();
149 String className = constPool.getClassName();
113 constPool.renameClass(map); 150 constPool.renameClass(map);
114 151
115 // rename class attributes 152 // rename class attributes
@@ -140,8 +177,9 @@ public class ClassRenamer {
140 if (attr != null) { 177 if (attr != null) {
141 for (int i = 0; i < attr.tableLength(); i++) { 178 for (int i = 0; i < attr.tableLength(); i++) {
142 179
180 String innerName = attr.innerClass(i);
143 // get the inner class full name (which has already been translated) 181 // get the inner class full name (which has already been translated)
144 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i))); 182 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName));
145 183
146 if (attr.innerNameIndex(i) != 0) { 184 if (attr.innerNameIndex(i) != 0) {
147 // update the inner name 185 // update the inner name
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java b/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java
index 6c05b838..62ebfafb 100644
--- a/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java
+++ b/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java
@@ -11,14 +11,9 @@
11package cuchaz.enigma.bytecode; 11package cuchaz.enigma.bytecode;
12 12
13import cuchaz.enigma.mapping.*; 13import cuchaz.enigma.mapping.*;
14import javassist.CtBehavior; 14import cuchaz.enigma.mapping.Translator;
15import javassist.CtClass; 15import javassist.*;
16import javassist.CtField; 16import javassist.bytecode.*;
17import javassist.CtMethod;
18import javassist.bytecode.ConstPool;
19import javassist.bytecode.Descriptor;
20import javassist.bytecode.EnclosingMethodAttribute;
21import javassist.bytecode.SourceFileAttribute;
22 17
23public class ClassTranslator { 18public class ClassTranslator {
24 19
@@ -74,6 +69,9 @@ public class ClassTranslator {
74 } 69 }
75 70
76 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); 71 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName()));
72 Mappings.EntryModifier modifier = this.translator.getModifier(classEntry);
73 if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED)
74 ClassRenamer.applyModifier(c, modifier);
77 75
78 // translate all the fields 76 // translate all the fields
79 for (CtField field : c.getDeclaredFields()) { 77 for (CtField field : c.getDeclaredFields()) {
@@ -81,6 +79,10 @@ public class ClassTranslator {
81 // translate the name 79 // translate the name
82 FieldEntry entry = EntryFactory.getFieldEntry(field); 80 FieldEntry entry = EntryFactory.getFieldEntry(field);
83 String translatedName = this.translator.translate(entry); 81 String translatedName = this.translator.translate(entry);
82 modifier = this.translator.getModifier(entry);
83 if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED)
84 ClassRenamer.applyModifier(field, modifier);
85
84 if (translatedName != null) { 86 if (translatedName != null) {
85 field.setName(translatedName); 87 field.setName(translatedName);
86 } 88 }
@@ -95,6 +97,10 @@ public class ClassTranslator {
95 97
96 BehaviorEntry entry = EntryFactory.getBehaviorEntry(behavior); 98 BehaviorEntry entry = EntryFactory.getBehaviorEntry(behavior);
97 99
100 modifier = this.translator.getModifier(entry);
101 if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED)
102 ClassRenamer.applyModifier(behavior, modifier);
103
98 if (behavior instanceof CtMethod) { 104 if (behavior instanceof CtMethod) {
99 CtMethod method = (CtMethod) behavior; 105 CtMethod method = (CtMethod) behavior;
100 106
@@ -149,5 +155,8 @@ public class ClassTranslator {
149 String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassEntry().getSimpleName()) + ".java"; 155 String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassEntry().getSimpleName()) + ".java";
150 c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile)); 156 c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile));
151 } 157 }
158 InnerClassesAttribute attr = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag);
159 if (attr != null)
160 InnerClassWriter.changeModifier(c, attr, translator);
152 } 161 }
153} 162}
diff --git a/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java
index 6d926106..6e2a29d5 100644
--- a/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java
+++ b/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java
@@ -15,22 +15,22 @@ import com.google.common.collect.Lists;
15import java.util.Collection; 15import java.util.Collection;
16import java.util.List; 16import java.util.List;
17 17
18import cuchaz.enigma.Deobfuscator;
18import cuchaz.enigma.analysis.JarIndex; 19import cuchaz.enigma.analysis.JarIndex;
19import cuchaz.enigma.mapping.BehaviorEntry; 20import cuchaz.enigma.mapping.*;
20import cuchaz.enigma.mapping.ClassEntry; 21import javassist.ClassPool;
21import cuchaz.enigma.mapping.EntryFactory;
22import javassist.CtClass; 22import javassist.CtClass;
23import javassist.bytecode.AccessFlag; 23import javassist.NotFoundException;
24import javassist.bytecode.ConstPool; 24import javassist.bytecode.*;
25import javassist.bytecode.EnclosingMethodAttribute;
26import javassist.bytecode.InnerClassesAttribute;
27 25
28public class InnerClassWriter { 26public class InnerClassWriter {
29 27
30 private JarIndex index; 28 private JarIndex index;
29 private Translator deobfuscatorTranslator;
31 30
32 public InnerClassWriter(JarIndex index) { 31 public InnerClassWriter(JarIndex index, Translator deobfuscatorTranslator) {
33 this.index = index; 32 this.index = index;
33 this.deobfuscatorTranslator = deobfuscatorTranslator;
34 } 34 }
35 35
36 public void write(CtClass c) { 36 public void write(CtClass c) {
@@ -96,6 +96,29 @@ public class InnerClassWriter {
96 } 96 }
97 } 97 }
98 98
99 // FIXME: modiffier is not applied to inner class
100 public static void changeModifier(CtClass c, InnerClassesAttribute attr, Translator translator)
101 {
102 ClassPool pool = c.getClassPool();
103 for (int i = 0; i < attr.tableLength(); i++) {
104
105 String innerName = attr.innerClass(i);
106 // get the inner class full name (which has already been translated)
107 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName));
108 try
109 {
110 CtClass innerClass = pool.get(innerName);
111 Mappings.EntryModifier modifier = translator.getModifier(classEntry);
112 if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED)
113 ClassRenamer.applyModifier(innerClass, modifier);
114 } catch (NotFoundException e)
115 {
116 // This shouldn't be possible in theory
117 //e.printStackTrace();
118 }
119 }
120 }
121
99 private void writeInnerClass(InnerClassesAttribute attr, List<ClassEntry> obfClassChain, ClassEntry obfClassEntry) { 122 private void writeInnerClass(InnerClassesAttribute attr, List<ClassEntry> obfClassChain, ClassEntry obfClassEntry) {
100 123
101 // get the new inner class name 124 // get the new inner class name
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java
index 6d9ea1df..ed18777a 100644
--- a/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -461,24 +461,29 @@ public class Gui {
461 461
462 private void showClassEntry(ClassEntry entry) { 462 private void showClassEntry(ClassEntry entry) {
463 addNameValue(m_infoPanel, "Class", entry.getName()); 463 addNameValue(m_infoPanel, "Class", entry.getName());
464 addModifierComboBox(m_infoPanel, "Modifier", entry);
464 } 465 }
465 466
466 private void showFieldEntry(FieldEntry entry) { 467 private void showFieldEntry(FieldEntry entry) {
467 addNameValue(m_infoPanel, "Field", entry.getName()); 468 addNameValue(m_infoPanel, "Field", entry.getName());
468 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); 469 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
469 addNameValue(m_infoPanel, "Type", entry.getType().toString()); 470 addNameValue(m_infoPanel, "Type", entry.getType().toString());
471 addModifierComboBox(m_infoPanel, "Modifier", entry);
470 } 472 }
471 473
472 private void showMethodEntry(MethodEntry entry) { 474 private void showMethodEntry(MethodEntry entry) {
473 addNameValue(m_infoPanel, "Method", entry.getName()); 475 addNameValue(m_infoPanel, "Method", entry.getName());
474 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); 476 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
475 addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); 477 addNameValue(m_infoPanel, "Signature", entry.getSignature().toString());
478 addModifierComboBox(m_infoPanel, "Modifier", entry);
479
476 } 480 }
477 481
478 private void showConstructorEntry(ConstructorEntry entry) { 482 private void showConstructorEntry(ConstructorEntry entry) {
479 addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName()); 483 addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName());
480 if (!entry.isStatic()) { 484 if (!entry.isStatic()) {
481 addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); 485 addNameValue(m_infoPanel, "Signature", entry.getSignature().toString());
486 addModifierComboBox(m_infoPanel, "Modifier", entry);
482 } 487 }
483 } 488 }
484 489
@@ -501,6 +506,25 @@ public class Gui {
501 panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT))); 506 panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT)));
502 } 507 }
503 508
509 private JComboBox<Mappings.EntryModifier> addModifierComboBox(JPanel container, String name, Entry entry)
510 {
511 if (!getController().entryIsInJar(entry))
512 return null;
513 JPanel panel = new JPanel();
514 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0));
515 container.add(panel);
516 JLabel label = new JLabel(name + ":", JLabel.RIGHT);
517 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
518 panel.add(label);
519 JComboBox<Mappings.EntryModifier> combo = new JComboBox<>(Mappings.EntryModifier.values());
520 ((JLabel)combo.getRenderer()).setHorizontalAlignment(JLabel.LEFT);
521 combo.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
522 combo.setSelectedIndex(getController().getDeobfuscator().getModifier(entry).ordinal());
523 combo.addItemListener(getController()::modifierChange);
524 panel.add(combo);
525 return combo;
526 }
527
504 public void onCaretMove(int pos) { 528 public void onCaretMove(int pos) {
505 529
506 Token token = this.controller.getToken(pos); 530 Token token = this.controller.getToken(pos);
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index 70fb4cf2..c2e202e2 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -20,6 +20,7 @@ import cuchaz.enigma.mapping.*;
20import cuchaz.enigma.throwables.MappingParseException; 20import cuchaz.enigma.throwables.MappingParseException;
21import cuchaz.enigma.utils.ReadableToken; 21import cuchaz.enigma.utils.ReadableToken;
22 22
23import java.awt.event.ItemEvent;
23import java.io.File; 24import java.io.File;
24import java.io.IOException; 25import java.io.IOException;
25import java.util.Collection; 26import java.util.Collection;
@@ -338,4 +339,19 @@ public class GuiController {
338 } 339 }
339 }.start(); 340 }.start();
340 } 341 }
342
343 public Deobfuscator getDeobfuscator()
344 {
345 return deobfuscator;
346 }
347
348 public void modifierChange(ItemEvent event)
349 {
350 if (event.getStateChange() == ItemEvent.SELECTED)
351 {
352 deobfuscator.changeModifier(gui.m_reference.entry, (Mappings.EntryModifier) event.getItem());
353 this.isDirty = true;
354 refreshCurrentClass();
355 }
356 }
341} 357}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
index 923c8ece..017a5b9f 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
@@ -30,12 +30,20 @@ public class ClassMapping implements Comparable<ClassMapping> {
30 private Map<String, MethodMapping> m_methodsByObf; 30 private Map<String, MethodMapping> m_methodsByObf;
31 private Map<String, MethodMapping> m_methodsByDeobf; 31 private Map<String, MethodMapping> m_methodsByDeobf;
32 private boolean isDirty; 32 private boolean isDirty;
33 private Mappings.EntryModifier modifier;
33 34
34 public ClassMapping(String obfFullName) { 35 public ClassMapping(String obfFullName)
35 this(obfFullName, null); 36 {
37 this(obfFullName, null, Mappings.EntryModifier.UNCHANGED);
36 } 38 }
37 39
38 public ClassMapping(String obfFullName, String deobfName) { 40 public ClassMapping(String obfFullName, String deobfName)
41 {
42 this(obfFullName, deobfName, Mappings.EntryModifier.UNCHANGED);
43 }
44
45 public ClassMapping(String obfFullName, String deobfName, Mappings.EntryModifier modifier)
46 {
39 m_obfFullName = obfFullName; 47 m_obfFullName = obfFullName;
40 ClassEntry classEntry = new ClassEntry(obfFullName); 48 ClassEntry classEntry = new ClassEntry(obfFullName);
41 m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName(); 49 m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName();
@@ -48,6 +56,7 @@ public class ClassMapping implements Comparable<ClassMapping> {
48 m_methodsByObf = Maps.newHashMap(); 56 m_methodsByObf = Maps.newHashMap();
49 m_methodsByDeobf = Maps.newHashMap(); 57 m_methodsByDeobf = Maps.newHashMap();
50 isDirty = true; 58 isDirty = true;
59 this.modifier = modifier;
51 } 60 }
52 61
53 public String getObfFullName() { 62 public String getObfFullName() {
@@ -186,15 +195,16 @@ public class ClassMapping implements Comparable<ClassMapping> {
186 if (m_fieldsByObf.containsKey(obfKey)) { 195 if (m_fieldsByObf.containsKey(obfKey)) {
187 throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); 196 throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey);
188 } 197 }
189 String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType()); 198 if (fieldMapping.getDeobfName() != null) {
190 if (m_fieldsByDeobf.containsKey(deobfKey)) { 199 String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType());
191 throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); 200 if (m_fieldsByDeobf.containsKey(deobfKey)) {
201 throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey);
202 }
203 boolean deobfWasAdded = m_fieldsByDeobf.put(deobfKey, fieldMapping) == null;
204 assert (deobfWasAdded);
192 } 205 }
193 boolean obfWasAdded = m_fieldsByObf.put(obfKey, fieldMapping) == null; 206 boolean obfWasAdded = m_fieldsByObf.put(obfKey, fieldMapping) == null;
194 assert (obfWasAdded); 207 assert (obfWasAdded);
195 boolean deobfWasAdded = m_fieldsByDeobf.put(deobfKey, fieldMapping) == null;
196 assert (deobfWasAdded);
197 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
198 this.isDirty = true; 208 this.isDirty = true;
199 } 209 }
200 210
@@ -242,12 +252,11 @@ public class ClassMapping implements Comparable<ClassMapping> {
242 return name + ":" + type; 252 return name + ":" + type;
243 } 253 }
244 254
245
246 public void setFieldName(String obfName, Type obfType, String deobfName) { 255 public void setFieldName(String obfName, Type obfType, String deobfName) {
247 assert (deobfName != null); 256 assert (deobfName != null);
248 FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType)); 257 FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType));
249 if (fieldMapping == null) { 258 if (fieldMapping == null) {
250 fieldMapping = new FieldMapping(obfName, obfType, deobfName); 259 fieldMapping = new FieldMapping(obfName, obfType, deobfName, Mappings.EntryModifier.UNCHANGED);
251 boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null; 260 boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null;
252 assert (obfWasAdded); 261 assert (obfWasAdded);
253 } else { 262 } else {
@@ -492,4 +501,44 @@ public class ClassMapping implements Comparable<ClassMapping> {
492 { 501 {
493 this.isDirty = false; 502 this.isDirty = false;
494 } 503 }
504
505 public void setModifier(Mappings.EntryModifier modifier)
506 {
507 if (this.modifier != modifier)
508 this.isDirty = true;
509 this.modifier = modifier;
510 }
511
512 public Mappings.EntryModifier getModifier()
513 {
514 return modifier;
515 }
516
517 public void setFieldModifier(String obfName, Type obfType, Mappings.EntryModifier modifier) {
518 FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType));
519 if (fieldMapping == null) {
520 fieldMapping = new FieldMapping(obfName, obfType, null, Mappings.EntryModifier.UNCHANGED);
521 m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping);
522 }
523
524 if (fieldMapping.getModifier() != modifier)
525 {
526 fieldMapping.setModifier(modifier);
527 this.isDirty = true;
528 }
529 }
530
531 public void setMethodModifier(String obfName, Signature sig, Mappings.EntryModifier modifier) {
532 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, sig));
533 if (methodMapping == null) {
534 methodMapping = new MethodMapping(obfName, sig, null, Mappings.EntryModifier.UNCHANGED);
535 m_methodsByObf.put(getMethodKey(obfName, sig), methodMapping);
536 }
537
538 if (methodMapping.getModifier() != modifier)
539 {
540 methodMapping.setModifier(modifier);
541 this.isDirty = true;
542 }
543 }
495} 544}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
index 1b596606..e75485cd 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
@@ -15,16 +15,19 @@ public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<Fie
15 private String obfName; 15 private String obfName;
16 private String deobfName; 16 private String deobfName;
17 private Type obfType; 17 private Type obfType;
18 private Mappings.EntryModifier modifier;
18 19
19 public FieldMapping(String obfName, Type obfType, String deobfName) { 20 public FieldMapping(String obfName, Type obfType, String deobfName, Mappings.EntryModifier modifier) {
20 this.obfName = obfName; 21 this.obfName = obfName;
21 this.deobfName = NameValidator.validateFieldName(deobfName); 22 this.deobfName = NameValidator.validateFieldName(deobfName);
22 this.obfType = obfType; 23 this.obfType = obfType;
24 this.modifier = modifier;
23 } 25 }
24 26
25 public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) { 27 public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) {
26 this.obfName = other.obfName; 28 this.obfName = other.obfName;
27 this.deobfName = other.deobfName; 29 this.deobfName = other.deobfName;
30 this.modifier = other.modifier;
28 this.obfType = new Type(other.obfType, obfClassNameReplacer); 31 this.obfType = new Type(other.obfType, obfClassNameReplacer);
29 } 32 }
30 33
@@ -58,6 +61,16 @@ public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<Fie
58 this.obfType = val; 61 this.obfType = val;
59 } 62 }
60 63
64 public void setModifier(Mappings.EntryModifier modifier)
65 {
66 this.modifier = modifier;
67 }
68
69 public Mappings.EntryModifier getModifier()
70 {
71 return modifier;
72 }
73
61 @Override 74 @Override
62 public int compareTo(FieldMapping other) { 75 public int compareTo(FieldMapping other) {
63 return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType); 76 return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType);
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
index 2166bb9f..d493dcfa 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -240,4 +240,14 @@ public class Mappings {
240 { 240 {
241 ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE 241 ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE
242 } 242 }
243
244 public enum EntryModifier
245 {
246 UNCHANGED, PUBLIC, PROTECTED, PRIVATE;
247
248 public String getFormattedName()
249 {
250 return " ACC:" + super.toString();
251 }
252 }
243} 253}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
index 93276a63..cdfed726 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
@@ -135,21 +135,51 @@ public class MappingsEnigmaReader
135 private ClassMapping readClass(String[] parts, boolean makeSimple) { 135 private ClassMapping readClass(String[] parts, boolean makeSimple) {
136 if (parts.length == 2) { 136 if (parts.length == 2) {
137 return new ClassMapping(parts[1]); 137 return new ClassMapping(parts[1]);
138 } else { 138 } else if (parts.length == 3) {
139 return new ClassMapping(parts[1], parts[2]); 139 boolean access = parts[2].startsWith("ACC:");
140 } 140 ClassMapping mapping;
141 if (access)
142 mapping = new ClassMapping(parts[1], null, Mappings.EntryModifier.valueOf(parts[2].substring(4)));
143 else
144 mapping = new ClassMapping(parts[1], parts[2]);
145
146 return mapping;
147 } else if (parts.length == 4)
148 return new ClassMapping(parts[1], parts[2], Mappings.EntryModifier.valueOf(parts[3].substring(4)));
149 return null;
141 } 150 }
142 151
143 /* TEMP */ 152 /* TEMP */
144 protected FieldMapping readField(String[] parts) { 153 protected FieldMapping readField(String[] parts) {
145 return new FieldMapping(parts[1], new Type(parts[3]), parts[2]); 154 FieldMapping mapping = null;
155 if (parts.length == 4)
156 {
157 boolean access = parts[3].startsWith("ACC:");
158 if (access)
159 mapping = new FieldMapping(parts[1], new Type(parts[2]), null,
160 Mappings.EntryModifier.valueOf(parts[3].substring(4)));
161 else
162 mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.UNCHANGED);
163 }
164 else if (parts.length == 5)
165 mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.valueOf(parts[4].substring(4)));
166 return mapping;
146 } 167 }
147 168
148 private MethodMapping readMethod(String[] parts) { 169 private MethodMapping readMethod(String[] parts) {
149 if (parts.length == 3) { 170 MethodMapping mapping = null;
150 return new MethodMapping(parts[1], new Signature(parts[2])); 171 if (parts.length == 3)
151 } else { 172 mapping = new MethodMapping(parts[1], new Signature(parts[2]));
152 return new MethodMapping(parts[1], new Signature(parts[3]), parts[2]); 173 else if (parts.length == 4){
174 boolean access = parts[3].startsWith("ACC:");
175 if (access)
176 mapping = new MethodMapping(parts[1], new Signature(parts[2]), null, Mappings.EntryModifier.valueOf(parts[3].substring(4)));
177 else
178 mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2]);
153 } 179 }
180 else if (parts.length == 5)
181 mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2],
182 Mappings.EntryModifier.valueOf(parts[4].substring(4)));
183 return mapping;
154 } 184 }
155} 185}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
index e1763d0a..95896898 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
@@ -110,9 +110,9 @@ public class MappingsEnigmaWriter {
110 110
111 private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException { 111 private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException {
112 if (classMapping.getDeobfName() == null) { 112 if (classMapping.getDeobfName() == null) {
113 out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfFullName()); 113 out.format("%sCLASS %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName());
114 } else { 114 } else {
115 out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName()); 115 out.format("%sCLASS %s %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName(), classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName());
116 } 116 }
117 117
118 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { 118 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) {
@@ -129,14 +129,17 @@ public class MappingsEnigmaWriter {
129 } 129 }
130 130
131 private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException { 131 private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException {
132 out.format("%sFIELD %s %s %s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString()); 132 if (fieldMapping.getDeobfName() == null)
133 out.format("%sFIELD %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getObfType().toString(), fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName());
134 else
135 out.format("%sFIELD %s %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString(), fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName());
133 } 136 }
134 137
135 private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException { 138 private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException {
136 if (methodMapping.getDeobfName() == null) { 139 if (methodMapping.getDeobfName() == null) {
137 out.format("%sMETHOD %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature()); 140 out.format("%sMETHOD %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature(), methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" :methodMapping.getModifier().getFormattedName());
138 } else { 141 } else {
139 out.format("%sMETHOD %s %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature()); 142 out.format("%sMETHOD %s %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature(), methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName());
140 } 143 }
141 144
142 for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) { 145 for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) {
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
index 4e812b10..bac62503 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -321,4 +321,22 @@ public class MappingsRenamer {
321 } 321 }
322 return mappingChain; 322 return mappingChain;
323 } 323 }
324
325 public void setClassModifier(ClassEntry obEntry, Mappings.EntryModifier modifier)
326 {
327 ClassMapping classMapping = getOrCreateClassMapping(obEntry);
328 classMapping.setModifier(modifier);
329 }
330
331 public void setFieldModifier(FieldEntry obEntry, Mappings.EntryModifier modifier)
332 {
333 ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
334 classMapping.setFieldModifier(obEntry.getName(), obEntry.getType(), modifier);
335 }
336
337 public void setMethodModifier(BehaviorEntry obEntry, Mappings.EntryModifier modifier)
338 {
339 ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
340 classMapping.setMethodModifier(obEntry.getName(), obEntry.getSignature(), modifier);
341 }
324} 342}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
index 99b9c887..455ff6b7 100644
--- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
@@ -22,12 +22,17 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B
22 private String deobfName; 22 private String deobfName;
23 private Signature obfSignature; 23 private Signature obfSignature;
24 private Map<Integer, ArgumentMapping> arguments; 24 private Map<Integer, ArgumentMapping> arguments;
25 private Mappings.EntryModifier modifier;
25 26
26 public MethodMapping(String obfName, Signature obfSignature) { 27 public MethodMapping(String obfName, Signature obfSignature) {
27 this(obfName, obfSignature, null); 28 this(obfName, obfSignature, null,Mappings.EntryModifier.UNCHANGED);
28 } 29 }
29 30
30 public MethodMapping(String obfName, Signature obfSignature, String deobfName) { 31 public MethodMapping(String obfName, Signature obfSignature, String deobfName) {
32 this(obfName, obfSignature, deobfName, Mappings.EntryModifier.UNCHANGED);
33 }
34
35 public MethodMapping(String obfName, Signature obfSignature, String deobfName, Mappings.EntryModifier modifier) {
31 if (obfName == null) { 36 if (obfName == null) {
32 throw new IllegalArgumentException("obf name cannot be null!"); 37 throw new IllegalArgumentException("obf name cannot be null!");
33 } 38 }
@@ -38,11 +43,13 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B
38 this.deobfName = NameValidator.validateMethodName(deobfName); 43 this.deobfName = NameValidator.validateMethodName(deobfName);
39 this.obfSignature = obfSignature; 44 this.obfSignature = obfSignature;
40 this.arguments = Maps.newTreeMap(); 45 this.arguments = Maps.newTreeMap();
46 this.modifier = modifier;
41 } 47 }
42 48
43 public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) { 49 public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) {
44 this.obfName = other.obfName; 50 this.obfName = other.obfName;
45 this.deobfName = other.deobfName; 51 this.deobfName = other.deobfName;
52 this.modifier = other.modifier;
46 this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer); 53 this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer);
47 this.arguments = Maps.newTreeMap(); 54 this.arguments = Maps.newTreeMap();
48 for (Map.Entry<Integer,ArgumentMapping> entry : other.arguments.entrySet()) { 55 for (Map.Entry<Integer,ArgumentMapping> entry : other.arguments.entrySet()) {
@@ -187,4 +194,14 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B
187 return new MethodEntry(classEntry, this.obfName, this.obfSignature); 194 return new MethodEntry(classEntry, this.obfName, this.obfSignature);
188 } 195 }
189 } 196 }
197
198 public Mappings.EntryModifier getModifier()
199 {
200 return modifier;
201 }
202
203 public void setModifier(Mappings.EntryModifier modifier)
204 {
205 this.modifier = modifier;
206 }
190} 207}
diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java
index 6b636f2f..e94009ee 100644
--- a/src/main/java/cuchaz/enigma/mapping/Translator.java
+++ b/src/main/java/cuchaz/enigma/mapping/Translator.java
@@ -329,4 +329,27 @@ public class Translator {
329 assert (mappingsChain.size() == parts.length); 329 assert (mappingsChain.size() == parts.length);
330 return mappingsChain; 330 return mappingsChain;
331 } 331 }
332
333 public Mappings.EntryModifier getModifier(Entry entry)
334 {
335 ClassMapping classMapping = findClassMapping(entry.getClassEntry());
336 if (classMapping != null && !entry.getName().equals("<clinit>"))
337 {
338 if (entry instanceof ClassEntry)
339 return classMapping.getModifier();
340 else if (entry instanceof FieldEntry)
341 {
342 FieldMapping fieldMapping = classMapping.getFieldByObf(entry.getName(), ((FieldEntry) entry).getType());
343 return fieldMapping != null ? fieldMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
344 }
345 else if (entry instanceof BehaviorEntry)
346 {
347 MethodMapping methodMapping = classMapping.getMethodByObf(entry.getName(), ((BehaviorEntry) entry).getSignature());
348 return methodMapping != null ? methodMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
349 }
350 else
351 throw new Error("Unknown entry type: " + entry.getClass().getName());
352 }
353 return Mappings.EntryModifier.UNCHANGED;
354 }
332} 355}