Read remapped resource file
This commit is contained in:
parent
09db31e61b
commit
aff457258e
|
@ -30,6 +30,10 @@ import java.lang.invoke.MethodType;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -50,8 +54,8 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
|||
redirect(Class.class, "getSimpleName", "classGetSimpleName");
|
||||
modify(Class.class, "getName", "classGetName");
|
||||
modify(Package.class, "getName", "packageGetName");
|
||||
modify(Class.class, "forName", "classForName", String.class);
|
||||
modify(Class.class, "forName", "classForName", String.class, boolean.class, ClassLoader.class);
|
||||
redirect(Class.class, "forName", "classForName", String.class);
|
||||
redirect(Class.class, "forName", "classForName", String.class, boolean.class, ClassLoader.class);
|
||||
modify(Class.class, "getField", "classGetField", String.class);
|
||||
modify(Class.class, "getDeclaredField", "classGetDeclaredField", String.class);
|
||||
modify(Class.class, "getMethod", "classGetMethod", String.class, Class[].class);
|
||||
|
@ -65,8 +69,18 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
|||
modify(MethodHandles.Lookup.class, "findStaticGetter", "lookupFindStaticGetter", Class.class, String.class, Class.class);
|
||||
modify(MethodHandles.Lookup.class, "findStaticSetter", "lookupFindStaticSetter", Class.class, String.class, Class.class);
|
||||
modify(ClassLoader.class, "loadClass", "classLoaderLoadClass", String.class);
|
||||
// todo not enable this yet
|
||||
// modify(Method.class, "invoke", "methodInvoke", Object.class, Object[].class);
|
||||
redirect(Class.class, "getResource", "classGetResource", String.class);
|
||||
redirect(Class.class, "getResourceAsStream", "classGetResourceAsStream", String.class);
|
||||
redirect(ClassLoader.class, "getResource", "classLoaderGetResource", String.class);
|
||||
redirect(ClassLoader.class, "getResources", "classLoaderGetResources", String.class);
|
||||
redirect(ClassLoader.class, "getResourceAsStream", "classLoaderGetResourceAsStream", String.class);
|
||||
modify(Method.class, "invoke", "methodInvoke", Object.class, Object[].class);
|
||||
modify(ClassLoader.class, "defineClass", byte[].class, int.class, int.class);
|
||||
modify(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class);
|
||||
modify(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
|
||||
modify(ClassLoader.class, "defineClass", String.class, ByteBuffer.class, ProtectionDomain.class);
|
||||
modify(SecureClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class, CodeSource.class);
|
||||
modify(SecureClassLoader.class, "defineClass", String.class, ByteBuffer.class, CodeSource.class);
|
||||
}
|
||||
|
||||
public static Product4<String, Class<?>[], String, Class<?>[]> getInvokeRule(Method method) {
|
||||
|
@ -215,6 +229,10 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
private static void modify(Class<?> owner, String name, Class<?>... args) {
|
||||
modify(owner, name, name, args);
|
||||
}
|
||||
|
||||
private static void modify(Class<?> owner, String name, String handlerName, Class<?>... args) {
|
||||
addRule(true, owner, name, handlerName, args);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@ import com.google.common.collect.HashBiMap;
|
|||
import io.izzel.arclight.api.Unsafe;
|
||||
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
|
||||
import io.izzel.arclight.common.mod.util.remapper.patcher.ArclightPluginPatcher;
|
||||
import io.izzel.arclight.common.mod.util.remapper.resource.RemapSourceHandler;
|
||||
import net.md_5.specialsource.InheritanceMap;
|
||||
import net.md_5.specialsource.JarMapping;
|
||||
import net.md_5.specialsource.JarRemapper;
|
||||
import net.md_5.specialsource.provider.ClassLoaderProvider;
|
||||
import net.md_5.specialsource.provider.JointProvider;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
@ -49,6 +51,7 @@ public class ArclightRemapper {
|
|||
private final JarMapping toBukkitMapping;
|
||||
public final InheritanceMap inheritanceMap;
|
||||
private final List<PluginTransformer> transformerList = new ArrayList<>();
|
||||
private final JarRemapper toBukkitRemapper;
|
||||
|
||||
public ArclightRemapper() throws Exception {
|
||||
this.toNmsMapping = new JarMapping();
|
||||
|
@ -75,12 +78,19 @@ public class ArclightRemapper {
|
|||
this.transformerList.add(ArclightRedirectAdapter.INSTANCE);
|
||||
this.transformerList.add(ClassLoaderAdapter.INSTANCE);
|
||||
ArclightPluginPatcher.load(this.transformerList);
|
||||
toBukkitMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
||||
this.toBukkitRemapper = new LenientJarRemapper(toBukkitMapping);
|
||||
RemapSourceHandler.register();
|
||||
}
|
||||
|
||||
public static ClassLoaderRemapper createClassLoaderRemapper(ClassLoader classLoader) {
|
||||
return new ClassLoaderRemapper(INSTANCE.copyOf(INSTANCE.toNmsMapping), INSTANCE.copyOf(INSTANCE.toBukkitMapping), classLoader);
|
||||
}
|
||||
|
||||
public static JarRemapper getResourceMapper() {
|
||||
return INSTANCE.toBukkitRemapper;
|
||||
}
|
||||
|
||||
public List<PluginTransformer> getTransformerList() {
|
||||
return transformerList;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package io.izzel.arclight.common.mod.util.remapper;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
|
||||
import io.izzel.arclight.common.mod.ArclightMod;
|
||||
import io.izzel.arclight.common.mod.util.remapper.generated.RemappingURLClassLoader;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
|
@ -22,14 +20,9 @@ import org.objectweb.asm.tree.MethodNode;
|
|||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ClassLoaderAdapter implements PluginTransformer {
|
||||
|
||||
|
@ -37,38 +30,9 @@ public class ClassLoaderAdapter implements PluginTransformer {
|
|||
private static final Marker MARKER = MarkerManager.getMarker("CLADAPTER");
|
||||
private static final String CLASSLOADER = "java/lang/ClassLoader";
|
||||
|
||||
private final Map<Type, Map.Entry<Type, int[]>> defineClassTypes = ImmutableMap.<Type, Map.Entry<Type, int[]>>builder()
|
||||
.put(Type.getMethodType("(Ljava/lang/String;[BIILjava/security/CodeSource;)Ljava/lang/Class;"), Maps.immutableEntry(Type.getType(SecureClassLoader.class), new int[]{1, 3}))
|
||||
.put(Type.getMethodType("(Ljava/lang/String;Ljava/nio/ByteBuffer;Ljava/security/CodeSource;)Ljava/lang/Class;"), Maps.immutableEntry(Type.getType(SecureClassLoader.class), new int[]{1, -1}))
|
||||
.put(Type.getMethodType("([BII)Ljava/lang/Class;"), Maps.immutableEntry(Type.getType(ClassLoader.class), new int[]{0, 2}))
|
||||
.put(Type.getMethodType("(Ljava/lang/String;[BII)Ljava/lang/Class;"), Maps.immutableEntry(Type.getType(ClassLoader.class), new int[]{1, 3}))
|
||||
.put(Type.getMethodType("(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;"), Maps.immutableEntry(Type.getType(ClassLoader.class), new int[]{1, 3}))
|
||||
.put(Type.getMethodType("(Ljava/lang/String;Ljava/nio/ByteBuffer;Ljava/security/ProtectionDomain;)Ljava/lang/Class;"), Maps.immutableEntry(Type.getType(ClassLoader.class), new int[]{1, -1}))
|
||||
.build();
|
||||
private final Map<String, String> classLoaderTypes = ImmutableMap.<String, String>builder()
|
||||
.put(Type.getInternalName(URLClassLoader.class), Type.getInternalName(RemappingURLClassLoader.class))
|
||||
.build();
|
||||
private final Set<ClassLoaderRemapper.WrappedMethod> defineClassMethods = defineClassTypes.entrySet().stream()
|
||||
.map(LamdbaExceptionUtils.rethrowFunction(entry -> {
|
||||
MethodType type = MethodType.fromMethodDescriptorString(entry.getKey().getDescriptor(), getClass().getClassLoader());
|
||||
return new ClassLoaderRemapper.WrappedMethod("defineClass", type.parameterArray());
|
||||
})).collect(Collectors.toSet());
|
||||
|
||||
public static boolean isDefineClassMethod(Class<?> cl, String bukkitName, Class<?>[] pTypes) {
|
||||
if (bukkitName.equals("defineClass") && ClassLoader.class.isAssignableFrom(cl)) {
|
||||
return INSTANCE.defineClassMethods.contains(new ClassLoaderRemapper.WrappedMethod(bukkitName, pTypes));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDefineClassMethod(Class<?> cl, String bukkitName, MethodType methodType) {
|
||||
if (bukkitName.equals("defineClass") && ClassLoader.class.isAssignableFrom(cl)) {
|
||||
return INSTANCE.defineClassMethods.contains(new ClassLoaderRemapper.WrappedMethod(bukkitName, methodType.parameterArray()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleClass(ClassNode node, ClassLoaderRemapper remapper) {
|
||||
|
@ -103,88 +67,12 @@ public class ClassLoaderAdapter implements PluginTransformer {
|
|||
if (methodInsnNode.getOpcode() == Opcodes.INVOKESPECIAL && methodNode.name.equals("<init>") && methodInsnNode.name.equals("<init>") && methodInsnNode.owner.equals(node.superName)) {
|
||||
methodInsnNode.owner = info.superName;
|
||||
}
|
||||
if (methodInsnNode.name.equals("defineClass")) {
|
||||
Type descType = Type.getMethodType(methodInsnNode.desc);
|
||||
Map.Entry<Type, int[]> entry = defineClassTypes.get(descType);
|
||||
if (entry != null && GlobalClassRepo.inheritanceProvider().getAll(methodInsnNode.owner).contains(entry.getKey().getInternalName())) {
|
||||
ArclightMod.LOGGER.debug(MARKER, "Found defineClass {} call in {} {}", descType.getInternalName(), node.name, methodNode.name + methodNode.desc);
|
||||
int index = entry.getValue()[0];
|
||||
int lengthIndex = entry.getValue()[1];
|
||||
InsnList insnList = new InsnList();
|
||||
Type[] argumentTypes = descType.getArgumentTypes();
|
||||
int[] argsMap = argsMap(argumentTypes);
|
||||
storeArgs(argumentTypes, argsMap, methodNode, insnList);
|
||||
insnList.add(new InsnNode(Opcodes.DUP));
|
||||
insnList.add(new VarInsnNode(argumentTypes[index].getOpcode(Opcodes.ILOAD), methodNode.maxLocals + argsMap[index]));
|
||||
insnList.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(ClassLoaderAdapter.class), "remapClassContent", "(Ljava/lang/ClassLoader;Ljava/lang/Object;)Ljava/lang/Object;", false));
|
||||
insnList.add(new TypeInsnNode(Opcodes.CHECKCAST, argumentTypes[index].getInternalName()));
|
||||
if (lengthIndex != -1) {
|
||||
insnList.add(new InsnNode(Opcodes.DUP));
|
||||
insnList.add(new InsnNode(Opcodes.ARRAYLENGTH));
|
||||
insnList.add(new VarInsnNode(argumentTypes[lengthIndex].getOpcode(Opcodes.ISTORE), methodNode.maxLocals + argsMap[lengthIndex]));
|
||||
}
|
||||
insnList.add(new VarInsnNode(argumentTypes[index].getOpcode(Opcodes.ISTORE), methodNode.maxLocals + argsMap[index]));
|
||||
loadArgs(argumentTypes, argsMap, methodNode, insnList);
|
||||
methodNode.instructions.insertBefore(methodInsnNode, insnList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node.superName = info.superName;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static Object remapClassContent(ClassLoader classLoader, Object classContent) {
|
||||
ArclightMod.LOGGER.trace(MARKER, "Remapping class content {} from classloader {}", classContent, classLoader);
|
||||
if (!(classLoader instanceof RemappingClassLoader)) {
|
||||
throw new IllegalArgumentException("" + classLoader + " is not a remapping class loader!");
|
||||
}
|
||||
byte[] classBytes;
|
||||
if (classContent instanceof byte[]) {
|
||||
classBytes = ((byte[]) classContent);
|
||||
} else if (classContent instanceof ByteBuffer) {
|
||||
classBytes = new byte[((ByteBuffer) classContent).remaining()];
|
||||
((ByteBuffer) classContent).get(classBytes);
|
||||
} else {
|
||||
throw new IllegalArgumentException("" + classContent + " is not a recognized class content type!");
|
||||
}
|
||||
byte[] bytes = ((RemappingClassLoader) classLoader).getRemapper().remapClass(classBytes);
|
||||
if (classContent instanceof byte[]) {
|
||||
return bytes;
|
||||
} else {
|
||||
return ByteBuffer.wrap(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] argsMap(Type[] args) {
|
||||
int[] ints = new int[args.length];
|
||||
int offset = 0;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Type arg = args[i];
|
||||
ints[i] = offset;
|
||||
offset += arg.getSize();
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
private static void storeArgs(Type[] args, int[] argsMap, MethodNode node, InsnList list) {
|
||||
int start = node.maxLocals;
|
||||
for (int i = args.length - 1; i >= 0; i--) {
|
||||
Type arg = args[i];
|
||||
list.add(new VarInsnNode(arg.getOpcode(Opcodes.ISTORE), start + argsMap[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadArgs(Type[] args, int[] argsMap, MethodNode node, InsnList list) {
|
||||
int start = node.maxLocals;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Type arg = args[i];
|
||||
list.add(new VarInsnNode(arg.getOpcode(Opcodes.ILOAD), start + argsMap[i]));
|
||||
node.maxLocals += argsMap[i];
|
||||
}
|
||||
}
|
||||
|
||||
private void implementIntf(ClassNode node) {
|
||||
ArclightMod.LOGGER.debug(MARKER, "Implementing RemappingClassLoader for class {}", node.name);
|
||||
FieldNode remapper = new FieldNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC, "remapper", Type.getDescriptor(ClassLoaderRemapper.class), null, null);
|
||||
|
|
|
@ -1,25 +1,34 @@
|
|||
package io.izzel.arclight.common.mod.util.remapper.generated;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import io.izzel.arclight.api.ArclightVersion;
|
||||
import io.izzel.arclight.api.Unsafe;
|
||||
import io.izzel.arclight.common.mod.util.remapper.ArclightRedirectAdapter;
|
||||
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
||||
import io.izzel.arclight.common.util.ArrayUtil;
|
||||
import io.izzel.tools.product.Product4;
|
||||
import org.apache.commons.collections.iterators.IteratorEnumeration;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permissions;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ArclightReflectionHandler extends ClassLoader {
|
||||
|
@ -64,9 +73,6 @@ public class ArclightReflectionHandler extends ClassLoader {
|
|||
|
||||
// srg -> bukkit
|
||||
public static String redirectClassGetSimpleName(Class<?> cl) {
|
||||
if (!cl.getName().startsWith(PREFIX)) {
|
||||
return cl.getSimpleName();
|
||||
}
|
||||
String simpleName = cl.getSimpleName();
|
||||
if (simpleName.length() == 0) {
|
||||
return simpleName; // anon class
|
||||
|
@ -108,35 +114,13 @@ public class ArclightReflectionHandler extends ClassLoader {
|
|||
return handlePackageGetName(pkg.getName());
|
||||
}
|
||||
|
||||
// bukkit -> srg
|
||||
public static String handleClassForName(String cl) {
|
||||
String mapped = remapper.map(cl.replace('.', '/')).replace('/', '.');
|
||||
if (mapped.equals(cl) && cl.startsWith(PREFIX)) {
|
||||
int i = cl.lastIndexOf('.');
|
||||
if (i > 0) {
|
||||
String nest = cl.substring(0, i).replace('.', '/') + "$" + cl.substring(i + 1);
|
||||
String replace = remapper.map(nest).replace('/', '.');
|
||||
return replace.equals(nest) ? mapped : replace;
|
||||
}
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
// bukkit -> srg
|
||||
public static Class<?> redirectClassForName(String cl) throws ClassNotFoundException {
|
||||
return redirectClassForName(cl, true, Unsafe.getCallerClass().getClassLoader());
|
||||
}
|
||||
|
||||
// bukkit -> srg
|
||||
public static Object[] handleClassForName(String cl, boolean initialize, ClassLoader classLoader) {
|
||||
return new Object[]{handleClassForName(cl), initialize, classLoader};
|
||||
}
|
||||
|
||||
// bukkit -> srg
|
||||
public static Class<?> redirectClassForName(String cl, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
if (!cl.startsWith(PREFIX)) {
|
||||
return Class.forName(cl, initialize, classLoader);
|
||||
}
|
||||
try {
|
||||
String replace = remapper.mapType(cl.replace('.', '/')).replace('/', '.');
|
||||
return Class.forName(replace, initialize, classLoader);
|
||||
|
@ -307,33 +291,107 @@ public class ArclightReflectionHandler extends ClassLoader {
|
|||
}
|
||||
|
||||
public static Object[] handleClassLoaderLoadClass(ClassLoader loader, String binaryName) {
|
||||
return new Object[]{loader, binaryName.startsWith(PREFIX) ?
|
||||
remapper.mapType(binaryName.replace('.', '/')).replace('/', '.')
|
||||
: binaryName};
|
||||
return new Object[]{loader, remapper.mapType(binaryName.replace('.', '/')).replace('/', '.')};
|
||||
}
|
||||
|
||||
// bukkit -> srg
|
||||
public static Class<?> redirectClassLoaderLoadClass(ClassLoader loader, String binaryName) throws ClassNotFoundException {
|
||||
if (!binaryName.startsWith(PREFIX)) {
|
||||
return loader.loadClass(binaryName);
|
||||
}
|
||||
String replace = remapper.mapType(binaryName.replace('.', '/')).replace('/', '.');
|
||||
return loader.loadClass(replace);
|
||||
}
|
||||
|
||||
public static String findMappedResource(Class<?> cl, String name) {
|
||||
if (name.isEmpty() || !name.endsWith(".class")) return null;
|
||||
name = name.substring(0, name.length() - 6);
|
||||
String className;
|
||||
if (cl != null) {
|
||||
if (name.charAt(0) == '/') {
|
||||
className = name.substring(1);
|
||||
} else {
|
||||
Class<?> c = cl;
|
||||
while (c.isArray()) c = c.getComponentType();
|
||||
String mapped = remapper.toBukkitRemapper().mapType(c.getName().replace('.', '/'));
|
||||
int index = mapped.lastIndexOf('/');
|
||||
if (index == -1) {
|
||||
className = name;
|
||||
} else {
|
||||
className = mapped.substring(0, index) + '/' + name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
className = name;
|
||||
}
|
||||
className = remapper.mapType(className);
|
||||
if (className.startsWith("java/")) return null;
|
||||
else if (cl != null) return "/" + className + ".class";
|
||||
else return className + ".class";
|
||||
}
|
||||
|
||||
public static URL redirectClassGetResource(Class<?> cl, String name) throws MalformedURLException {
|
||||
String mappedResource = findMappedResource(cl, name);
|
||||
if (mappedResource == null) {
|
||||
return cl.getResource(name);
|
||||
} else {
|
||||
URL resource = cl.getResource(mappedResource);
|
||||
return resource == null ? null : new URL("remap:" + resource);
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream redirectClassGetResourceAsStream(Class<?> cl, String name) throws IOException {
|
||||
String mappedResource = findMappedResource(cl, name);
|
||||
if (mappedResource == null) {
|
||||
return cl.getResourceAsStream(name);
|
||||
} else {
|
||||
URL resource = cl.getResource(mappedResource);
|
||||
if (resource == null) return null;
|
||||
return new URL("remap:" + resource).openStream();
|
||||
}
|
||||
}
|
||||
|
||||
public static URL redirectClassLoaderGetResource(ClassLoader loader, String name) throws MalformedURLException {
|
||||
String mappedResource = findMappedResource(null, name);
|
||||
if (mappedResource == null) {
|
||||
return loader.getResource(name);
|
||||
} else {
|
||||
URL resource = loader.getResource(mappedResource);
|
||||
return resource == null ? null : new URL("remap:" + resource);
|
||||
}
|
||||
}
|
||||
|
||||
public static Enumeration<URL> redirectClassLoaderGetResources(ClassLoader loader, String name) throws IOException {
|
||||
String mappedResource = findMappedResource(null, name);
|
||||
if (mappedResource == null) {
|
||||
return loader.getResources(name);
|
||||
} else {
|
||||
URL resource = loader.getResource(mappedResource);
|
||||
return resource == null ? null : new IteratorEnumeration(
|
||||
Iterators.singletonIterator(new URL("remap:" + resource)));
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream redirectClassLoaderGetResourceAsStream(ClassLoader loader, String name) throws IOException {
|
||||
URL url = redirectClassLoaderGetResource(loader, name);
|
||||
if (url == null) {
|
||||
return null;
|
||||
} else {
|
||||
return url.openStream();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object[] handleMethodInvoke(Method method, Object src, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||
Product4<String, Class<?>[], String, Class<?>[]> invokeRule = ArclightRedirectAdapter.getInvokeRule(method);
|
||||
if (invokeRule != null) {
|
||||
if (invokeRule._3 != null && method.getParameterCount() > 0) {
|
||||
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._3, invokeRule._4);
|
||||
if (handleMethod.getReturnType().isArray()) {
|
||||
return (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||
if (handleMethod.getReturnType().isArray() && !Modifier.isStatic(method.getModifiers())) {
|
||||
Object[] invoke = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||
return new Object[]{method, invoke[0], Arrays.copyOfRange(invoke, 1, invoke.length)};
|
||||
} else {
|
||||
return new Object[]{method, src, handleMethod.invoke(null, param)};
|
||||
}
|
||||
} else {
|
||||
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
||||
return new Object[]{handleMethod, null, ArrayUtil.prepend(param, src)};
|
||||
Method redirectMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
||||
return new Object[]{redirectMethod, null, ArrayUtil.prepend(param, src)};
|
||||
}
|
||||
} else {
|
||||
return new Object[]{method, src, param};
|
||||
|
@ -346,44 +404,82 @@ public class ArclightReflectionHandler extends ClassLoader {
|
|||
if (invokeRule._3 != null && method.getParameterCount() > 0) {
|
||||
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._3, invokeRule._4);
|
||||
if (handleMethod.getReturnType().isArray()) {
|
||||
Object[] result = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||
return method.invoke(result[0], Arrays.copyOfRange(result, 1, result.length));
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
return method.invoke(src, (Object[]) handleMethod.invoke(null, param));
|
||||
} else {
|
||||
Object[] result = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||
return method.invoke(result[0], Arrays.copyOfRange(result, 1, result.length));
|
||||
}
|
||||
} else {
|
||||
return method.invoke(src, handleMethod.invoke(null, param));
|
||||
}
|
||||
} else {
|
||||
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
||||
return handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||
Method redirectMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
||||
return redirectMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||
}
|
||||
} else {
|
||||
return method.invoke(src, param);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> defineClass(ClassLoader loader, byte[] b, int off, int len) {
|
||||
return defineClass(loader, null, b, off, len);
|
||||
public static Object[] handleDefineClass(ClassLoader loader, byte[] b, int off, int len) {
|
||||
byte[] bytes = remapper.remapClass(b);
|
||||
return new Object[]{loader, bytes, 0, bytes.length};
|
||||
}
|
||||
|
||||
public static Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
||||
return defineClass(loader, name, b, off, len, (ProtectionDomain) null);
|
||||
public static Class<?> redirectDefineClass(ClassLoader loader, byte[] b, int off, int len) {
|
||||
return redirectDefineClass(loader, null, b, off, len);
|
||||
}
|
||||
|
||||
public static Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
||||
public static Object[] handleDefineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
||||
byte[] bytes = remapper.remapClass(b);
|
||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length};
|
||||
}
|
||||
|
||||
public static Class<?> redirectDefineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
|
||||
return redirectDefineClass(loader, name, b, off, len, (ProtectionDomain) null);
|
||||
}
|
||||
|
||||
public static Object[] handleDefineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
||||
byte[] bytes = remapper.remapClass(b);
|
||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, pd};
|
||||
}
|
||||
|
||||
public static Class<?> redirectDefineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
|
||||
byte[] bytes = remapper.remapClass(b);
|
||||
return Unsafe.defineClass(new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, loader, pd);
|
||||
}
|
||||
|
||||
public static Class<?> defineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) {
|
||||
public static Object[] handleDefineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) {
|
||||
byte[] bytes = new byte[b.remaining()];
|
||||
b.get(bytes);
|
||||
return defineClass(loader, name, bytes, 0, bytes.length, pd);
|
||||
bytes = remapper.remapClass(bytes);
|
||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), ByteBuffer.wrap(bytes), pd};
|
||||
}
|
||||
|
||||
public static Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) {
|
||||
return defineClass(loader, name, b, off, len, new ProtectionDomain(cs, new Permissions()));
|
||||
public static Class<?> redirectDefineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) {
|
||||
byte[] bytes = new byte[b.remaining()];
|
||||
b.get(bytes);
|
||||
return redirectDefineClass(loader, name, bytes, 0, bytes.length, pd);
|
||||
}
|
||||
|
||||
public static Class<?> defineClass(ClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
||||
return defineClass(loader, name, b, new ProtectionDomain(cs, new Permissions()));
|
||||
public static Object[] handleDefineClass(SecureClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) {
|
||||
byte[] bytes = remapper.remapClass(b);
|
||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), bytes, 0, bytes.length, cs};
|
||||
}
|
||||
|
||||
public static Class<?> redirectDefineClass(SecureClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) {
|
||||
return redirectDefineClass(loader, name, b, off, len, new ProtectionDomain(cs, new Permissions()));
|
||||
}
|
||||
|
||||
public static Object[] handleDefineClass(SecureClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
||||
byte[] bytes = new byte[b.remaining()];
|
||||
b.get(bytes);
|
||||
bytes = remapper.remapClass(bytes);
|
||||
return new Object[]{loader, new ClassReader(bytes).getClassName().replace('/', '.'), ByteBuffer.wrap(bytes), cs};
|
||||
}
|
||||
|
||||
public static Class<?> redirectDefineClass(SecureClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
|
||||
return redirectDefineClass(loader, name, b, new ProtectionDomain(cs, new Permissions()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,13 @@ import java.util.function.IntFunction;
|
|||
|
||||
public class ArrayUtil {
|
||||
|
||||
public static Object[] append(Object[] array, Object obj) {
|
||||
Object[] newArray = new Object[array.length + 1];
|
||||
newArray[array.length] = obj;
|
||||
System.arraycopy(array, 0, newArray, 0, array.length);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
public static Object[] prepend(Object[] array, Object obj) {
|
||||
Object[] newArray = new Object[array.length + 1];
|
||||
newArray[0] = obj;
|
||||
|
|
Loading…
Reference in New Issue
Block a user