Read remapped resource file

This commit is contained in:
IzzelAliz 2021-02-19 15:58:57 +08:00
parent 09db31e61b
commit aff457258e
5 changed files with 185 additions and 166 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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()) {
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()));
}
}

View File

@ -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;