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.
---
.../cuchaz/enigma/bytecode/CheckCastIterator.java | 117 ++++++++++++++++++++
.../java/cuchaz/enigma/bytecode/ClassRenamer.java | 10 ++
.../cuchaz/enigma/bytecode/ConstPoolEditor.java | 122 +++++++++++++++++++++
.../bytecode/accessors/ClassInfoAccessor.java | 4 +
.../bytecode/accessors/ConstInfoAccessor.java | 42 +++++++
.../accessors/InvokeDynamicInfoAccessor.java | 4 +
.../bytecode/accessors/MemberRefInfoAccessor.java | 4 +
.../accessors/MethodHandleInfoAccessor.java | 4 +
.../bytecode/accessors/MethodTypeInfoAccessor.java | 4 +
.../accessors/NameAndTypeInfoAccessor.java | 4 +
.../bytecode/accessors/StringInfoAccessor.java | 4 +
.../bytecode/accessors/Utf8InfoAccessor.java | 28 +++++
12 files changed, 347 insertions(+)
create mode 100644 src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java
create mode 100644 src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java
(limited to 'src/main/java/cuchaz/enigma/bytecode')
diff --git a/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java
new file mode 100644
index 0000000..19c39d3
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * 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 java.util.Iterator;
+
+import cuchaz.enigma.bytecode.CheckCastIterator.CheckCast;
+import cuchaz.enigma.mapping.ClassEntry;
+import cuchaz.enigma.mapping.MethodEntry;
+import cuchaz.enigma.mapping.Signature;
+import javassist.bytecode.*;
+
+public class CheckCastIterator implements Iterator {
+
+ public static class CheckCast {
+
+ public String className;
+ public MethodEntry prevMethodEntry;
+
+ public CheckCast(String className, MethodEntry prevMethodEntry) {
+ this.className = className;
+ this.prevMethodEntry = prevMethodEntry;
+ }
+ }
+
+ private ConstPool constants;
+ private CodeAttribute attribute;
+ private CodeIterator iter;
+ private CheckCast next;
+
+ public CheckCastIterator(CodeAttribute codeAttribute) throws BadBytecode {
+ this.constants = codeAttribute.getConstPool();
+ this.attribute = codeAttribute;
+ this.iter = this.attribute.iterator();
+
+ this.next = getNext();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return this.next != null;
+ }
+
+ @Override
+ public CheckCast next() {
+ CheckCast out = this.next;
+ try {
+ this.next = getNext();
+ } catch (BadBytecode ex) {
+ throw new Error(ex);
+ }
+ return out;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ private CheckCast getNext() throws BadBytecode {
+ int prevPos = 0;
+ while (this.iter.hasNext()) {
+ int pos = this.iter.next();
+ int opcode = this.iter.byteAt(pos);
+ switch (opcode) {
+ case Opcode.CHECKCAST:
+
+ // get the type of this op code (next two bytes are a classinfo index)
+ MethodEntry prevMethodEntry = getMethodEntry(prevPos);
+ if (prevMethodEntry != null) {
+ return new CheckCast(this.constants.getClassInfo(this.iter.s16bitAt(pos + 1)), prevMethodEntry);
+ }
+ break;
+ }
+ prevPos = pos;
+ }
+ return null;
+ }
+
+ private MethodEntry getMethodEntry(int pos) {
+ switch (this.iter.byteAt(pos)) {
+ case Opcode.INVOKEVIRTUAL:
+ case Opcode.INVOKESTATIC:
+ case Opcode.INVOKEDYNAMIC:
+ case Opcode.INVOKESPECIAL: {
+ int index = this.iter.s16bitAt(pos + 1);
+ return new MethodEntry(
+ new ClassEntry(Descriptor.toJvmName(this.constants.getMethodrefClassName(index))),
+ this.constants.getMethodrefName(index),
+ new Signature(this.constants.getMethodrefType(index))
+ );
+ }
+
+ case Opcode.INVOKEINTERFACE: {
+ int index = this.iter.s16bitAt(pos + 1);
+ return new MethodEntry(
+ new ClassEntry(Descriptor.toJvmName(this.constants.getInterfaceMethodrefClassName(index))),
+ this.constants.getInterfaceMethodrefName(index),
+ new Signature(this.constants.getInterfaceMethodrefType(index))
+ );
+ }
+ }
+ return null;
+ }
+
+ public Iterable casts() {
+ return () -> CheckCastIterator.this;
+ }
+}
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
index 4a77eec..c13aae4 100644
--- a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
+++ b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java
@@ -90,6 +90,16 @@ public class ClassRenamer {
});
}
+ public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) {
+ renameClasses(c, className -> {
+ ClassEntry entry = new ClassEntry(className);
+ if (entry.getPackageName().equals(oldPackageName)) {
+ return entry.getSimpleName();
+ }
+ return null;
+ });
+ }
+
@SuppressWarnings("unchecked")
public static void renameClasses(CtClass c, ClassNameReplacer replacer) {
diff --git a/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java
index af8c79a..256df61 100644
--- a/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java
@@ -17,6 +17,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
+import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor;
import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor;
import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor;
import javassist.bytecode.ConstPool;
@@ -77,6 +78,22 @@ public class ConstPoolEditor {
this.pool = pool;
}
+ public void writePool(DataOutputStream out) {
+ try {
+ methodWritePool.invoke(this.pool, out);
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ public static ConstPool readPool(DataInputStream in) {
+ try {
+ return constructorPool.newInstance(in);
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
public String getMemberrefClassname(int memberrefIndex) {
return Descriptor.toJvmName(this.pool.getClassInfo(this.pool.getMemberClass(memberrefIndex)));
}
@@ -101,6 +118,48 @@ public class ConstPoolEditor {
}
}
+ public int addItem(Object item) {
+ try {
+ return (Integer) addItem.invoke(this.pool, item);
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ public int addItemForceNew(Object item) {
+ try {
+ return (Integer) addItem0.invoke(this.pool, item);
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void removeLastItem() {
+ try {
+ // remove the item from the cache
+ HashMap cache = getCache();
+ if (cache != null) {
+ Object item = getItem(this.pool.getSize() - 1);
+ cache.remove(item);
+ }
+
+ // remove the actual item
+ // based off of LongVector.addElement()
+ Object item = items.get(this.pool);
+ Object[][] object = (Object[][]) objects.get(items);
+ int numElements = (Integer) elements.get(items) - 1;
+ int nth = numElements >> 7;
+ int offset = numElements & (128 - 1);
+ object[nth][offset] = null;
+
+ // decrement the number of items
+ elements.set(item, numElements);
+ numItems.set(this.pool, (Integer) numItems.get(this.pool) - 1);
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
@SuppressWarnings("rawtypes")
public HashMap getCache() {
@@ -138,4 +197,67 @@ public class ConstPoolEditor {
assert (newName.equals(getMemberrefName(memberrefIndex)));
assert (newType.equals(getMemberrefType(memberrefIndex)));
}
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void changeClassName(int classNameIndex, String newName) {
+ // NOTE: when changing values, we always need to copy-on-write
+ try {
+ // get the class item
+ Object item = getItem(classNameIndex).getItem();
+
+ // update the cache
+ HashMap cache = getCache();
+ if (cache != null) {
+ cache.remove(item);
+ }
+
+ // add the new name and repoint the name-and-type to it
+ new ClassInfoAccessor(item).setNameIndex(this.pool.addUtf8Info(newName));
+
+ // update the cache
+ if (cache != null) {
+ cache.put(item, item);
+ }
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ public static ConstPool newConstPool() {
+ // const pool expects the name of a class to initialize itself
+ // but we want an empty pool
+ // so give it a bogus name, and then clear the entries afterwards
+ ConstPool pool = new ConstPool("a");
+
+ ConstPoolEditor editor = new ConstPoolEditor(pool);
+ int size = pool.getSize();
+ for (int i = 0; i < size - 1; i++) {
+ editor.removeLastItem();
+ }
+
+ // make sure the pool is actually empty
+ // although, in this case "empty" means one thing in it
+ // the JVM spec says index 0 should be reserved
+ assert (pool.getSize() == 1);
+ assert (editor.getItem(0) == null);
+ assert (editor.getItem(1) == null);
+ assert (editor.getItem(2) == null);
+ assert (editor.getItem(3) == null);
+
+ // also, clear the cache
+ editor.getCache().clear();
+
+ return pool;
+ }
+
+ public String dump() {
+ StringBuilder buf = new StringBuilder();
+ for (int i = 1; i < this.pool.getSize(); i++) {
+ buf.append(String.format("%4d", i));
+ buf.append(" ");
+ buf.append(getItem(i).toString());
+ buf.append("\n");
+ }
+ return buf.toString();
+ }
}
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java
index 316bb5e..66f2283 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java
@@ -39,6 +39,10 @@ public class ClassInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.ClassInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java
index 474a3ef..bc7af87 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java
@@ -10,8 +10,12 @@
******************************************************************************/
package cuchaz.enigma.bytecode.accessors;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Field;
@@ -55,6 +59,44 @@ public class ConstInfoAccessor {
}
}
+ public ConstInfoAccessor copy() {
+ return new ConstInfoAccessor(copyItem());
+ }
+
+ public Object copyItem() {
+ // I don't know of a simpler way to copy one of these silly things...
+ try {
+ // serialize the item
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(buf);
+ write(out);
+
+ // deserialize the item
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf.toByteArray()));
+ Object item = new ConstInfoAccessor(in).getItem();
+ in.close();
+
+ return item;
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ try {
+ out.writeUTF(this.item.getClass().getName());
+ out.writeInt(getIndex());
+
+ Method method = this.item.getClass().getMethod("write", DataOutputStream.class);
+ method.setAccessible(true);
+ method.invoke(this.item, out);
+ } catch (IOException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
@Override
public String toString() {
try {
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java
index a158394..69aee16 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java
@@ -57,6 +57,10 @@ public class InvokeDynamicInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.InvokeDynamicInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java
index 2835508..0e0297b 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java
@@ -56,6 +56,10 @@ public class MemberRefInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.MemberrefInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java
index a203b43..9a7dd69 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java
@@ -56,6 +56,10 @@ public class MethodHandleInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.MethodHandleInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java
index 993c79b..5ec9c3b 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java
@@ -39,6 +39,10 @@ public class MethodTypeInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.MethodTypeInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java
index d6c2531..95df37c 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java
@@ -56,6 +56,10 @@ public class NameAndTypeInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.NameAndTypeInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java
index e211381..1c55a44 100644
--- a/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java
@@ -39,6 +39,10 @@ public class StringInfoAccessor {
}
}
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+
static {
try {
clazz = Class.forName("javassist.bytecode.StringInfo");
diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java
new file mode 100644
index 0000000..7a2cb66
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * 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.accessors;
+
+public class Utf8InfoAccessor {
+
+ private static Class> clazz;
+
+ static {
+ try {
+ clazz = Class.forName("javassist.bytecode.Utf8Info");
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+ }
+
+ public static boolean isType(ConstInfoAccessor accessor) {
+ return clazz.isAssignableFrom(accessor.getItem().getClass());
+ }
+}
--
cgit v1.2.3