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/bytecode/InnerClassWriter.java | 132 +++++++++++++++++++++
1 file changed, 132 insertions(+)
create mode 100644 src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java
(limited to 'src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java')
diff --git a/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java
new file mode 100644
index 0000000..25ac7d6
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * 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.bytecode;
+
+import com.google.common.collect.Lists;
+
+import java.util.Collection;
+import java.util.List;
+
+import cuchaz.enigma.analysis.JarIndex;
+import cuchaz.enigma.mapping.BehaviorEntry;
+import cuchaz.enigma.mapping.ClassEntry;
+import cuchaz.enigma.mapping.EntryFactory;
+import javassist.CtClass;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.EnclosingMethodAttribute;
+import javassist.bytecode.InnerClassesAttribute;
+
+public class InnerClassWriter {
+
+ private JarIndex m_index;
+
+ public InnerClassWriter(JarIndex index) {
+ m_index = index;
+ }
+
+ public void write(CtClass c) {
+
+ // don't change anything if there's already an attribute there
+ InnerClassesAttribute oldAttr = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag);
+ if (oldAttr != null) {
+ // bail!
+ return;
+ }
+
+ ClassEntry obfClassEntry = EntryFactory.getClassEntry(c);
+ List obfClassChain = m_index.getObfClassChain(obfClassEntry);
+
+ boolean isInnerClass = obfClassChain.size() > 1;
+ if (isInnerClass) {
+
+ // it's an inner class, rename it to the fully qualified name
+ c.setName(obfClassEntry.buildClassEntry(obfClassChain).getName());
+
+ BehaviorEntry caller = m_index.getAnonymousClassCaller(obfClassEntry);
+ if (caller != null) {
+
+ // write the enclosing method attribute
+ if (caller.getName().equals("")) {
+ c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName()));
+ } else {
+ c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName(), caller.getName(), caller.getSignature().toString()));
+ }
+ }
+ }
+
+ // does this class have any inner classes?
+ Collection obfInnerClassEntries = m_index.getInnerClasses(obfClassEntry);
+
+ if (isInnerClass || !obfInnerClassEntries.isEmpty()) {
+
+ // create an inner class attribute
+ InnerClassesAttribute attr = new InnerClassesAttribute(c.getClassFile().getConstPool());
+ c.getClassFile().addAttribute(attr);
+
+ // write the ancestry, but not the outermost class
+ for (int i = 1; i < obfClassChain.size(); i++) {
+ ClassEntry obfInnerClassEntry = obfClassChain.get(i);
+ writeInnerClass(attr, obfClassChain, obfInnerClassEntry);
+
+ // update references to use the fully qualified inner class name
+ c.replaceClassName(obfInnerClassEntry.getName(), obfInnerClassEntry.buildClassEntry(obfClassChain).getName());
+ }
+
+ // write the inner classes
+ for (ClassEntry obfInnerClassEntry : obfInnerClassEntries) {
+
+ // extend the class chain
+ List extendedObfClassChain = Lists.newArrayList(obfClassChain);
+ extendedObfClassChain.add(obfInnerClassEntry);
+
+ writeInnerClass(attr, extendedObfClassChain, obfInnerClassEntry);
+
+ // update references to use the fully qualified inner class name
+ c.replaceClassName(obfInnerClassEntry.getName(), obfInnerClassEntry.buildClassEntry(extendedObfClassChain).getName());
+ }
+ }
+ }
+
+ private void writeInnerClass(InnerClassesAttribute attr, List obfClassChain, ClassEntry obfClassEntry) {
+
+ // get the new inner class name
+ ClassEntry obfInnerClassEntry = obfClassEntry.buildClassEntry(obfClassChain);
+ ClassEntry obfOuterClassEntry = obfInnerClassEntry.getOuterClassEntry();
+
+ // here's what the JVM spec says about the InnerClasses attribute
+ // append(inner, parent, 0 if anonymous else simple name, flags);
+
+ // update the attribute with this inner class
+ ConstPool constPool = attr.getConstPool();
+ int innerClassIndex = constPool.addClassInfo(obfInnerClassEntry.getName());
+ int parentClassIndex = constPool.addClassInfo(obfOuterClassEntry.getName());
+ int innerClassNameIndex = 0;
+ int accessFlags = AccessFlag.PUBLIC;
+ // TODO: need to figure out if we can put static or not
+ if (!m_index.isAnonymousClass(obfClassEntry)) {
+ innerClassNameIndex = constPool.addUtf8Info(obfInnerClassEntry.getInnermostClassName());
+ }
+
+ attr.append(innerClassIndex, parentClassIndex, innerClassNameIndex, accessFlags);
+
+ /* DEBUG
+ System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)",
+ obfClassEntry,
+ attr.innerClass(attr.tableLength() - 1),
+ attr.outerClass(attr.tableLength() - 1),
+ attr.innerName(attr.tableLength() - 1),
+ Constants.NonePackage + "/" + obfInnerClassName,
+ obfClassEntry.getName()
+ ));
+ */
+ }
+}
--
cgit v1.2.3