From 4be005617b3b8c3578cca07c5d085d12916f0d1d Mon Sep 17 00:00:00 2001
From: lclc98
Date: Thu, 30 Jun 2016 00:49:21 +1000
Subject: Json format (#2)
* Added new format
* Fixed bug
* Updated Version
---
.../cuchaz/enigma/analysis/TranslationIndex.java | 282 +++++++++++++++++++++
1 file changed, 282 insertions(+)
create mode 100644 src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
(limited to 'src/main/java/cuchaz/enigma/analysis/TranslationIndex.java')
diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
new file mode 100644
index 0000000..0261a96
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * 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.analysis;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import cuchaz.enigma.mapping.*;
+import javassist.CtBehavior;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.bytecode.Descriptor;
+
+public class TranslationIndex implements Serializable {
+
+ private static final long serialVersionUID = 738687982126844179L;
+
+ private Map m_superclasses;
+ private Multimap m_fieldEntries;
+ private Multimap m_behaviorEntries;
+ private Multimap m_interfaces;
+
+ public TranslationIndex() {
+ m_superclasses = Maps.newHashMap();
+ m_fieldEntries = HashMultimap.create();
+ m_behaviorEntries = HashMultimap.create();
+ m_interfaces = HashMultimap.create();
+ }
+
+ public TranslationIndex(TranslationIndex other, Translator translator) {
+
+ // translate the superclasses
+ m_superclasses = Maps.newHashMap();
+ for (Map.Entry mapEntry : other.m_superclasses.entrySet()) {
+ m_superclasses.put(
+ translator.translateEntry(mapEntry.getKey()),
+ translator.translateEntry(mapEntry.getValue())
+ );
+ }
+
+ // translate the interfaces
+ m_interfaces = HashMultimap.create();
+ for (Map.Entry mapEntry : other.m_interfaces.entries()) {
+ m_interfaces.put(
+ translator.translateEntry(mapEntry.getKey()),
+ translator.translateEntry(mapEntry.getValue())
+ );
+ }
+
+ // translate the fields
+ m_fieldEntries = HashMultimap.create();
+ for (Map.Entry mapEntry : other.m_fieldEntries.entries()) {
+ m_fieldEntries.put(
+ translator.translateEntry(mapEntry.getKey()),
+ translator.translateEntry(mapEntry.getValue())
+ );
+ }
+
+ m_behaviorEntries = HashMultimap.create();
+ for (Map.Entry mapEntry : other.m_behaviorEntries.entries()) {
+ m_behaviorEntries.put(
+ translator.translateEntry(mapEntry.getKey()),
+ translator.translateEntry(mapEntry.getValue())
+ );
+ }
+ }
+
+ public void indexClass(CtClass c) {
+ indexClass(c, true);
+ }
+
+ public void indexClass(CtClass c, boolean indexMembers) {
+
+ ClassEntry classEntry = EntryFactory.getClassEntry(c);
+ if (isJre(classEntry)) {
+ return;
+ }
+
+ // add the superclass
+ ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c);
+ if (superclassEntry != null) {
+ m_superclasses.put(classEntry, superclassEntry);
+ }
+
+ // add the interfaces
+ for (String interfaceClassName : c.getClassFile().getInterfaces()) {
+ ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName));
+ if (!isJre(interfaceClassEntry)) {
+ m_interfaces.put(classEntry, interfaceClassEntry);
+ }
+ }
+
+ if (indexMembers) {
+ // add fields
+ for (CtField field : c.getDeclaredFields()) {
+ FieldEntry fieldEntry = EntryFactory.getFieldEntry(field);
+ m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry);
+ }
+
+ // add behaviors
+ for (CtBehavior behavior : c.getDeclaredBehaviors()) {
+ BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
+ m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry);
+ }
+ }
+ }
+
+ public void renameClasses(Map renames) {
+ EntryRenamer.renameClassesInMap(renames, m_superclasses);
+ EntryRenamer.renameClassesInMultimap(renames, m_fieldEntries);
+ EntryRenamer.renameClassesInMultimap(renames, m_behaviorEntries);
+ }
+
+ public ClassEntry getSuperclass(ClassEntry classEntry) {
+ return m_superclasses.get(classEntry);
+ }
+
+ public List getAncestry(ClassEntry classEntry) {
+ List ancestors = Lists.newArrayList();
+ while (classEntry != null) {
+ classEntry = getSuperclass(classEntry);
+ if (classEntry != null) {
+ ancestors.add(classEntry);
+ }
+ }
+ return ancestors;
+ }
+
+ public List getSubclass(ClassEntry classEntry) {
+
+ // linear search is fast enough for now
+ List subclasses = Lists.newArrayList();
+ for (Map.Entry entry : m_superclasses.entrySet()) {
+ ClassEntry subclass = entry.getKey();
+ ClassEntry superclass = entry.getValue();
+ if (classEntry.equals(superclass)) {
+ subclasses.add(subclass);
+ }
+ }
+ return subclasses;
+ }
+
+ public void getSubclassesRecursively(Set out, ClassEntry classEntry) {
+ for (ClassEntry subclassEntry : getSubclass(classEntry)) {
+ out.add(subclassEntry);
+ getSubclassesRecursively(out, subclassEntry);
+ }
+ }
+
+ public void getSubclassNamesRecursively(Set out, ClassEntry classEntry) {
+ for (ClassEntry subclassEntry : getSubclass(classEntry)) {
+ out.add(subclassEntry.getName());
+ getSubclassNamesRecursively(out, subclassEntry);
+ }
+ }
+
+ public Collection> getClassInterfaces() {
+ return m_interfaces.entries();
+ }
+
+ public Collection getInterfaces(ClassEntry classEntry) {
+ return m_interfaces.get(classEntry);
+ }
+
+ public boolean isInterface(ClassEntry classEntry) {
+ return m_interfaces.containsValue(classEntry);
+ }
+
+ public boolean entryExists(Entry entry) {
+ if (entry instanceof FieldEntry) {
+ return fieldExists((FieldEntry) entry);
+ } else if (entry instanceof BehaviorEntry) {
+ return behaviorExists((BehaviorEntry) entry);
+ } else if (entry instanceof ArgumentEntry) {
+ return behaviorExists(((ArgumentEntry) entry).getBehaviorEntry());
+ }
+ throw new IllegalArgumentException("Cannot check existence for " + entry.getClass());
+ }
+
+ public boolean fieldExists(FieldEntry fieldEntry) {
+ return m_fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry);
+ }
+
+ public boolean behaviorExists(BehaviorEntry behaviorEntry) {
+ return m_behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry);
+ }
+
+ public ClassEntry resolveEntryClass(Entry entry) {
+
+ if (entry instanceof ClassEntry) {
+ return (ClassEntry) entry;
+ }
+
+ ClassEntry superclassEntry = resolveSuperclass(entry);
+ if (superclassEntry != null) {
+ return superclassEntry;
+ }
+
+ ClassEntry interfaceEntry = resolveInterface(entry);
+ if (interfaceEntry != null) {
+ return interfaceEntry;
+ }
+
+ return null;
+ }
+
+ public ClassEntry resolveSuperclass(Entry entry) {
+
+ // this entry could refer to a method on a class where the method is not actually implemented
+ // travel up the inheritance tree to find the closest implementation
+ while (!entryExists(entry)) {
+
+ // is there a parent class?
+ ClassEntry superclassEntry = getSuperclass(entry.getClassEntry());
+ if (superclassEntry == null) {
+ // this is probably a method from a class in a library
+ // we can't trace the implementation up any higher unless we index the library
+ return null;
+ }
+
+ // move up to the parent class
+ entry = entry.cloneToNewClass(superclassEntry);
+ }
+ return entry.getClassEntry();
+ }
+
+ public ClassEntry resolveInterface(Entry entry) {
+
+ // the interfaces for any class is a forest
+ // so let's look at all the trees
+ for (ClassEntry interfaceEntry : m_interfaces.get(entry.getClassEntry())) {
+ ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry));
+ if (resolvedClassEntry != null) {
+ return resolvedClassEntry;
+ }
+ }
+ return null;
+ }
+
+ private boolean isJre(ClassEntry classEntry) {
+ String packageName = classEntry.getPackageName();
+ return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax"));
+ }
+
+ public void write(OutputStream out)
+ throws IOException {
+ GZIPOutputStream gzipout = new GZIPOutputStream(out);
+ ObjectOutputStream oout = new ObjectOutputStream(gzipout);
+ oout.writeObject(m_superclasses);
+ oout.writeObject(m_fieldEntries);
+ oout.writeObject(m_behaviorEntries);
+ gzipout.finish();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void read(InputStream in)
+ throws IOException {
+ try {
+ ObjectInputStream oin = new ObjectInputStream(new GZIPInputStream(in));
+ m_superclasses = (HashMap) oin.readObject();
+ m_fieldEntries = (HashMultimap) oin.readObject();
+ m_behaviorEntries = (HashMultimap) oin.readObject();
+ } catch (ClassNotFoundException ex) {
+ throw new Error(ex);
+ }
+ }
+}
--
cgit v1.2.3