diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRedirectAdapter.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRedirectAdapter.java index c5b44ba0..a81a55ad 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRedirectAdapter.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRedirectAdapter.java @@ -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[]> 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); } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRemapper.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRemapper.java index d6d63e4e..482924ab 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRemapper.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ArclightRemapper.java @@ -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 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 getTransformerList() { return transformerList; } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java index f62c3a15..ca3578c4 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/ClassLoaderAdapter.java @@ -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> defineClassTypes = ImmutableMap.>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 classLoaderTypes = ImmutableMap.builder() .put(Type.getInternalName(URLClassLoader.class), Type.getInternalName(RemappingURLClassLoader.class)) .build(); - private final Set 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("") && methodInsnNode.name.equals("") && methodInsnNode.owner.equals(node.superName)) { methodInsnNode.owner = info.superName; } - if (methodInsnNode.name.equals("defineClass")) { - Type descType = Type.getMethodType(methodInsnNode.desc); - Map.Entry 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); diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java index f8e3f25b..078e7f72 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/remapper/generated/ArclightReflectionHandler.java @@ -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 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[]> 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())); } } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/util/ArrayUtil.java b/arclight-common/src/main/java/io/izzel/arclight/common/util/ArrayUtil.java index 20433d60..632477b2 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/util/ArrayUtil.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/util/ArrayUtil.java @@ -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;