Remove debug class writing. Add class signing
This commit is contained in:
parent
89f25af378
commit
4f5da66edc
19 changed files with 1129 additions and 322 deletions
|
@ -4,11 +4,10 @@ apply plugin: 'eclipse'
|
|||
repositories {
|
||||
maven {
|
||||
url "https://libraries.minecraft.net/"
|
||||
// Needs .poms in order to function
|
||||
// url "https://mcphackers.github.io/libraries/"
|
||||
}
|
||||
mavenCentral()
|
||||
flatDir {
|
||||
dirs "lib"
|
||||
}
|
||||
}
|
||||
|
||||
group = 'org.mcphackers'
|
||||
|
@ -17,8 +16,8 @@ version = '1.0'
|
|||
sourceCompatibility = 1.6
|
||||
|
||||
dependencies {
|
||||
implementation name: 'lwjgl-2.9.4'
|
||||
implementation name: 'lwjgl_util-2.9.4'
|
||||
// implementation 'org.lwjgl:lwjgl:2.9.4'
|
||||
// implementation 'org.lwjgl:lwjgl_util:2.9.4'
|
||||
implementation 'org.ow2.asm:asm:9.3'
|
||||
implementation 'org.ow2.asm:asm-tree:9.3'
|
||||
implementation 'org.json:json:20220924'
|
||||
|
|
Binary file not shown.
BIN
lib/lwjgl.jar
BIN
lib/lwjgl.jar
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -42,7 +42,4 @@ public class AppletLaunchTarget extends LaunchTarget {
|
|||
}
|
||||
AppletWrapper.startApplet(appletClass, width, height, title, icon);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
@ -36,16 +37,21 @@ public class LaunchConfig {
|
|||
public LaunchParameter<String> versionType = new LaunchParameter<String>("versionType", String.class);
|
||||
public LaunchParameter<Boolean> applet = new LaunchParameter<Boolean>("applet", Boolean.class, false);
|
||||
public LaunchParameter<Boolean> haspaid = new LaunchParameter<Boolean>("haspaid", Boolean.class, true);
|
||||
public LaunchParameter<String> loadmap_user = new LaunchParameter<String>("loadmap_user", String.class);
|
||||
public LaunchParameter<Integer> loadmap_id = new LaunchParameter<Integer>("loadmap_id", Integer.class);
|
||||
public LaunchParameter<String> mppass = new LaunchParameter<String>("mppass", String.class, "");
|
||||
public LaunchParameter<Boolean> lwjglFrame = new LaunchParameter<Boolean>("lwjglFrame", Boolean.class, true, true);
|
||||
public LaunchParameter<Boolean> isom = new LaunchParameter<Boolean>("isom", Boolean.class, false, true);
|
||||
public LaunchParameter<Boolean> forceVsync = new LaunchParameter<Boolean>("forceVsync", Boolean.class, false, true);
|
||||
public LaunchParameter<String> skinProxy = new LaunchParameter<String>("skinProxy", String.class, null, true);
|
||||
public LaunchParameter<Integer> resourcesProxyPort = new LaunchParameter<Integer>("resourcesProxyPort", Integer.class, null, true);
|
||||
|
||||
public LaunchConfig(String[] args) {
|
||||
int i = 0;
|
||||
while(i < args.length) {
|
||||
if(args[i].startsWith("--")) {
|
||||
String paramName = args[i].substring(2);
|
||||
LaunchParameter<Object> param = parameters.get(paramName);
|
||||
LaunchParameter<Object> param = parameters.get(paramName.toLowerCase(Locale.ROOT));
|
||||
if(param != null && param.type == Boolean.class) {
|
||||
param.set(true);
|
||||
}
|
||||
|
@ -54,16 +60,15 @@ public class LaunchConfig {
|
|||
}
|
||||
else if(i + 1 < args.length) {
|
||||
try {
|
||||
LaunchParameter<Object> param2 = parameters.get(paramName);
|
||||
if(param2 != null) {
|
||||
if(param != null) {
|
||||
if(param.type == String.class) {
|
||||
param2.set(args[i + 1]);
|
||||
param.set(args[i + 1]);
|
||||
}
|
||||
else if(param.type == File.class) {
|
||||
param2.set(new File(args[i + 1]));
|
||||
param.set(new File(args[i + 1]));
|
||||
}
|
||||
else if(param.type == Integer.class) {
|
||||
param2.set(Integer.valueOf(args[i + 1]));
|
||||
param.set(Integer.valueOf(args[i + 1]));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -119,7 +124,7 @@ public class LaunchConfig {
|
|||
public LaunchParameter(String name, Class<?> type, T defaultValue) {
|
||||
this.type = type;
|
||||
this.value = defaultValue;
|
||||
parameters.put(name, (LaunchParameter<Object>) this);
|
||||
parameters.put(name.toLowerCase(Locale.ROOT), (LaunchParameter<Object>) this);
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
|
|
|
@ -24,10 +24,16 @@ public class Inject {
|
|||
return new AppletWrapper(LAUNCH.config.getArgsAsMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indev load level injection
|
||||
*/
|
||||
public static File getLevelFile(int index) {
|
||||
return new File(LAUNCH.config.gameDir.get(), "levels/level" + index + ".dat");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indev save level injection
|
||||
*/
|
||||
public static File saveLevel(int index, String levelName) {
|
||||
final int maxLevels = 5;
|
||||
File levels = new File(LAUNCH.config.gameDir.get(), "levels");
|
||||
|
|
|
@ -9,6 +9,10 @@ import java.io.InputStream;
|
|||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLConnection;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -23,7 +27,7 @@ import org.objectweb.asm.tree.FieldNode;
|
|||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
||||
|
||||
|
||||
private static LaunchClassLoader INSTANCE;
|
||||
|
||||
private ClassLoader parent;
|
||||
|
@ -84,28 +88,29 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
|||
protected Class<?> redefineClass(String name) {
|
||||
byte[] classData = getClassAsBytes(name);
|
||||
if(classData == null) return null;
|
||||
Class<?> definedClass = defineClass(name, classData, 0, classData.length);
|
||||
Class<?> definedClass = defineClass(name, classData, 0, classData.length, getProtectionDomain(name));
|
||||
classes.put(name, definedClass);
|
||||
return definedClass;
|
||||
}
|
||||
|
||||
private ProtectionDomain getProtectionDomain(String name) {
|
||||
final URL resource = parent.getResource(classResourceName(name));
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
URLConnection urlConnection;
|
||||
try {
|
||||
urlConnection = resource.openConnection();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
CodeSource codeSource = urlConnection == null ? null : new CodeSource(urlConnection.getURL(), new CodeSigner[0]);
|
||||
return new ProtectionDomain(codeSource, null);
|
||||
}
|
||||
|
||||
public void overrideClass(ClassNode node) {
|
||||
if(node == null) return;
|
||||
// if(true) {
|
||||
// File saveFolder = new File("C:/Users/User/Desktop/debug");
|
||||
// ClassWriter writer = new SafeClassWriter(parent, COMPUTE_MAXS);
|
||||
// node.accept(writer);
|
||||
// byte[] classData = writer.toByteArray();
|
||||
// File cls = new File(saveFolder, node.name + ".class");
|
||||
// cls.getParentFile().mkdirs();
|
||||
// try {
|
||||
// FileOutputStream fos = new FileOutputStream(cls);
|
||||
// fos.write(classData);
|
||||
// fos.close();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
overridenClasses.put(className(node.name), node);
|
||||
classNodeCache.put(node.name, node);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,13 @@ import java.net.URLConnection;
|
|||
|
||||
public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
|
||||
|
||||
// private LegacyProxyData data;
|
||||
//
|
||||
// public LegacyURLStreamHandler(LegacyProxyData proxyData) {
|
||||
// data = proxyData;
|
||||
// }
|
||||
private SkinType skins;
|
||||
private int port;
|
||||
|
||||
public LegacyURLStreamHandler(SkinType skins, int port) {
|
||||
this.skins = skins;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
|
@ -33,14 +35,11 @@ public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
|
|||
return new LoadLevelURLConnection(url);
|
||||
else if (path.equals("/listmaps.jsp"))
|
||||
return new ListLevelsURLConnection(url);
|
||||
else if (path.startsWith("/MinecraftResources/"))
|
||||
return new ResourceIndexURLConnection(url, true);
|
||||
else if (path.startsWith("/resources/"))
|
||||
return new ResourceIndexURLConnection(url, false);
|
||||
else if (path.startsWith("/MinecraftSkins/") || path.startsWith("/skin/"))
|
||||
return new SkinURLConnection(url);
|
||||
else if (path.startsWith("/MinecraftCloaks/") || path.startsWith("/cloak/"))
|
||||
return new SkinURLConnection(url);
|
||||
else if (path.startsWith("/MinecraftResources/") || path.startsWith("/resources/"))
|
||||
return new ResourceIndexURLConnection(url, port);
|
||||
else if (path.startsWith("/MinecraftSkins/") || path.startsWith("/skin/")
|
||||
|| path.startsWith("/MinecraftCloaks/") || path.startsWith("/cloak/"))
|
||||
return new SkinURLConnection(url, skins);
|
||||
else if(host.equals("assets.minecraft.net") && path.equals("/1_6_has_been_released.flag")) {
|
||||
return new BasicResponseURLConnection(url, "");
|
||||
//return new BasicResponseURLConnection(url, "https://web.archive.org/web/20130702232237if_/https://mojang.com/2013/07/minecraft-the-horse-update/");
|
||||
|
@ -48,4 +47,30 @@ public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
|
|||
}
|
||||
return super.openConnection(url);
|
||||
}
|
||||
|
||||
public enum SkinType {
|
||||
CLASSIC("classic"),
|
||||
PRE_B1_9("pre-b1.9"),
|
||||
PRE_1_7("pre-1.7"),
|
||||
PRE_1_8("pre-1.8"),
|
||||
DEFAULT("default");
|
||||
|
||||
private String name;
|
||||
|
||||
private SkinType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static SkinType get(String name) {
|
||||
for(SkinType skinType : values()) {
|
||||
if(skinType.name.equals(name)) {
|
||||
return skinType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ResourceIndex {
|
||||
}
|
||||
}
|
|
@ -1,23 +1,22 @@
|
|||
package org.mcphackers.launchwrapper.protocol;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.mcphackers.launchwrapper.Launch;
|
||||
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.ResourceIndex;
|
||||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public class ResourceIndexURLConnection extends URLConnection {
|
||||
private static final String[] RESOURCES = new String[] {"/resources/", "/MinecraftResources/"};
|
||||
private boolean xmlMode;
|
||||
|
||||
public ResourceIndexURLConnection(URL u, boolean xmlMode) {
|
||||
super(u);
|
||||
this.xmlMode = xmlMode;
|
||||
ResourceIndex index = null;
|
||||
int port = -1;
|
||||
|
||||
public ResourceIndexURLConnection(URL url, int port) {
|
||||
super(url);
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,35 +24,16 @@ public class ResourceIndexURLConnection extends URLConnection {
|
|||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
File assetsDir = new File(Launch.INSTANCE.config.gameDir.get(), "resources");
|
||||
String path = url.getPath();
|
||||
for(String template : RESOURCES) {
|
||||
if(path.startsWith(template)) {
|
||||
String assetName = path.substring(template.length());
|
||||
if(assetName.isEmpty()) {
|
||||
File indexFile;
|
||||
if (xmlMode) {
|
||||
indexFile = new File(assetsDir, "index.xml");
|
||||
} else {
|
||||
indexFile = new File(assetsDir, "index.txt");
|
||||
}
|
||||
if(indexFile.exists()) {
|
||||
return new FileInputStream(indexFile);
|
||||
} else {
|
||||
//TODO download from another host if missing locally
|
||||
throw new FileNotFoundException("Missing resource index");
|
||||
}
|
||||
}
|
||||
//TODO download from another host at all times
|
||||
// it only requests it if (file.length() != resourceIndexFileLength || !file.exists())
|
||||
File asset = new File(assetsDir, assetName);
|
||||
if(asset.exists()) {
|
||||
return new FileInputStream(asset);
|
||||
} else {
|
||||
throw new FileNotFoundException(assetName);
|
||||
}
|
||||
return Util.replaceHost(url, "betacraft.uk", getPort()).openStream();
|
||||
}
|
||||
}
|
||||
throw new MalformedURLException(url.toExternalForm() + " is not a resource index");
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
protected int getPort() {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.net.URL;
|
|||
import java.util.HashMap;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
|
||||
import org.mcphackers.launchwrapper.util.Base64;
|
||||
import org.mcphackers.launchwrapper.util.ImageUtils;
|
||||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
@ -38,7 +39,7 @@ public class SkinRequests {
|
|||
int attemptCount = 0;
|
||||
while(attemptCount < 2) {
|
||||
attemptCount++;
|
||||
URL nametouuidURL = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||
URL nametouuidURL = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||
HttpURLConnection connection = (HttpURLConnection)nametouuidURL.openConnection();
|
||||
if(connection.getResponseCode() == 429) {
|
||||
// wait for the block to pass
|
||||
|
@ -129,7 +130,7 @@ public class SkinRequests {
|
|||
|
||||
cape = imgu.getInByteForm();
|
||||
break;
|
||||
default:
|
||||
case DEFAULT:
|
||||
return skindata.cape;
|
||||
}
|
||||
}
|
||||
|
@ -154,18 +155,18 @@ public class SkinRequests {
|
|||
|
||||
switch(skinType) {
|
||||
case CLASSIC:
|
||||
imgu = overlayHeadLayer(imgu);
|
||||
overlayHeadLayer(imgu);
|
||||
case PRE_B1_9:
|
||||
rotateBottomTX(imgu);
|
||||
case PRE_1_7:
|
||||
useLeftArm(imgu);
|
||||
useLeftLeg(imgu);
|
||||
case PRE_1_8:
|
||||
imgu = overlay64to32(imgu);
|
||||
overlay64to32(imgu);
|
||||
if(skindata.slim)
|
||||
alexToSteve(imgu);
|
||||
imgu = imgu.crop(0, 0, 64, 32);
|
||||
default:
|
||||
case DEFAULT:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -191,13 +192,13 @@ public class SkinRequests {
|
|||
imgu.setArea(28, 16, imgu.crop(28, 16, 8, 4).flip(false, true).getImage());
|
||||
}
|
||||
|
||||
public static ImageUtils overlay64to32(ImageUtils imgu) {
|
||||
public static void overlay64to32(ImageUtils imgu) {
|
||||
// 32-64 body
|
||||
return imgu.setArea(0, 16, imgu.crop(0, 32, 56, 16).getImage(), false);
|
||||
imgu.setArea(0, 16, imgu.crop(0, 32, 56, 16).getImage(), false);
|
||||
}
|
||||
|
||||
public static ImageUtils overlayHeadLayer(ImageUtils imgu) {
|
||||
return imgu.setArea(0, 0, imgu.crop(32, 0, 32, 16).getImage(), false);
|
||||
public static void overlayHeadLayer(ImageUtils imgu) {
|
||||
imgu.setArea(0, 0, imgu.crop(32, 0, 32, 16).getImage(), false);
|
||||
}
|
||||
|
||||
public static void useLeftLeg(ImageUtils imgu) {
|
||||
|
@ -229,11 +230,4 @@ public class SkinRequests {
|
|||
// fill the 1px space on the right
|
||||
imgu.setArea(51, 16, imgu.crop(50, 16, 1, 4).getImage());
|
||||
}
|
||||
|
||||
public enum SkinType {
|
||||
CLASSIC,
|
||||
PRE_B1_9,
|
||||
PRE_1_7,
|
||||
PRE_1_8
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
package org.mcphackers.launchwrapper.protocol;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mcphackers.launchwrapper.Launch;
|
||||
import org.mcphackers.launchwrapper.protocol.SkinRequests.SkinType;
|
||||
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
|
||||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public class SkinURLConnection extends HttpURLConnection {
|
||||
|
||||
private static final String[] CLOAKS = new String[] {"/cloak/", "/MinecraftCloaks/"};
|
||||
private static final String[] SKINS = new String[] {"/skin/", "/MinecraftSkins/"};
|
||||
private static final String[] CLOAKS = {"/cloak/", "/MinecraftCloaks/"};
|
||||
private static final String[] SKINS = {"/skin/", "/MinecraftSkins/"};
|
||||
|
||||
protected SkinType skinType = SkinType.PRE_1_8;
|
||||
protected SkinType skinType;
|
||||
protected InputStream inputStream;
|
||||
|
||||
public SkinURLConnection(URL url) {
|
||||
public SkinURLConnection(URL url, SkinType skin) {
|
||||
super(url);
|
||||
responseCode = 200;
|
||||
skinType = skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -36,7 +34,7 @@ public class SkinURLConnection extends HttpURLConnection {
|
|||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
File skinDir = new File(Launch.INSTANCE.config.gameDir.get(), "skins");
|
||||
// File skinDir = new File(Launch.INSTANCE.config.gameDir.get(), "skins");
|
||||
Map<String, String> queryMap = Util.queryMap(url);
|
||||
String username = queryMap.get("user");
|
||||
String path = url.getPath();
|
||||
|
@ -57,11 +55,11 @@ public class SkinURLConnection extends HttpURLConnection {
|
|||
if (path.startsWith(template)) {
|
||||
if(username == null)
|
||||
username = path.substring(template.length()).replace(".png", "");
|
||||
File cached = new File(skinDir, username + ".png");
|
||||
if(cached.exists()) {
|
||||
inputStream = new FileInputStream(cached);
|
||||
return;
|
||||
}
|
||||
// File cached = new File(skinDir, username + ".png");
|
||||
// if(cached.exists()) {
|
||||
// inputStream = new FileInputStream(cached);
|
||||
// return;
|
||||
// }
|
||||
byte[] skinData = SkinRequests.getSkin(username, skinType);
|
||||
if(skinData != null) {
|
||||
inputStream = new ByteArrayInputStream(skinData);
|
||||
|
|
|
@ -6,11 +6,15 @@ import java.net.Proxy;
|
|||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public abstract class URLStreamHandlerProxy extends URLStreamHandler {
|
||||
private static final Map<String, URLStreamHandler> DEFAULT_HANDLERS = new HashMap<String, URLStreamHandler>();
|
||||
|
||||
protected URLStreamHandler parent;
|
||||
|
||||
@Override
|
||||
|
@ -22,7 +26,7 @@ public abstract class URLStreamHandlerProxy extends URLStreamHandler {
|
|||
if(parent == null) {
|
||||
return null;
|
||||
}
|
||||
return new URL(null, url.toString(), parent).openConnection();
|
||||
return new URL(null, url.toExternalForm(), parent).openConnection();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
|
@ -38,10 +42,16 @@ public abstract class URLStreamHandlerProxy extends URLStreamHandler {
|
|||
}
|
||||
|
||||
public static URLStreamHandler getURLStreamHandler(String protocol) {
|
||||
URLStreamHandler handler = DEFAULT_HANDLERS.get(protocol);
|
||||
if(handler != null) {
|
||||
return handler;
|
||||
}
|
||||
try {
|
||||
URL url = new URL(protocol + ":");
|
||||
Field handlerField = URL.class.getDeclaredField("handler");
|
||||
return (URLStreamHandler)Util.getObjectUnsafe(url, handlerField);
|
||||
handler = (URLStreamHandler)Util.getObjectUnsafe(url, handlerField);
|
||||
DEFAULT_HANDLERS.put(protocol, handler);
|
||||
return handler;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
|
|
|
@ -13,9 +13,10 @@ import org.mcphackers.launchwrapper.inject.InjectUtils;
|
|||
import org.mcphackers.launchwrapper.inject.InjectUtils.Access;
|
||||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler;
|
||||
import org.mcphackers.launchwrapper.protocol.SkinRequests.SkinType;
|
||||
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
|
||||
import org.mcphackers.launchwrapper.protocol.URLStreamHandlerProxy;
|
||||
import org.mcphackers.launchwrapper.util.Util;
|
||||
import org.mcphackers.rdi.util.IdentifyCall;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
@ -24,7 +25,6 @@ import org.objectweb.asm.tree.FieldInsnNode;
|
|||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
|
@ -48,13 +48,11 @@ public class LegacyTweak extends Tweak {
|
|||
"net/minecraft/client/MinecraftApplet",
|
||||
"com/mojang/minecraft/MinecraftApplet"
|
||||
};
|
||||
|
||||
public static final boolean experimentalIndevSaving = true;
|
||||
|
||||
protected ClassNode minecraft;
|
||||
protected ClassNode minecraftApplet;
|
||||
/** Class containing username and sessionId */
|
||||
protected ClassNode user;
|
||||
/** Field of user class */
|
||||
protected FieldNode userField;
|
||||
/** Field that determines if Minecraft should exit */
|
||||
protected FieldNode running;
|
||||
/** Frame width */
|
||||
|
@ -64,11 +62,7 @@ public class LegacyTweak extends Tweak {
|
|||
/** Working game directory */
|
||||
protected FieldNode mcDir;
|
||||
/** Whenever the game runs in an applet */
|
||||
protected FieldNode appletMode;
|
||||
private FieldInsnNode hasPaid;
|
||||
protected FieldNode minecraftUri;
|
||||
protected MethodNode setDemo;
|
||||
protected MethodNode setServer;
|
||||
private FieldNode appletMode;
|
||||
private FieldInsnNode defaultWidth;
|
||||
private FieldInsnNode defaultHeight;
|
||||
private FieldInsnNode fullscreenField;
|
||||
|
@ -76,9 +70,8 @@ public class LegacyTweak extends Tweak {
|
|||
private boolean supportsResizing;
|
||||
/** public static main(String[]) */
|
||||
protected MethodNode main;
|
||||
/** Class used to instantiate a Minecraft instance */
|
||||
protected ClassNode minecraftImpl;
|
||||
protected SkinType skinFormat = null; //TODO analyze and choose which format the skin should be in
|
||||
protected SkinType skinType = SkinType.DEFAULT;
|
||||
protected int port = -1;
|
||||
|
||||
public LegacyTweak(ClassNodeSource source, LaunchConfig launch) {
|
||||
super(source);
|
||||
|
@ -87,6 +80,12 @@ public class LegacyTweak extends Tweak {
|
|||
|
||||
public boolean transform() {
|
||||
init();
|
||||
if(launch.skinProxy.get() != null) {
|
||||
skinType = SkinType.get(launch.skinProxy.get());
|
||||
}
|
||||
if(launch.resourcesProxyPort.get() != null) {
|
||||
port = launch.resourcesProxyPort.get();
|
||||
}
|
||||
if(minecraft == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -95,19 +94,16 @@ public class LegacyTweak extends Tweak {
|
|||
return false;
|
||||
}
|
||||
MethodNode runTick = getTickMethod(run);
|
||||
replaceGameDirectory(mcDir);
|
||||
//fixSkinURL();
|
||||
fixSplash();
|
||||
fixPaulscode();
|
||||
fixIndevLaunch();
|
||||
addIndevSaving();
|
||||
fixA111GrayScreen();
|
||||
fixShutdown(run);
|
||||
//setOnePointSixReleased(runTick, false);
|
||||
removeCanvas(runTick);
|
||||
MethodNode init = getInit(run);
|
||||
replaceGameDirectory(init, mcDir);
|
||||
optionsLoadFix(init);
|
||||
//assetsURLFix(init);
|
||||
displayPatch(init, supportsResizing);
|
||||
fixMouseHelper(mouseHelperName);
|
||||
patchMinecraftInit();
|
||||
|
@ -126,7 +122,7 @@ public class LegacyTweak extends Tweak {
|
|||
public LaunchTarget getLaunchTarget(LaunchClassLoader loader) {
|
||||
if(main != null) {
|
||||
enableLegacyMergeSort();
|
||||
URLStreamHandlerProxy.setURLStreamHandler("http", new LegacyURLStreamHandler());
|
||||
URLStreamHandlerProxy.setURLStreamHandler("http", new LegacyURLStreamHandler(skinType, port));
|
||||
MainLaunchTarget target = new MainLaunchTarget(loader, minecraft.name);
|
||||
target.args = new String[] {launch.username.get(), launch.sessionid.get()};
|
||||
return target;
|
||||
|
@ -135,7 +131,6 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
|
||||
private void addIndevSaving() {
|
||||
final boolean experimentalIndevSaving = true;
|
||||
if(!experimentalIndevSaving) {
|
||||
return;
|
||||
}
|
||||
|
@ -170,7 +165,7 @@ public class LegacyTweak extends Tweak {
|
|||
if(compareInsn(insns2[0], ALOAD, 1)
|
||||
&& compareInsn(insns2[1], GETFIELD, idField.owner, idField.name, idField.desc)
|
||||
&& compareInsn(insns2[3], IF_ICMPNE)) {
|
||||
AbstractInsnNode[] insns3 = fill(insns2[3].getNext(), 3);
|
||||
AbstractInsnNode[] insns3 = fill(nextInsn(insns2[3]), 3);
|
||||
if(compareInsn(insns3[2], NEW)) {
|
||||
if(compareInsn(insns2[2], ICONST_2)) {
|
||||
saveLevelMenu = source.getClass(((TypeInsnNode)insns3[2]).desc);
|
||||
|
@ -239,7 +234,7 @@ public class LegacyTweak extends Tweak {
|
|||
insn = getField;
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -375,14 +370,6 @@ public class LegacyTweak extends Tweak {
|
|||
AbstractInsnNode insn = insnList.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fill(insn, 6);
|
||||
|
||||
if(mcDir != null && launch.gameDir.get() != null
|
||||
&& compareInsn(insns[1], PUTFIELD, minecraft.name, mcDir.name, mcDir.desc)
|
||||
&& compareInsn(insns[0], ALOAD)) {
|
||||
insnList.remove(insns[0]);
|
||||
insnList.insertBefore(insns[1], getGameDirectory());
|
||||
insn = insns[1];
|
||||
}
|
||||
if(iLabel == null
|
||||
&& compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraft.name, null, "Ljava/awt/Canvas;")
|
||||
|
@ -505,7 +492,7 @@ public class LegacyTweak extends Tweak {
|
|||
mouseHelperName = found ? ((MethodInsnNode)insns[2]).owner : ((MethodInsnNode)insns[4]).owner;
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
|
||||
if(afterLabel != null
|
||||
|
@ -637,70 +624,39 @@ public class LegacyTweak extends Tweak {
|
|||
debugInfo("Replaced height");
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
int thisIndex = 0;
|
||||
if(width != null && height != null) {
|
||||
if(!widthReplaced) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new VarInsnNode(ALOAD, thisIndex));
|
||||
insert.add(intInsn(launch.width.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, width.name, width.desc));
|
||||
debugInfo("Set initial width");
|
||||
}
|
||||
if(!heightReplaced) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new VarInsnNode(ALOAD, thisIndex));
|
||||
insert.add(intInsn(launch.height.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, height.name, height.desc));
|
||||
debugInfo("Set initial height");
|
||||
}
|
||||
}
|
||||
if(!fullscreenReplaced) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
if(!fullscreenReplaced && fullscreenField != null) {
|
||||
insert.add(new VarInsnNode(ALOAD, thisIndex));
|
||||
insert.add(booleanInsn(launch.fullscreen.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, fullscreenField.name, fullscreenField.desc));
|
||||
debugInfo("Set fullscreen");
|
||||
}
|
||||
if(defaultWidth != null && defaultHeight != null) {
|
||||
debugInfo("Set default width and height");
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new VarInsnNode(ALOAD, thisIndex));
|
||||
insert.add(intInsn(launch.width.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultWidth.name, defaultWidth.desc));
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new VarInsnNode(ALOAD, thisIndex));
|
||||
insert.add(intInsn(launch.height.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultHeight.name, defaultHeight.desc));
|
||||
}
|
||||
if(appletMode != null) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(booleanInsn(launch.applet.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, appletMode.name, appletMode.desc));
|
||||
}
|
||||
if(minecraftUri != null) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new LdcInsnNode("www.minecraft.net"));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, minecraftUri.name, minecraftUri.desc));
|
||||
}
|
||||
if(user != null) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new TypeInsnNode(NEW, user.name));
|
||||
insert.add(new InsnNode(DUP));
|
||||
insert.add(new LdcInsnNode(launch.username.get()));
|
||||
insert.add(new LdcInsnNode(launch.sessionid.get()));
|
||||
insert.add(new MethodInsnNode(INVOKESPECIAL, user.name, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, minecraft.name, userField.name, userField.desc));
|
||||
}
|
||||
if(hasPaid != null) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new FieldInsnNode(GETFIELD, minecraft.name, userField.name, userField.desc));
|
||||
insert.add(booleanInsn(launch.haspaid.get()));
|
||||
insert.add(new FieldInsnNode(PUTFIELD, hasPaid.owner, hasPaid.name, hasPaid.desc));
|
||||
}
|
||||
if(setDemo != null) {
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(booleanInsn(launch.demo.get()));
|
||||
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraft.name, setDemo.name, setDemo.desc));
|
||||
}
|
||||
insert.add(new InsnNode(ICONST_0));
|
||||
insert.add(new MethodInsnNode(INVOKESTATIC, "javax/imageio/ImageIO", "setUseCache", "(Z)V"));
|
||||
m.instructions.insertBefore(getLastReturn(m.instructions.getLast()), insert);
|
||||
m.instructions.insert(getSuper(m.instructions.getFirst()), insert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -755,7 +711,7 @@ public class LegacyTweak extends Tweak {
|
|||
dy = putfield.name;
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
continue method;
|
||||
}
|
||||
|
@ -764,7 +720,7 @@ public class LegacyTweak extends Tweak {
|
|||
setGrabbed = m;
|
||||
continue method;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
if(setDelta != null && setGrabbed != null && dx != null && dy != null) {
|
||||
|
@ -855,7 +811,7 @@ public class LegacyTweak extends Tweak {
|
|||
break method;
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
if(success) {
|
||||
|
@ -915,7 +871,7 @@ public class LegacyTweak extends Tweak {
|
|||
m.instructions.remove(insns[1]);
|
||||
m.instructions.remove(insns[2]);
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -942,7 +898,7 @@ public class LegacyTweak extends Tweak {
|
|||
if(insn.getOpcode() == INVOKESTATIC) {
|
||||
return;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1118,11 +1074,11 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
return run;
|
||||
}
|
||||
|
@ -1149,7 +1105,14 @@ public class LegacyTweak extends Tweak {
|
|||
|
||||
final String listenerClass = "org/mcphackers/launchwrapper/inject/WindowListener";
|
||||
|
||||
String mcField = null;
|
||||
String mcDesc = "L" + minecraft.name + ";";
|
||||
if(minecraftApplet != null) {
|
||||
for(FieldNode field : minecraftApplet.fields) {
|
||||
if(mcDesc.equals(field.desc)) {
|
||||
mcField = field.name;
|
||||
}
|
||||
}
|
||||
insns.add(new TypeInsnNode(NEW, minecraftApplet.name));
|
||||
insns.add(new InsnNode(DUP));
|
||||
insns.add(new MethodInsnNode(INVOKESPECIAL, minecraftApplet.name, "<init>", "()V"));
|
||||
|
@ -1157,6 +1120,9 @@ public class LegacyTweak extends Tweak {
|
|||
insns.add(new VarInsnNode(ALOAD, appletIndex));
|
||||
insns.add(new MethodInsnNode(INVOKESTATIC, "org/mcphackers/launchwrapper/inject/Inject", "getApplet", "()Lorg/mcphackers/launchwrapper/tweak/AppletWrapper;"));
|
||||
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/applet/Applet", "setStub", "(Ljava/applet/AppletStub;)V"));
|
||||
insns.add(new VarInsnNode(ALOAD, appletIndex));
|
||||
insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "init", "()V"));
|
||||
patchAppletInit();
|
||||
}
|
||||
if(!launch.lwjglFrame.get()) {
|
||||
insns.add(new TypeInsnNode(NEW, "java/awt/Frame"));
|
||||
|
@ -1193,17 +1159,79 @@ public class LegacyTweak extends Tweak {
|
|||
insns.add(new InsnNode(ACONST_NULL));
|
||||
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/awt/Frame", "setLocationRelativeTo", "(Ljava/awt/Component;)V"));
|
||||
}
|
||||
insns.add(getMinecraftImpl());
|
||||
if(minecraftApplet != null) {
|
||||
insns.add(new VarInsnNode(ALOAD, appletIndex));
|
||||
insns.add(new FieldInsnNode(GETFIELD, minecraftApplet.name, mcField, mcDesc));
|
||||
} else {
|
||||
insns.add(getNewMinecraftImpl(minecraft, null));
|
||||
}
|
||||
insns.add(new VarInsnNode(ASTORE, mcIndex));
|
||||
if(width != null && height != null) {
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(intInsn(launch.width.get()));
|
||||
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, width.name, width.desc));
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(intInsn(launch.height.get()));
|
||||
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, height.name, height.desc));
|
||||
}
|
||||
if(fullscreenField != null) {
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(booleanInsn(launch.fullscreen.get()));
|
||||
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, fullscreenField.name, fullscreenField.desc));
|
||||
}
|
||||
if(defaultWidth != null && defaultHeight != null) {
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(intInsn(launch.width.get()));
|
||||
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultWidth.name, defaultWidth.desc));
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(intInsn(launch.height.get()));
|
||||
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, defaultHeight.name, defaultHeight.desc));
|
||||
}
|
||||
if(appletMode != null) {
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(booleanInsn(launch.applet.get()));
|
||||
insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, appletMode.name, appletMode.desc));
|
||||
}
|
||||
// if(minecraftUri != null) {
|
||||
// insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
// insns.add(new LdcInsnNode("www.minecraft.net"));
|
||||
// insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, minecraftUri.name, minecraftUri.desc));
|
||||
// }
|
||||
// if(user != null) {
|
||||
// insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
// insns.add(new TypeInsnNode(NEW, user.name));
|
||||
// insns.add(new InsnNode(DUP));
|
||||
// insns.add(new LdcInsnNode(launch.username.get()));
|
||||
// insns.add(new LdcInsnNode(launch.sessionid.get()));
|
||||
// insns.add(new MethodInsnNode(INVOKESPECIAL, user.name, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"));
|
||||
// insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, userField.name, userField.desc));
|
||||
// }
|
||||
// if(hasPaid != null) {
|
||||
// insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
// insns.add(new FieldInsnNode(GETFIELD, minecraft.name, userField.name, userField.desc));
|
||||
// insns.add(booleanInsn(launch.haspaid.get()));
|
||||
// insns.add(new FieldInsnNode(PUTFIELD, hasPaid.owner, hasPaid.name, hasPaid.desc));
|
||||
// }
|
||||
// if(setDemo != null) {
|
||||
// insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
// insns.add(booleanInsn(launch.demo.get()));
|
||||
// insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraft.name, setDemo.name, setDemo.desc));
|
||||
// }
|
||||
// if(setServer != null && launch.server.get() != null) {
|
||||
// insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
// insns.add(new LdcInsnNode(launch.server.get()));
|
||||
// insns.add(intInsn(launch.port.get()));
|
||||
// insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraft.name, setServer.name, setServer.desc));
|
||||
// }
|
||||
insns.add(new TypeInsnNode(NEW, "java/lang/Thread"));
|
||||
insns.add(new InsnNode(DUP));
|
||||
insns.add(new VarInsnNode(ALOAD, mcIndex));
|
||||
insns.add(new LdcInsnNode("Minecraft main thread"));
|
||||
insns.add(new MethodInsnNode(INVOKESPECIAL, "java/lang/Thread", "<init>", "(Ljava/lang/Runnable;Ljava/lang/String;)V"));
|
||||
insns.add(new VarInsnNode(ASTORE, threadIndex));
|
||||
insns.add(new VarInsnNode(ALOAD, threadIndex));
|
||||
insns.add(new IntInsnNode(BIPUSH, 10));
|
||||
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/Thread", "setPriority", "(I)V"));
|
||||
// insns.add(new VarInsnNode(ALOAD, threadIndex));
|
||||
// insns.add(new IntInsnNode(BIPUSH, 10));
|
||||
// insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/Thread", "setPriority", "(I)V"));
|
||||
if(!launch.lwjglFrame.get()) {
|
||||
insns.add(new VarInsnNode(ALOAD, frameIndex));
|
||||
insns.add(new InsnNode(ICONST_1));
|
||||
|
@ -1224,6 +1252,75 @@ public class LegacyTweak extends Tweak {
|
|||
return node;
|
||||
}
|
||||
|
||||
private void patchAppletInit() {
|
||||
String mcField = null;
|
||||
String canvasField = null;
|
||||
String mcDesc = "L" + minecraft.name + ";";
|
||||
MethodNode init = InjectUtils.getMethod(minecraftApplet, "init", "()V");
|
||||
if(init == null) {
|
||||
throw new IllegalStateException("Missing applet init");
|
||||
}
|
||||
for(FieldNode field : minecraftApplet.fields) {
|
||||
if(mcDesc.equals(field.desc)) {
|
||||
field.access = Access.PUBLIC.setAccess(field.access);
|
||||
mcField = field.name;
|
||||
}
|
||||
if("Ljava/awt/Canvas;".equals(field.desc)) {
|
||||
canvasField = field.name;
|
||||
}
|
||||
}
|
||||
AbstractInsnNode insn = init.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns2 = fill(insn, 5);
|
||||
if(compareInsn(insns2[1], PUTFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns2[0], INVOKESPECIAL, null, "<init>")) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)insns2[0];
|
||||
init.instructions.insertBefore(insns2[1], getNewMinecraftImpl(source.getClass(invoke.owner), canvasField));
|
||||
IdentifyCall call = new IdentifyCall(invoke);
|
||||
AbstractInsnNode newInsn = call.getArgument(0)[0].getPrevious();
|
||||
if(newInsn.getOpcode() == NEW) {
|
||||
init.instructions.remove(newInsn);
|
||||
}
|
||||
for(AbstractInsnNode[] arg : call.getArguments()) {
|
||||
remove(init.instructions, arg);
|
||||
}
|
||||
init.instructions.remove(invoke);
|
||||
insn = insns2[1];
|
||||
}
|
||||
if(compareInsn(insns2[0], ALOAD, 0)
|
||||
&& compareInsn(insns2[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns2[2], LDC, "79.136.77.240")
|
||||
&& compareInsn(insns2[3], SIPUSH)
|
||||
&& compareInsn(insns2[4], INVOKEVIRTUAL, minecraft.name, null, "(Ljava/lang/String;I)V")) {
|
||||
LabelNode label = new LabelNode();
|
||||
init.instructions.remove(insns2[2]);
|
||||
init.instructions.remove(insns2[3]);
|
||||
InsnList insert = new InsnList();
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new LdcInsnNode("server"));
|
||||
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new LdcInsnNode("port"));
|
||||
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
|
||||
insert.add(new MethodInsnNode(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I"));
|
||||
init.instructions.insertBefore(insns2[4], insert);
|
||||
insert = new InsnList();
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new LdcInsnNode("server"));
|
||||
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
|
||||
insert.add(new JumpInsnNode(IFNULL, label));
|
||||
insert.add(new VarInsnNode(ALOAD, 0));
|
||||
insert.add(new LdcInsnNode("port"));
|
||||
insert.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;"));
|
||||
insert.add(new JumpInsnNode(IFNULL, label));
|
||||
init.instructions.insertBefore(insns2[0], insert);
|
||||
init.instructions.insert(insns2[4], label);
|
||||
}
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
source.overrideClass(minecraftApplet);
|
||||
}
|
||||
|
||||
private void createWindowListener(String listenerClass) {
|
||||
running.access = Access.PUBLIC.setAccess(running.access);
|
||||
|
||||
|
@ -1275,7 +1372,7 @@ public class LegacyTweak extends Tweak {
|
|||
source.overrideClass(node);
|
||||
}
|
||||
|
||||
private InsnList getMinecraftImpl() {
|
||||
private InsnList getNewMinecraftImpl(ClassNode minecraftImpl, String canvasField) {
|
||||
MethodNode init = null;
|
||||
for(MethodNode m : minecraftImpl.methods) {
|
||||
if(m.name.equals("<init>")) {
|
||||
|
@ -1286,9 +1383,9 @@ public class LegacyTweak extends Tweak {
|
|||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
final int appletIndex = 1;
|
||||
final int frameIndex = 2;
|
||||
final int canvasIndex = 3;
|
||||
// final int appletIndex = 1;
|
||||
// final int frameIndex = 2;
|
||||
// final int canvasIndex = 3;
|
||||
|
||||
InsnList insns = new InsnList();
|
||||
insns.add(new TypeInsnNode(NEW, minecraftImpl.name));
|
||||
|
@ -1303,16 +1400,19 @@ public class LegacyTweak extends Tweak {
|
|||
if(launch.lwjglFrame.get()) {
|
||||
insns.add(new InsnNode(ACONST_NULL));
|
||||
} else {
|
||||
insns.add(new VarInsnNode(ALOAD, canvasIndex));
|
||||
//insns.add(new VarInsnNode(ALOAD, canvasIndex));
|
||||
insns.add(new VarInsnNode(ALOAD, 0));
|
||||
insns.add(new FieldInsnNode(GETFIELD, minecraftApplet.name, canvasField, "Ljava/awt/Canvas;"));
|
||||
}
|
||||
} else if(desc.equals("Ljava/awt/Component;")) {
|
||||
if(launch.lwjglFrame.get()) {
|
||||
insns.add(new InsnNode(ACONST_NULL));
|
||||
} else {
|
||||
insns.add(new VarInsnNode(ALOAD, frameIndex));
|
||||
//insns.add(new VarInsnNode(ALOAD, frameIndex));
|
||||
}
|
||||
} else if(minecraftApplet != null && desc.equals("L" + minecraftApplet.name + ";")) {
|
||||
insns.add(new VarInsnNode(ALOAD, appletIndex));
|
||||
//insns.add(new VarInsnNode(ALOAD, appletIndex));
|
||||
insns.add(new VarInsnNode(ALOAD, 0));
|
||||
}
|
||||
else if(desc.equals("I")) {
|
||||
if(i == 0) {
|
||||
|
@ -1333,16 +1433,25 @@ public class LegacyTweak extends Tweak {
|
|||
return insns;
|
||||
}
|
||||
|
||||
public void fixSplash() {
|
||||
private void fixSplash() {
|
||||
for(MethodNode m : minecraft.methods) {
|
||||
for(AbstractInsnNode insn : m.instructions) {
|
||||
if(insn.getOpcode() == LDC) {
|
||||
LdcInsnNode ldc = (LdcInsnNode)insn;
|
||||
if(ldc.cst.equals("/title/mojang.png")) {
|
||||
AbstractInsnNode insn3 = ldc.getNext();
|
||||
boolean store2 = false;
|
||||
boolean store3 = false;
|
||||
while(insn3 != null) {
|
||||
AbstractInsnNode[] insns2 = fill(insn3, 15);
|
||||
if(compareInsn(insns2[0], ALOAD)
|
||||
if(compareInsn(insns2[0], ISTORE, 2)) {
|
||||
store2 = true;
|
||||
}
|
||||
if(compareInsn(insns2[0], ISTORE, 3)) {
|
||||
store3 = true;
|
||||
}
|
||||
if(store2 && store3
|
||||
&& compareInsn(insns2[0], ALOAD)
|
||||
&& compareInsn(insns2[1], GETFIELD, null, null, "I")
|
||||
&& compareInsn(insns2[2], ICONST_2)
|
||||
&& compareInsn(insns2[3], IDIV)
|
||||
|
@ -1477,10 +1586,11 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void fixPaulscode() {
|
||||
ClassNode libraryOpenAL = source.getClass("paulscode/sound/libraries/LibraryLWJGLOpenAL");
|
||||
ClassNode libraryChannel = source.getClass("paulscode/sound/libraries/ChannelLWJGLOpenAL");
|
||||
|
@ -1543,7 +1653,7 @@ public class LegacyTweak extends Tweak {
|
|||
success |= true;
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
boolean bufferBufferField = false;
|
||||
insn = queueBuffer.instructions.getFirst();
|
||||
|
@ -1580,7 +1690,7 @@ public class LegacyTweak extends Tweak {
|
|||
success |= true;
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
insn = preLoadBuffers.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
|
@ -1622,7 +1732,7 @@ public class LegacyTweak extends Tweak {
|
|||
success |= true;
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
if(bufferBufferField) {
|
||||
if(InjectUtils.getField(libraryChannel, "bufferBuffer", "Ljava/nio/ByteBuffer;") == null) {
|
||||
|
@ -1639,7 +1749,7 @@ public class LegacyTweak extends Tweak {
|
|||
success |= true;
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1670,7 +1780,7 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1699,120 +1809,38 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
}
|
||||
|
||||
for(MethodNode method : minecraftApplet.methods) {
|
||||
if("init".equals(method.name) && "()V".equals(method.desc)) {
|
||||
AbstractInsnNode insn = method.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fillBackwards(insn, 9);
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], ALOAD)
|
||||
&& compareInsn(insns[3], INVOKEVIRTUAL, minecraftApplet.name, "getDocumentBase", "()Ljava/net/URL;")
|
||||
&& compareInsn(insns[4], INVOKEVIRTUAL, "java/net/URL", "getHost", "()Ljava/lang/String;")
|
||||
&& compareInsn(insns[5], PUTFIELD, minecraft.name, null, "Ljava/lang/String;")) {
|
||||
FieldInsnNode field = (FieldInsnNode)insns[5];
|
||||
minecraftUri = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
if(compareInsn(insns[1], PUTFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[0], INVOKESPECIAL, null, "<init>")) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)insns[0];
|
||||
minecraftImpl = source.getClass(invoke.owner);
|
||||
}
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], ICONST_1)
|
||||
&& compareInsn(insns[3], PUTFIELD, minecraft.name, null, "Z")) {
|
||||
FieldInsnNode field = (FieldInsnNode)insns[3];
|
||||
MethodNode init = InjectUtils.getMethod(minecraftApplet, "init", "()V");
|
||||
if(init != null) {
|
||||
AbstractInsnNode insn = init.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fillBackwards(insn, 8);
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], ICONST_1)
|
||||
&& compareInsn(insns[3], PUTFIELD, minecraft.name, null, "Z")) {
|
||||
FieldInsnNode field = (FieldInsnNode)insns[3];
|
||||
appletMode = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], LDC, "true")
|
||||
&& compareInsn(insns[3], ALOAD)
|
||||
&& compareInsn(insns[4], LDC, "stand-alone")
|
||||
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[6], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")) {
|
||||
AbstractInsnNode[] insns2 = fill(insns[7], 7);
|
||||
if(compareInsn(insns2[0], IFNE)
|
||||
&& compareInsn(insns2[1], ICONST_1)
|
||||
&& compareInsn(insns2[2], GOTO)
|
||||
&& compareInsn(insns2[3], ICONST_0)
|
||||
&& compareInsn(insns2[4], PUTFIELD, minecraft.name, null, "Z")) {
|
||||
FieldInsnNode field = (FieldInsnNode)insns2[4];
|
||||
appletMode = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], LDC, "true")
|
||||
&& compareInsn(insns[3], ALOAD)
|
||||
&& compareInsn(insns[4], LDC, "stand-alone")
|
||||
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[6], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")) {
|
||||
AbstractInsnNode[] insns2 = fill(insns[7], 7);
|
||||
if(compareInsn(insns2[0], IFNE)
|
||||
&& compareInsn(insns2[1], ICONST_1)
|
||||
&& compareInsn(insns2[2], GOTO)
|
||||
&& compareInsn(insns2[3], ICONST_0)
|
||||
&& compareInsn(insns2[4], PUTFIELD, minecraft.name, null, "Z")) {
|
||||
FieldInsnNode field = (FieldInsnNode)insns2[4];
|
||||
appletMode = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
}
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], GETFIELD, minecraft.name)
|
||||
&& compareInsn(insns[3], LDC, "true")
|
||||
&& compareInsn(insns[4], ALOAD)
|
||||
&& compareInsn(insns[5], LDC, "haspaid")
|
||||
&& compareInsn(insns[6], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[7], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")
|
||||
&& compareInsn(insns[8], PUTFIELD, null, null, "Z")) {
|
||||
hasPaid = (FieldInsnNode)insns[8];
|
||||
}
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[2], LDC, "true")
|
||||
&& compareInsn(insns[3], ALOAD)
|
||||
&& compareInsn(insns[4], LDC, "demo")
|
||||
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[6], INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z")
|
||||
&& compareInsn(insns[7], INVOKEVIRTUAL, minecraft.name, null, "(Z)V")) {
|
||||
MethodInsnNode call = (MethodInsnNode)insns[7];
|
||||
setDemo = InjectUtils.getMethod(minecraft, call.name, call.desc);
|
||||
}
|
||||
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], LDC, "username")
|
||||
&& compareInsn(insns[2], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[3], ALOAD)
|
||||
&& compareInsn(insns[4], LDC, "sessionid")
|
||||
&& compareInsn(insns[5], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[6], INVOKESPECIAL, null, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V")
|
||||
&& compareInsn(insns[7], PUTFIELD, minecraft.name)) {
|
||||
debugInfo("Found user field");
|
||||
MethodInsnNode invokespecial = (MethodInsnNode)insns[6];
|
||||
user = source.getClass(invokespecial.owner);
|
||||
FieldInsnNode field = (FieldInsnNode)insns[7];
|
||||
userField = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
else
|
||||
if(compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], LDC, "username")
|
||||
&& compareInsn(insns[2], INVOKEVIRTUAL, minecraftApplet.name, "getParameter", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
&& compareInsn(insns[3], LDC)
|
||||
&& compareInsn(insns[4], INVOKESPECIAL, null, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V")
|
||||
&& compareInsn(insns[5], PUTFIELD, minecraft.name)) {
|
||||
debugInfo("Found user field");
|
||||
MethodInsnNode invokespecial = (MethodInsnNode)insns[6];
|
||||
user = source.getClass(invokespecial.owner);
|
||||
FieldInsnNode field = (FieldInsnNode)insns[7];
|
||||
userField = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
else
|
||||
if(compareInsn(insns[0], GETFIELD, minecraftApplet.name, mcField, mcDesc)
|
||||
&& compareInsn(insns[1], NEW)
|
||||
&& compareInsn(insns[2], DUP)
|
||||
&& compareInsn(insns[3], INVOKESPECIAL, null, "<init>")) {
|
||||
if(compareInsn(insns[4], PUTFIELD, minecraft.name)) {
|
||||
FieldInsnNode field = (FieldInsnNode)insns[4];
|
||||
if(field.desc.startsWith("L") && field.desc.endsWith(";")) {
|
||||
debugInfo("Found user field");
|
||||
user = source.getClass(field.desc.substring(1, field.desc.length() - 1));
|
||||
userField = InjectUtils.getField(minecraft, field.name, field.desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
insn = insn.getNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(minecraftImpl == null) {
|
||||
minecraftImpl = minecraft;
|
||||
}
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1879,7 +1907,46 @@ public class LegacyTweak extends Tweak {
|
|||
return insns;
|
||||
}
|
||||
|
||||
public void replaceGameDirectory(FieldNode mcDir) {
|
||||
public void replaceGameDirectory(MethodNode init, FieldNode mcDir) {
|
||||
InsnList insnList = init.instructions;
|
||||
AbstractInsnNode insn = insnList.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fill(insn, 6);
|
||||
// Indev game dir patch
|
||||
if(mcDir != null && launch.gameDir.get() != null
|
||||
&& compareInsn(insns[1], PUTFIELD, minecraft.name, mcDir.name, mcDir.desc)
|
||||
&& compareInsn(insns[0], ALOAD)) {
|
||||
insnList.remove(insns[0]);
|
||||
insnList.insertBefore(insns[1], getGameDirectory());
|
||||
insn = insns[1];
|
||||
debugInfo("Replaced gameDir");
|
||||
}
|
||||
// Classic game dir patch
|
||||
if(mcDir == null
|
||||
&& compareInsn(insns[0], ALOAD)
|
||||
&& compareInsn(insns[1], INVOKEVIRTUAL, "java/io/File", "exists", "()Z")
|
||||
&& compareInsn(insns[2], IFNE)
|
||||
&& compareInsn(insns[3], ALOAD)
|
||||
&& compareInsn(insns[4], INVOKEVIRTUAL, "java/io/File", "mkdirs", "()Z")
|
||||
&& compareInsn(insns[5], IFNE)) {
|
||||
LabelNode lbl = ((JumpInsnNode)insns[2]).label;
|
||||
int index = ((VarInsnNode)insns[0]).var;
|
||||
|
||||
if(lbl == ((JumpInsnNode)insns[5]).label
|
||||
&& index == ((VarInsnNode)insns[3]).var) {
|
||||
AbstractInsnNode[] insns2 = fill(nextInsn(lbl), 2);
|
||||
if(compareInsn(insns2[0], ALOAD)
|
||||
&& compareInsn(insns2[1], ASTORE)) {
|
||||
if(index == ((VarInsnNode)insns2[0]).var) {
|
||||
insnList.remove(insns2[0]);
|
||||
insnList.insertBefore(insns2[1], getGameDirectory());
|
||||
debugInfo("Replaced gameDir");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
if(mcDir != null && launch.gameDir.get() != null) {
|
||||
if(InjectUtils.isStatic(mcDir)) {
|
||||
MethodNode clinit = InjectUtils.getMethod(minecraft, "<clinit>", "()V");
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.HashMap;
|
||||
|
@ -75,6 +76,15 @@ public final class Util {
|
|||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
public static URL replaceHost(URL url, String hostName, int port) {
|
||||
try {
|
||||
return new URL(url.getProtocol(), hostName, port, url.getFile());
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> queryMap(URL url) throws UnsupportedEncodingException {
|
||||
Map<String, String> queryMap = new HashMap<String, String>();
|
||||
String query = url.getQuery();
|
||||
|
|
91
src/main/java/org/mcphackers/rdi/util/IdentifyCall.java
Normal file
91
src/main/java/org/mcphackers/rdi/util/IdentifyCall.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
package org.mcphackers.rdi.util;
|
||||
|
||||
import static org.mcphackers.rdi.util.InsnHelper.range;
|
||||
import static org.mcphackers.rdi.util.InsnHelper.remove;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
|
||||
public class IdentifyCall {
|
||||
protected MethodInsnNode invokeInsn;
|
||||
protected List<AbstractInsnNode[]> arguments;
|
||||
|
||||
public IdentifyCall(MethodInsnNode invoke) {
|
||||
invokeInsn = invoke;
|
||||
arguments = initArguments();
|
||||
}
|
||||
|
||||
private List<AbstractInsnNode[]> initArguments() {
|
||||
boolean isStatic = invokeInsn.getOpcode() == Opcodes.INVOKESTATIC;
|
||||
Type[] argTypes = Type.getArgumentTypes(invokeInsn.desc);
|
||||
List<AbstractInsnNode[]> args = new ArrayList<AbstractInsnNode[]>(argTypes.length);
|
||||
if(argTypes.length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
AbstractInsnNode insn = invokeInsn.getPrevious();
|
||||
AbstractInsnNode start = null;
|
||||
AbstractInsnNode end = insn;
|
||||
for(int currentArg = argTypes.length - 1; currentArg >= 0; currentArg--) {
|
||||
int stack = argTypes[currentArg].getSize();
|
||||
end = insn;
|
||||
while(stack > 0) {
|
||||
stack -= OPHelper.getStackSizeDelta(insn);
|
||||
if(stack == 0) {
|
||||
start = insn;
|
||||
}
|
||||
insn = insn.getPrevious();
|
||||
}
|
||||
if(start != null) {
|
||||
while(args.size() <= currentArg) {
|
||||
args.add(null);
|
||||
}
|
||||
args.set(currentArg, range(start, end));
|
||||
}
|
||||
}
|
||||
if(!isStatic) {
|
||||
int stack = 1;
|
||||
end = insn;
|
||||
while(stack > 0) {
|
||||
stack -= OPHelper.getStackSizeDelta(insn);
|
||||
if(stack == 0) {
|
||||
start = insn;
|
||||
}
|
||||
insn = insn.getPrevious();
|
||||
}
|
||||
args.add(0, range(start, end));
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of insn node arrays with each argument
|
||||
* Non-static methods include the owner of a call at index 0
|
||||
* @return
|
||||
*/
|
||||
public List<AbstractInsnNode[]> getArguments() {
|
||||
return Collections.unmodifiableList(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of insn nodes belonging to the argument at that index
|
||||
* Non-static methods include the owner of a call at index 0
|
||||
* @return
|
||||
*/
|
||||
public AbstractInsnNode[] getArgument(int index) {
|
||||
return arguments.get(index);
|
||||
}
|
||||
|
||||
public static void removeCall(InsnList insns, MethodInsnNode invoke) {
|
||||
for(AbstractInsnNode[] arg : new IdentifyCall(invoke).getArguments()) {
|
||||
remove(insns, arg);
|
||||
}
|
||||
insns.remove(invoke);
|
||||
}
|
||||
}
|
236
src/main/java/org/mcphackers/rdi/util/InsnHelper.java
Normal file
236
src/main/java/org/mcphackers/rdi/util/InsnHelper.java
Normal file
|
@ -0,0 +1,236 @@
|
|||
package org.mcphackers.rdi.util;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static org.objectweb.asm.tree.AbstractInsnNode.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
public class InsnHelper {
|
||||
|
||||
public static AbstractInsnNode[] fill(AbstractInsnNode insn, int size) {
|
||||
AbstractInsnNode[] arr = new AbstractInsnNode[size];
|
||||
int i = 0;
|
||||
while(insn != null && i < size) {
|
||||
arr[i] = insn;
|
||||
insn = insn.getNext();
|
||||
i++;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static void removeRange(InsnList insns, AbstractInsnNode first, AbstractInsnNode last) {
|
||||
if(first == null || last == null) {
|
||||
return;
|
||||
}
|
||||
AbstractInsnNode next = first;
|
||||
while(next != null && next != last) {
|
||||
AbstractInsnNode forRemoval = next;
|
||||
next = next.getNext();
|
||||
insns.remove(forRemoval);
|
||||
}
|
||||
insns.remove(last);
|
||||
}
|
||||
|
||||
public static void remove(InsnList insns, AbstractInsnNode... toRemove) {
|
||||
for(AbstractInsnNode insn : toRemove) {
|
||||
insns.remove(insn);
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractInsnNode[] range(AbstractInsnNode start, AbstractInsnNode end) {
|
||||
List<AbstractInsnNode> list = new LinkedList<AbstractInsnNode>();
|
||||
AbstractInsnNode insn = start;
|
||||
while(insn != end) {
|
||||
list.add(insn);
|
||||
insn = insn.getNext();
|
||||
}
|
||||
list.add(end);
|
||||
AbstractInsnNode[] arr = new AbstractInsnNode[list.size()];
|
||||
return list.toArray(arr);
|
||||
}
|
||||
|
||||
public static InsnList clone(Iterable<AbstractInsnNode> insnList) {
|
||||
Map<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
|
||||
for (AbstractInsnNode insn : insnList) {
|
||||
if (insn.getType() == LABEL) {
|
||||
LabelNode label = (LabelNode) insn;
|
||||
labels.put(label, new LabelNode());
|
||||
}
|
||||
}
|
||||
|
||||
InsnList destList = new InsnList();
|
||||
for (AbstractInsnNode insn : insnList) {
|
||||
AbstractInsnNode insnCopy = insn.clone(labels);
|
||||
destList.add(insnCopy);
|
||||
}
|
||||
return destList;
|
||||
}
|
||||
|
||||
public static InsnList clone(AbstractInsnNode[] insnList) {
|
||||
return clone(Arrays.asList(insnList));
|
||||
}
|
||||
|
||||
public static LabelNode labelBefore(AbstractInsnNode current) {
|
||||
current = current.getPrevious();
|
||||
while(current.getType() == LINE) { // Skip line number nodes
|
||||
current = current.getPrevious();
|
||||
}
|
||||
if(current.getType() == LABEL) {
|
||||
return (LabelNode)current;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static AbstractInsnNode nextInsn(AbstractInsnNode current) {
|
||||
while((current = current.getNext()) != null && current.getOpcode() == -1);
|
||||
return current;
|
||||
}
|
||||
|
||||
public static AbstractInsnNode previousInsn(AbstractInsnNode current) {
|
||||
while((current = current.getPrevious()) != null && current.getOpcode() == -1);
|
||||
return current;
|
||||
}
|
||||
|
||||
public static boolean containsInvoke(InsnList insns, MethodInsnNode invoke) {
|
||||
for(AbstractInsnNode insn : insns) {
|
||||
if(insn.getType() == METHOD_INSN) {
|
||||
MethodInsnNode invoke2 = (MethodInsnNode)insn;
|
||||
if(invoke2.getOpcode() == invoke.getOpcode() && invoke2.owner.equals(invoke.owner) && invoke2.name.equals(invoke.name) && invoke2.desc.equals(invoke.desc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void addTryCatch(MethodNode method, AbstractInsnNode startInsn, AbstractInsnNode endInsn, String exception) {
|
||||
addTryCatch(method, startInsn, endInsn, null, exception);
|
||||
}
|
||||
|
||||
public static void addTryCatch(MethodNode method, AbstractInsnNode startInsn, AbstractInsnNode endInsn, InsnList handle, String exception) {
|
||||
InsnList instructions = method.instructions;
|
||||
if(!instructions.contains(startInsn) || !instructions.contains(endInsn)) {
|
||||
throw new IllegalArgumentException("Instruction does not belong to the list");
|
||||
}
|
||||
LabelNode start = new LabelNode();
|
||||
LabelNode end = new LabelNode();
|
||||
LabelNode handler = new LabelNode();
|
||||
LabelNode after = new LabelNode();
|
||||
instructions.insertBefore(startInsn, start);
|
||||
InsnList insert = new InsnList();
|
||||
insert.add(end);
|
||||
insert.add(new JumpInsnNode(GOTO, after));
|
||||
insert.add(handler);
|
||||
if(handle == null) {
|
||||
insert.add(new InsnNode(POP));
|
||||
} else {
|
||||
insert.add(handle);
|
||||
}
|
||||
insert.add(after);
|
||||
instructions.insert(endInsn, insert);
|
||||
int index = 0; // FIXME Shouldn't be 0 if there are try/catch blocks within the range
|
||||
method.tryCatchBlocks.add(index, new TryCatchBlockNode(start, end, handler, exception));
|
||||
}
|
||||
|
||||
public static int getFreeIndex(InsnList instructions) {
|
||||
int lastFree = 1;
|
||||
AbstractInsnNode insn = instructions.getFirst();
|
||||
while(insn != null) {
|
||||
if(insn.getType() == VAR_INSN) {
|
||||
VarInsnNode var = (VarInsnNode)insn;
|
||||
lastFree = Math.max(lastFree, var.var + 1); //FIXME 2 if it's a double or long?
|
||||
}
|
||||
insn = insn.getNext();
|
||||
}
|
||||
return lastFree;
|
||||
}
|
||||
|
||||
public static AbstractInsnNode intInsn(int value) {
|
||||
switch(value) {
|
||||
case -1:
|
||||
return new InsnNode(ICONST_M1);
|
||||
case 0:
|
||||
return new InsnNode(ICONST_0);
|
||||
case 1:
|
||||
return new InsnNode(ICONST_1);
|
||||
case 2:
|
||||
return new InsnNode(ICONST_2);
|
||||
case 3:
|
||||
return new InsnNode(ICONST_3);
|
||||
case 4:
|
||||
return new InsnNode(ICONST_4);
|
||||
case 5:
|
||||
return new InsnNode(ICONST_5);
|
||||
default:
|
||||
if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||
return new IntInsnNode(BIPUSH, value);
|
||||
}
|
||||
else if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
return new IntInsnNode(SIPUSH, value);
|
||||
}
|
||||
else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractInsnNode longInsn(long value) {
|
||||
if(value == 0L) {
|
||||
return new InsnNode(LCONST_0);
|
||||
}
|
||||
else if(value == 1L) {
|
||||
return new InsnNode(LCONST_1);
|
||||
}
|
||||
else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractInsnNode booleanInsn(boolean value) {
|
||||
return new InsnNode(value ? ICONST_1 : ICONST_0);
|
||||
}
|
||||
|
||||
public static AbstractInsnNode floatInsn(float value) {
|
||||
if(value == 0F) {
|
||||
return new InsnNode(FCONST_0);
|
||||
}
|
||||
else if(value == 1F) {
|
||||
return new InsnNode(FCONST_1);
|
||||
}
|
||||
else if(value == 2F) {
|
||||
return new InsnNode(FCONST_2);
|
||||
}
|
||||
else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractInsnNode doubleInsn(double value) {
|
||||
if(value == 0D) {
|
||||
return new InsnNode(DCONST_0);
|
||||
}
|
||||
else if(value == 1D) {
|
||||
return new InsnNode(DCONST_1);
|
||||
}
|
||||
else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
384
src/main/java/org/mcphackers/rdi/util/OPHelper.java
Normal file
384
src/main/java/org/mcphackers/rdi/util/OPHelper.java
Normal file
|
@ -0,0 +1,384 @@
|
|||
package org.mcphackers.rdi.util;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public final class OPHelper {
|
||||
|
||||
private static final int[] STACK_SIZE_DELTA = new int[0xFF];
|
||||
|
||||
static {
|
||||
STACK_SIZE_DELTA[NOP] = 0;
|
||||
STACK_SIZE_DELTA[ACONST_NULL] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_M1] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_0] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_1] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_2] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_3] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_4] = 1;
|
||||
STACK_SIZE_DELTA[ICONST_5] = 1;
|
||||
STACK_SIZE_DELTA[LCONST_0] = 2;
|
||||
STACK_SIZE_DELTA[LCONST_1] = 1;
|
||||
STACK_SIZE_DELTA[FCONST_0] = 1;
|
||||
STACK_SIZE_DELTA[FCONST_1] = 1;
|
||||
STACK_SIZE_DELTA[FCONST_2] = 1;
|
||||
STACK_SIZE_DELTA[DCONST_0] = 2;
|
||||
STACK_SIZE_DELTA[DCONST_1] = 2;
|
||||
STACK_SIZE_DELTA[BIPUSH] = 1;
|
||||
STACK_SIZE_DELTA[SIPUSH] = 1;
|
||||
STACK_SIZE_DELTA[LDC] = 1; // special case
|
||||
STACK_SIZE_DELTA[ILOAD] = 1;
|
||||
STACK_SIZE_DELTA[LLOAD] = 2;
|
||||
STACK_SIZE_DELTA[FLOAD] = 1;
|
||||
STACK_SIZE_DELTA[DLOAD] = 2;
|
||||
STACK_SIZE_DELTA[ALOAD] = 1;
|
||||
STACK_SIZE_DELTA[IALOAD] = -1;
|
||||
STACK_SIZE_DELTA[LALOAD] = 0;
|
||||
STACK_SIZE_DELTA[FALOAD] = -1;
|
||||
STACK_SIZE_DELTA[DALOAD] = 0;
|
||||
STACK_SIZE_DELTA[AALOAD] = -1;
|
||||
STACK_SIZE_DELTA[BALOAD] = -1;
|
||||
STACK_SIZE_DELTA[CALOAD] = -1;
|
||||
STACK_SIZE_DELTA[SALOAD] = -1;
|
||||
STACK_SIZE_DELTA[ISTORE] = -1;
|
||||
STACK_SIZE_DELTA[LSTORE] = -2;
|
||||
STACK_SIZE_DELTA[FSTORE] = -1;
|
||||
STACK_SIZE_DELTA[DSTORE] = -2;
|
||||
STACK_SIZE_DELTA[ASTORE] = -1;
|
||||
STACK_SIZE_DELTA[IASTORE] = -3;
|
||||
STACK_SIZE_DELTA[LASTORE] = -4;
|
||||
STACK_SIZE_DELTA[FASTORE] = -3;
|
||||
STACK_SIZE_DELTA[DASTORE] = -4;
|
||||
STACK_SIZE_DELTA[AASTORE] = -3;
|
||||
STACK_SIZE_DELTA[BASTORE] = -3;
|
||||
STACK_SIZE_DELTA[CASTORE] = -3;
|
||||
STACK_SIZE_DELTA[SASTORE] = -3;
|
||||
STACK_SIZE_DELTA[POP] = -1;
|
||||
STACK_SIZE_DELTA[POP2] = -2;
|
||||
STACK_SIZE_DELTA[DUP] = 1;
|
||||
STACK_SIZE_DELTA[DUP_X1] = 1;
|
||||
STACK_SIZE_DELTA[DUP_X2] = 1;
|
||||
STACK_SIZE_DELTA[DUP2] = 2;
|
||||
STACK_SIZE_DELTA[DUP2_X1] = 2;
|
||||
STACK_SIZE_DELTA[DUP2_X2] = 2;
|
||||
STACK_SIZE_DELTA[SWAP] = 0;
|
||||
STACK_SIZE_DELTA[IADD] = -1;
|
||||
STACK_SIZE_DELTA[LADD] = -2;
|
||||
STACK_SIZE_DELTA[FADD] = -1;
|
||||
STACK_SIZE_DELTA[DADD] = -2;
|
||||
STACK_SIZE_DELTA[ISUB] = -1;
|
||||
STACK_SIZE_DELTA[LSUB] = -2;
|
||||
STACK_SIZE_DELTA[FSUB] = -1;
|
||||
STACK_SIZE_DELTA[DSUB] = -2;
|
||||
STACK_SIZE_DELTA[IMUL] = -1;
|
||||
STACK_SIZE_DELTA[LMUL] = -2;
|
||||
STACK_SIZE_DELTA[FMUL] = -1;
|
||||
STACK_SIZE_DELTA[DMUL] = -2;
|
||||
STACK_SIZE_DELTA[IDIV] = -1;
|
||||
STACK_SIZE_DELTA[LDIV] = -2;
|
||||
STACK_SIZE_DELTA[FDIV] = -1;
|
||||
STACK_SIZE_DELTA[DDIV] = -2;
|
||||
STACK_SIZE_DELTA[IREM] = -1;
|
||||
STACK_SIZE_DELTA[LREM] = -2;
|
||||
STACK_SIZE_DELTA[FREM] = -1;
|
||||
STACK_SIZE_DELTA[DREM] = -2;
|
||||
STACK_SIZE_DELTA[INEG] = 0;
|
||||
STACK_SIZE_DELTA[LNEG] = 0;
|
||||
STACK_SIZE_DELTA[FNEG] = 0;
|
||||
STACK_SIZE_DELTA[DNEG] = 0;
|
||||
STACK_SIZE_DELTA[ISHL] = -1;
|
||||
STACK_SIZE_DELTA[LSHL] = -1;
|
||||
STACK_SIZE_DELTA[ISHR] = -1;
|
||||
STACK_SIZE_DELTA[LSHR] = -1;
|
||||
STACK_SIZE_DELTA[IUSHR] = -1;
|
||||
STACK_SIZE_DELTA[LUSHR] = -1;
|
||||
STACK_SIZE_DELTA[IAND] = -1;
|
||||
STACK_SIZE_DELTA[LAND] = -2;
|
||||
STACK_SIZE_DELTA[IOR] = -1;
|
||||
STACK_SIZE_DELTA[LOR] = -2;
|
||||
STACK_SIZE_DELTA[IXOR] = -1;
|
||||
STACK_SIZE_DELTA[LXOR] = -2;
|
||||
STACK_SIZE_DELTA[IINC] = 0;
|
||||
STACK_SIZE_DELTA[I2L] = 1;
|
||||
STACK_SIZE_DELTA[I2F] = 0;
|
||||
STACK_SIZE_DELTA[I2D] = 1;
|
||||
STACK_SIZE_DELTA[L2I] = -1;
|
||||
STACK_SIZE_DELTA[L2F] = -1;
|
||||
STACK_SIZE_DELTA[L2D] = 0;
|
||||
STACK_SIZE_DELTA[F2I] = 0;
|
||||
STACK_SIZE_DELTA[F2L] = 1;
|
||||
STACK_SIZE_DELTA[F2D] = 1;
|
||||
STACK_SIZE_DELTA[D2I] = -1;
|
||||
STACK_SIZE_DELTA[D2L] = 0;
|
||||
STACK_SIZE_DELTA[D2F] = -1;
|
||||
STACK_SIZE_DELTA[I2B] = 0;
|
||||
STACK_SIZE_DELTA[I2C] = 0;
|
||||
STACK_SIZE_DELTA[I2S] = 0;
|
||||
STACK_SIZE_DELTA[LCMP] = -3;
|
||||
STACK_SIZE_DELTA[FCMPL] = -1;
|
||||
STACK_SIZE_DELTA[FCMPG] = -1;
|
||||
STACK_SIZE_DELTA[DCMPL] = -3;
|
||||
STACK_SIZE_DELTA[DCMPG] = -3;
|
||||
STACK_SIZE_DELTA[IFEQ] = -1;
|
||||
STACK_SIZE_DELTA[IFNE] = -1;
|
||||
STACK_SIZE_DELTA[IFLT] = -1;
|
||||
STACK_SIZE_DELTA[IFGE] = -1;
|
||||
STACK_SIZE_DELTA[IFGT] = -1;
|
||||
STACK_SIZE_DELTA[IFLE] = -1;
|
||||
STACK_SIZE_DELTA[IF_ICMPEQ] = -2;
|
||||
STACK_SIZE_DELTA[IF_ICMPNE] = -2;
|
||||
STACK_SIZE_DELTA[IF_ICMPLT] = -2;
|
||||
STACK_SIZE_DELTA[IF_ICMPGE] = -2;
|
||||
STACK_SIZE_DELTA[IF_ICMPGT] = -2;
|
||||
STACK_SIZE_DELTA[IF_ICMPLE] = -2;
|
||||
STACK_SIZE_DELTA[IF_ACMPEQ] = -2;
|
||||
STACK_SIZE_DELTA[IF_ACMPNE] = -2;
|
||||
STACK_SIZE_DELTA[GOTO] = 0;
|
||||
STACK_SIZE_DELTA[JSR] = 1;
|
||||
STACK_SIZE_DELTA[RET] = 0;
|
||||
STACK_SIZE_DELTA[TABLESWITCH] = -1;
|
||||
STACK_SIZE_DELTA[LOOKUPSWITCH] = -1;
|
||||
STACK_SIZE_DELTA[IRETURN] = -1;
|
||||
STACK_SIZE_DELTA[LRETURN] = -2;
|
||||
STACK_SIZE_DELTA[FRETURN] = -1;
|
||||
STACK_SIZE_DELTA[DRETURN] = -2;
|
||||
STACK_SIZE_DELTA[ARETURN] = -1;
|
||||
STACK_SIZE_DELTA[RETURN] = 0;
|
||||
STACK_SIZE_DELTA[GETSTATIC] = 0; // special case
|
||||
STACK_SIZE_DELTA[PUTSTATIC] = 0; // special case
|
||||
STACK_SIZE_DELTA[GETFIELD] = 0; // special case
|
||||
STACK_SIZE_DELTA[PUTFIELD] = 0; // special case
|
||||
STACK_SIZE_DELTA[INVOKEVIRTUAL] = 0; // special case
|
||||
STACK_SIZE_DELTA[INVOKESPECIAL] = 0; // special case
|
||||
STACK_SIZE_DELTA[INVOKESTATIC] = 0; // special case
|
||||
STACK_SIZE_DELTA[INVOKEINTERFACE] = 0; // special case
|
||||
STACK_SIZE_DELTA[INVOKEDYNAMIC] = 0; // special case
|
||||
STACK_SIZE_DELTA[NEW] = 1;
|
||||
STACK_SIZE_DELTA[NEWARRAY] = 0;
|
||||
STACK_SIZE_DELTA[ANEWARRAY] = 0;
|
||||
STACK_SIZE_DELTA[ARRAYLENGTH] = 0;
|
||||
STACK_SIZE_DELTA[ATHROW] = 0; // special case
|
||||
STACK_SIZE_DELTA[CHECKCAST] = 0;
|
||||
STACK_SIZE_DELTA[INSTANCEOF] = 0;
|
||||
STACK_SIZE_DELTA[MONITORENTER] = -1;
|
||||
STACK_SIZE_DELTA[MONITOREXIT] = -1;
|
||||
STACK_SIZE_DELTA[MULTIANEWARRAY] = 0; // special case
|
||||
STACK_SIZE_DELTA[IFNULL] = -1;
|
||||
STACK_SIZE_DELTA[IFNONNULL] = -1;
|
||||
}
|
||||
|
||||
public static final int getStackSizeDelta(AbstractInsnNode insn) {
|
||||
int opcode = insn.getOpcode();
|
||||
if(opcode == -1) {
|
||||
return 0;
|
||||
}
|
||||
if(insn.getType() == AbstractInsnNode.LDC_INSN) {
|
||||
LdcInsnNode ldc = (LdcInsnNode)insn;
|
||||
if(ldc.cst instanceof Double || ldc.cst instanceof Long) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if(insn.getType() == AbstractInsnNode.METHOD_INSN) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)insn;
|
||||
int sizes = Type.getArgumentsAndReturnSizes(invoke.desc);
|
||||
int argumentSizes = sizes >> 2;
|
||||
if(opcode == INVOKESTATIC) {
|
||||
argumentSizes--;
|
||||
}
|
||||
int returnSize = sizes & 3;
|
||||
return returnSize - argumentSizes;
|
||||
}
|
||||
if(insn.getType() == AbstractInsnNode.FIELD_INSN) {
|
||||
FieldInsnNode field = (FieldInsnNode)insn;
|
||||
int returnSize = Type.getType(field.desc).getSize();
|
||||
if(opcode == GETSTATIC) {
|
||||
return returnSize;
|
||||
}
|
||||
return returnSize - 1;
|
||||
}
|
||||
else if(opcode != ATHROW && opcode != MULTIANEWARRAY && opcode != INVOKEDYNAMIC) {
|
||||
return STACK_SIZE_DELTA[opcode];
|
||||
}
|
||||
throw new IllegalArgumentException("Could not get stack size delta for " + opcode);
|
||||
}
|
||||
|
||||
public static boolean isReturn(int opcode) {
|
||||
return
|
||||
opcode == RETURN ||
|
||||
opcode == IRETURN ||
|
||||
opcode == LRETURN ||
|
||||
opcode == FRETURN ||
|
||||
opcode == DRETURN ||
|
||||
opcode == ARETURN;
|
||||
}
|
||||
|
||||
public static final boolean isArrayLoad(int opcode) {
|
||||
switch (opcode) {
|
||||
case AALOAD:
|
||||
case BALOAD: // for booleans and bytes
|
||||
case CALOAD:
|
||||
case DALOAD:
|
||||
case FALOAD:
|
||||
case IALOAD:
|
||||
case LALOAD:
|
||||
case SALOAD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isVarLoad(int opcode) {
|
||||
switch (opcode) {
|
||||
case ALOAD:
|
||||
//case BLOAD: // bytes & booleans are also regular integers
|
||||
//case CLOAD: // characters are regular integers (?) under the hood
|
||||
case DLOAD:
|
||||
case FLOAD:
|
||||
case ILOAD:
|
||||
case LLOAD:
|
||||
//case SLOAD: // and so are shorts
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int reverseVarOpcode(int opcode) {
|
||||
switch (opcode) {
|
||||
case AALOAD:
|
||||
return AASTORE;
|
||||
case BALOAD:
|
||||
return BASTORE;
|
||||
case CALOAD:
|
||||
return CASTORE;
|
||||
case IALOAD:
|
||||
return IASTORE;
|
||||
case SALOAD:
|
||||
return IASTORE;
|
||||
case DALOAD:
|
||||
return IASTORE;
|
||||
case FALOAD:
|
||||
return IASTORE;
|
||||
case LALOAD:
|
||||
return IASTORE;
|
||||
case ALOAD:
|
||||
return IASTORE;
|
||||
case DLOAD:
|
||||
return IASTORE;
|
||||
case FLOAD:
|
||||
return IASTORE;
|
||||
case ILOAD:
|
||||
return IASTORE;
|
||||
case LLOAD:
|
||||
return IASTORE;
|
||||
case AASTORE:
|
||||
return AALOAD;
|
||||
case BASTORE:
|
||||
return BALOAD;
|
||||
case CASTORE:
|
||||
return CALOAD;
|
||||
case IASTORE:
|
||||
return IALOAD;
|
||||
case SASTORE:
|
||||
return SALOAD;
|
||||
case DASTORE:
|
||||
return DALOAD;
|
||||
case FASTORE:
|
||||
return FALOAD;
|
||||
case LASTORE:
|
||||
return LALOAD;
|
||||
case ASTORE:
|
||||
return ALOAD;
|
||||
case DSTORE:
|
||||
return DLOAD;
|
||||
case FSTORE:
|
||||
return FLOAD;
|
||||
case ISTORE:
|
||||
return ILOAD;
|
||||
case LSTORE:
|
||||
return LLOAD;
|
||||
default:
|
||||
throw new IllegalArgumentException("Opcode not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isVarSimilarType(int opcode1, int opcode2) {
|
||||
switch (opcode1) {
|
||||
case AALOAD:
|
||||
return opcode2 == ALOAD;
|
||||
case BALOAD:
|
||||
case CALOAD:
|
||||
case IALOAD:
|
||||
case SALOAD:
|
||||
return opcode2 == ILOAD;
|
||||
case DALOAD:
|
||||
return opcode2 == DLOAD;
|
||||
case FALOAD:
|
||||
return opcode2 == FLOAD;
|
||||
case LALOAD:
|
||||
return opcode2 == LLOAD;
|
||||
case ALOAD:
|
||||
return opcode2 == AALOAD;
|
||||
case DLOAD:
|
||||
return opcode2 == DALOAD;
|
||||
case FLOAD:
|
||||
return opcode2 == FALOAD;
|
||||
case ILOAD:
|
||||
return opcode2 == IALOAD || opcode2 == SALOAD
|
||||
|| opcode2 == BALOAD || opcode2 == CALOAD;
|
||||
case LLOAD:
|
||||
return opcode2 == LALOAD;
|
||||
// -- The same story for the store operation family --
|
||||
case AASTORE:
|
||||
return opcode2 == ASTORE;
|
||||
case BASTORE:
|
||||
case CASTORE:
|
||||
case IASTORE:
|
||||
case SASTORE:
|
||||
return opcode2 == ISTORE;
|
||||
case DASTORE:
|
||||
return opcode2 == DSTORE;
|
||||
case FASTORE:
|
||||
return opcode2 == FSTORE;
|
||||
case LASTORE:
|
||||
return opcode2 == LSTORE;
|
||||
case ASTORE:
|
||||
return opcode2 == ASTORE;
|
||||
case DSTORE:
|
||||
return opcode2 == DSTORE;
|
||||
case FSTORE:
|
||||
return opcode2 == FSTORE;
|
||||
case ISTORE:
|
||||
return opcode2 == IASTORE || opcode2 == SASTORE
|
||||
|| opcode2 == BASTORE || opcode2 == CASTORE;
|
||||
case LSTORE:
|
||||
return opcode2 == LSTORE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Opcode1 not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isVarStore(int opcode) {
|
||||
switch (opcode) {
|
||||
case ASTORE:
|
||||
//case BSTORE: // bytes & booleans are also regular integers
|
||||
//case CSTORE: // characters are regular integers (?) under the hood
|
||||
case DSTORE:
|
||||
case FSTORE:
|
||||
case ISTORE:
|
||||
case LSTORE:
|
||||
//case SSTORE: // and so are shorts
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue