Asm mixins that "work"

This commit is contained in:
ThatGamerBlue
2019-05-16 14:36:19 +01:00
parent ada157ae9d
commit c9d7fc4c23
80 changed files with 39711 additions and 1759 deletions

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor;
public class MethodGarbageValue
{
private final String type;
private final int value;
public MethodGarbageValue(int value)
{
if(value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE)
{
type = "B";
}
else if(value <= Short.MAX_VALUE && value >= Short.MIN_VALUE)
{
type = "S";
}
else
{
type = "I";
}
this.value = value;
}
public int getValue()
{
return value;
}
public String getType()
{
return type;
}
public String toString()
{
return "MethodGarbageValue[type="+getType()+",value="+getValue()+"]";
}
}

View File

@@ -0,0 +1,281 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import com.google.common.reflect.ClassPath;
import io.sigpipe.jbsdiff.Patch;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.LoaderClassPath;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import us.runelitepl.mixinprocessor.generators.AnnotationProcessor;
import us.runelitepl.mixinprocessor.generators.PatchGenerator;
import us.runelitepl.mixinprocessor.generators.StaticGenerator;
import us.runelitepl.mixinprocessor.generators.StaticStageTwoGenerator;
import us.runelitepl.mixinprocessor.parsers.GamepackDownloader;
import us.runelitepl.mixinprocessor.parsers.HooksParser;
import us.runelitepl.mixinprocessor.transformers.AsmMethodGarbageTransformer;
import us.runelitepl.mixinprocessor.transformers.AsmMethodSignatureTransformer;
import us.runelitepl.mixinprocessor.util.JavassistUtils;
import us.runelitepl.mixinprocessor.util.RefUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Goal which touches a timestamp file.
*/
@Mojo(name = "process-mixins", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution =
ResolutionScope.COMPILE)
public class MixinProcessorMojo
extends AbstractMojo implements Opcodes
{
private static final String PATCHES_PACKAGE = "us.runelitepl.mixins";
/**
* Location of the file.
*/
@Parameter(defaultValue = "${project.build.directory}", property = "outputDir", required = true)
private File outputDirectory;
@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;
@Parameter(property = "process-mixins.hooks", defaultValue = "hooks.json", required = true)
private String hooks;
@Parameter(property = "process-mixins.ops", defaultValue = "gamepack.deob.jar.op.json", required = true)
private String ops;
private static MixinProcessorMojo INST;
public static ClassPool classPool;
public static HashMap<String, Long> fieldDecoders = new HashMap<>();
public static HashMap<String, String> classNames = new HashMap<>();
public static HashMap<String, String> methodNames = new HashMap<>();
public static HashMap<String, String> fieldNames = new HashMap<>();
public static HashMap<String, Boolean> isFieldTagged = new HashMap<>();
public static HashMap<String, Boolean> isMethodTagged = new HashMap<>();
public static HashMap<String, MethodGarbageValue> methodGarbageValues = new HashMap<>();
public static HashMap<String, byte[]> gamepack = new HashMap<>();
public static final int BUFFER_SIZE = 1024 * 1024 * 4;
public void execute()
throws MojoExecutionException
{
INST = this;
try
{
List runtimeClasspathElements = project.getRuntimeClasspathElements();
URL[] runtimeUrls = new URL[runtimeClasspathElements.size()];
for (int i = 0; i < runtimeClasspathElements.size(); i++)
{
String element = (String) runtimeClasspathElements.get(i);
runtimeUrls[i] = new File(element).toURI().toURL();
}
URLClassLoader classLoader = new URLClassLoader(runtimeUrls,
Thread.currentThread().getContextClassLoader());
File outputFolder = new File(project.getBuild().getOutputDirectory());
File projectDir = new File(System.getProperty("user.dir"));
File hooksFile = new File(projectDir, hooks);
File opsFile = new File(projectDir, ops);
outputFolder.mkdirs();
GamepackDownloader.downloadGamepack(gamepack);
ByteArrayOutputStream patchOutputStream = new ByteArrayOutputStream(BUFFER_SIZE); // 4mb
HooksParser.run(hooksFile, opsFile);
classPool = new ClassPool();
classPool.appendClassPath((new LoaderClassPath(classLoader)));
for (Map.Entry<String, byte[]> entry : gamepack.entrySet())
{
byte[] b1_;
try (InputStream is = getClass().getResourceAsStream("/patch/" + entry.getKey() + ".class.bs"))
{
if (is == null)
{
stderr("IS null for %s", entry.getKey());
continue;
}
b1_ = ByteStreams.toByteArray(is);
}
patchOutputStream.reset();
Patch.patch(entry.getValue(), b1_, patchOutputStream);
entry.setValue(patchOutputStream.toByteArray());
classPool.makeClass(new ByteArrayInputStream(entry.getValue()));
}
HashMap<String, byte[]> finalClasses = new HashMap<>();
ImmutableSet<ClassPath.ClassInfo> classes =
ClassPath.from(classLoader).getTopLevelClassesRecursive(PATCHES_PACKAGE);
for (ClassPath.ClassInfo clazz : classes)
{
stderr("");
stderr("Annotations: %s", clazz.getSimpleName());
CtClass ctClass = classPool.get(clazz.getName());
String className = ctClass.getSimpleName();
className = RefUtils.getObbedClassName(className);
byte[] finalCode = JavassistUtils.getClassBytecode(ctClass);
finalCode = new AnnotationProcessor(className, finalCode).run();
finalClasses.put(className, finalCode);
}
for (Map.Entry<String, byte[]> entry : finalClasses.entrySet())
{
String className = entry.getKey();
byte[] finalCode = entry.getValue();
stderr("");
stderr("Pass 1: %s", className);
finalCode = new AsmMethodSignatureTransformer(className, finalCode).transform();
finalCode = new AsmMethodGarbageTransformer(className, finalCode, finalClasses).transform();
finalClasses.put(className, finalCode);
}
stderr("");
stderr("Pass Statics");
new StaticGenerator().run(finalClasses.get(RefUtils.STATICS_STRING));
new StaticStageTwoGenerator(finalClasses).run();
for (Map.Entry<String, byte[]> entry : finalClasses.entrySet())
{
String className = entry.getKey();
if (className == null)
{
stderr("Class name null? %s", entry.getValue().length);
continue;
}
if (className.endsWith(RefUtils.STATICS_STRING))
{
continue;
}
stderr("");
stderr("Pass 2: %s", className);
byte[] finalCode = entry.getValue();
finalCode = new PatchGenerator(className, finalCode).run();
entry.setValue(finalCode);
}
deleteDir(new File(outputFolder, "us/runelitepl/mixins"));
outputFolder = new File(outputFolder, "extended-mixins");
outputFolder.mkdirs();
for (Map.Entry<String, byte[]> entry : finalClasses.entrySet())
{
if (entry.getKey().contains(RefUtils.STATICS_STRING))
{
continue;
}
Files.write(new File(outputFolder, entry.getKey() + ".class").toPath(),
entry.getValue());
}
}
catch (Exception ex)
{
ex.printStackTrace();
throw new MojoExecutionException(ex.getMessage());
}
}
public void stderr(String s, Object... format)
{
getLog().info(String.format(s, format));
}
public static void log(String s, Object... format)
{
INST.stderr(s, format);
}
static void deleteDir(File file) throws IOException
{
if (!file.exists())
{
return;
}
Files.walk(file.toPath())
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Append
{
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject
{
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Overwrite
{
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Prepend
{
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Provided
{
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Reobfuscate
{
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.enums;
public enum InjectionType
{
INJECT,
APPEND,
OVERWRITE,
PREPEND,
PROVIDED;
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.generators;
import javassist.CannotCompileException;
import javassist.CtClass;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.parsers.FieldAnnotationParser;
import us.runelitepl.mixinprocessor.parsers.MethodAnnotationParser;
import us.runelitepl.mixinprocessor.util.JavassistUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class AnnotationProcessor
{
private final String className;
private final byte[] finalCode;
public AnnotationProcessor(String className, byte[] finalCode)
{
this.className = className;
this.finalCode = finalCode;
}
public byte[] run() throws IOException, CannotCompileException, ClassNotFoundException
{
byte[] newCode = finalCode;
CtClass clazz = MixinProcessorMojo.classPool.makeClass(new ByteArrayInputStream(newCode));
new FieldAnnotationParser(clazz).run();
new MethodAnnotationParser(clazz).run();
newCode = JavassistUtils.getClassBytecode(clazz);
return newCode;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.generators;
import us.runelitepl.mixinprocessor.transformers.AnnotationRemoverTransformer;
import us.runelitepl.mixinprocessor.transformers.AsmMethodGarbageTransformer;
import us.runelitepl.mixinprocessor.transformers.AsmMethodSignatureTransformer;
import us.runelitepl.mixinprocessor.transformers.AsmNameTransformer;
import us.runelitepl.mixinprocessor.transformers.AsmStaticUsageTransformer;
import us.runelitepl.mixinprocessor.transformers.DoNothingTransformer;
import us.runelitepl.mixinprocessor.transformers.GetFieldDecoderTransformer;
import us.runelitepl.mixinprocessor.transformers.ProvidedRemoverTransformer;
public class PatchGenerator
{
private final String className;
private final byte[] bytecode;
public PatchGenerator(String className, byte[] bytecode)
{
this.className = className;
this.bytecode = bytecode;
}
public byte[] run()
{
byte[] newCode = bytecode;
newCode = new GetFieldDecoderTransformer(className, newCode).transform();
// https://asm.ow2.io/javadoc/org/objectweb/asm/commons/Remapper.html
// https://asm.ow2.io/javadoc/org/objectweb/asm/commons/ClassRemapper.html
newCode = new AsmStaticUsageTransformer(className, newCode).transform();
newCode = new AsmNameTransformer(className, newCode).transform();
newCode = new ProvidedRemoverTransformer(className, newCode).transform();
newCode = new AnnotationRemoverTransformer(className, newCode).transform();
newCode = new DoNothingTransformer(className, newCode).transform();
return newCode;
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.generators;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.NotFoundException;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.util.JavassistUtils;
import us.runelitepl.mixinprocessor.util.RefUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class StaticGenerator
{
public static HashMap<String, ArrayList<MethodNode>> staticMethods = new HashMap<>();
public static HashMap<String, ArrayList<FieldNode>> staticFields = new HashMap<>();
public static Set<String> modifiedClasses = new HashSet<>();
public void run(byte[] bytecode) throws NotFoundException, IOException, CannotCompileException
{
ClassReader cr = new ClassReader(bytecode);
ClassNode node = new ClassNode();
cr.accept(node, 0);
for (Object aaa : node.methods)
{
MethodNode method = (MethodNode) aaa;
String methodName = method.name;
method.desc = RefUtils.reobMethodDescriptor(method.desc);
int access = method.access;
if ((access & 8) != 8)
{
continue;
}
String reobbed = RefUtils.reobMethodName(RefUtils.STATICS_STRING, methodName, method.desc);
if(reobbed == null)
{
MixinProcessorMojo.log("Failed to reob static method: %s %s", methodName, method.desc);
throw new RuntimeException();
}
String[] split = reobbed.split(" ");
method.name = split[1];
ArrayList<MethodNode> list = staticMethods.getOrDefault(split[0], new ArrayList<>());
list.add(method);
staticMethods.put(split[0], list);
modifiedClasses.add(split[0]);
}
for (Object aaa : node.fields)
{
FieldNode field = (FieldNode) aaa;
String fieldName = field.name;
field.desc = RefUtils.reobDescriptor(field.desc);
int access = field.access;
if ((access & 8) != 8)
{
continue;
}
String reobbed = RefUtils.reobFieldName(RefUtils.STATICS_STRING, fieldName, field.desc);
if(reobbed == null)
{
MixinProcessorMojo.log("Failed to reob static field: %s %s", fieldName, field.desc);
throw new RuntimeException();
}
String[] split = reobbed.split(" ");
field.name = split[1];
ArrayList<FieldNode> list = staticFields.getOrDefault(split[0], new ArrayList<>());
list.add(field);
staticFields.put(split[0], list);
modifiedClasses.add(split[0]);
}
}
}

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.generators;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeAnnotationNode;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.parsers.MethodReflector;
import java.util.HashMap;
import static us.runelitepl.mixinprocessor.generators.StaticGenerator.modifiedClasses;
import static us.runelitepl.mixinprocessor.generators.StaticGenerator.staticFields;
import static us.runelitepl.mixinprocessor.generators.StaticGenerator.staticMethods;
public class StaticStageTwoGenerator implements Opcodes
{
private HashMap<String, byte[]> classes;
public StaticStageTwoGenerator(HashMap<String, byte[]> classes)
{
this.classes = classes;
}
public void run()
{
for (String className : modifiedClasses)
{
byte[] targetBytecode = classes.getOrDefault(className, null);
if (targetBytecode == null)
{
//create new class
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
cw.visit(V1_6, ACC_PUBLIC, className, null, "java/lang/Object", null);
if (staticMethods.get(className) != null)
{
for (MethodNode method : staticMethods.get(className))
{
mv = cw.visitMethod(method.access, method.name, method.desc, method.signature,
(String[]) method.exceptions.toArray(new String[0]));
MethodReflector reflector = new MethodReflector(mv);
method.accept(reflector);
}
}
if (staticFields.get(className) != null)
{
for (FieldNode field : staticFields.get(className))
{
fv = cw.visitField(field.access, field.name, field.desc, field.signature, field.value);
int i;
int n;
AnnotationNode annotation;
if (field.visibleAnnotations != null)
{
i = 0;
for (n = field.visibleAnnotations.size(); i < n; ++i)
{
annotation = (AnnotationNode) field.visibleAnnotations.get(i);
annotation.accept(fv.visitAnnotation(annotation.desc, true));
}
}
if (field.invisibleAnnotations != null)
{
i = 0;
for (n = field.invisibleAnnotations.size(); i < n; ++i)
{
annotation = (AnnotationNode) field.invisibleAnnotations.get(i);
annotation.accept(fv.visitAnnotation(annotation.desc, false));
}
}
TypeAnnotationNode typeAnnotation;
if (field.visibleTypeAnnotations != null)
{
i = 0;
for (n = field.visibleTypeAnnotations.size(); i < n; ++i)
{
typeAnnotation = (TypeAnnotationNode) field.visibleTypeAnnotations.get(i);
typeAnnotation.accept(fv
.visitTypeAnnotation(typeAnnotation.typeRef, typeAnnotation.typePath,
typeAnnotation.desc, true));
}
}
if (field.invisibleTypeAnnotations != null)
{
i = 0;
for (n = field.invisibleTypeAnnotations.size(); i < n; ++i)
{
typeAnnotation = (TypeAnnotationNode) field.invisibleTypeAnnotations.get(i);
typeAnnotation.accept(fv
.visitTypeAnnotation(typeAnnotation.typeRef, typeAnnotation.typePath,
typeAnnotation.desc, false));
}
}
if (field.attrs != null)
{
i = 0;
for (n = field.attrs.size(); i < n; ++i)
{
fv.visitAttribute((Attribute) field.attrs.get(i));
}
}
fv.visitEnd();
}
}
cw.visitEnd();
targetBytecode = cw.toByteArray();
}
else
{
ClassReader cr = new ClassReader(targetBytecode);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ClassVisitor(ASM6)
{
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
{
super.visit(version, access, name, signature, superName, interfaces);
if (staticMethods.get(className) != null)
{
for (MethodNode method : staticMethods.get(className))
{
MethodVisitor mv = visitMethod(method.access, method.name, method.desc,
method.signature, (String[]) method.exceptions.toArray(new String[0]));
MethodReflector reflector = new MethodReflector(mv);
method.accept(reflector);
}
}
if (staticFields.get(className) != null)
{
for (FieldNode field : staticFields.get(className))
{
FieldVisitor fv = visitField(field.access, field.name, field.desc, field.signature,
field.value);
int i;
int n;
AnnotationNode annotation;
if (field.visibleAnnotations != null)
{
i = 0;
for (n = field.visibleAnnotations.size(); i < n; ++i)
{
annotation = (AnnotationNode) field.visibleAnnotations.get(i);
annotation.accept(fv.visitAnnotation(annotation.desc, true));
}
}
if (field.invisibleAnnotations != null)
{
i = 0;
for (n = field.invisibleAnnotations.size(); i < n; ++i)
{
annotation = (AnnotationNode) field.invisibleAnnotations.get(i);
annotation.accept(fv.visitAnnotation(annotation.desc, false));
}
}
TypeAnnotationNode typeAnnotation;
if (field.visibleTypeAnnotations != null)
{
i = 0;
for (n = field.visibleTypeAnnotations.size(); i < n; ++i)
{
typeAnnotation = (TypeAnnotationNode) field.visibleTypeAnnotations.get(i);
typeAnnotation.accept(fv
.visitTypeAnnotation(typeAnnotation.typeRef, typeAnnotation.typePath,
typeAnnotation.desc, true));
}
}
if (field.invisibleTypeAnnotations != null)
{
i = 0;
for (n = field.invisibleTypeAnnotations.size(); i < n; ++i)
{
typeAnnotation = (TypeAnnotationNode) field.invisibleTypeAnnotations.get(i);
typeAnnotation.accept(fv
.visitTypeAnnotation(typeAnnotation.typeRef, typeAnnotation.typePath,
typeAnnotation.desc, false));
}
}
if (field.attrs != null)
{
i = 0;
for (n = field.attrs.size(); i < n; ++i)
{
fv.visitAttribute((Attribute) field.attrs.get(i));
}
}
fv.visitEnd();
}
}
}
};
cr.accept(cv, 0);
targetBytecode = cw.toByteArray();
}
classes.put(className, targetBytecode);
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.parsers;
import javassist.CtClass;
import javassist.CtField;
import us.runelitepl.mixinprocessor.annotations.Append;
import us.runelitepl.mixinprocessor.annotations.Inject;
import us.runelitepl.mixinprocessor.annotations.Overwrite;
import us.runelitepl.mixinprocessor.annotations.Prepend;
import us.runelitepl.mixinprocessor.annotations.Provided;
import us.runelitepl.mixinprocessor.annotations.Reobfuscate;
import us.runelitepl.mixinprocessor.enums.InjectionType;
import us.runelitepl.mixinprocessor.util.RefUtils;
import static us.runelitepl.mixinprocessor.MixinProcessorMojo.isFieldTagged;
public class FieldAnnotationParser
{
private CtClass clazz;
public FieldAnnotationParser(CtClass clazz)
{
this.clazz = clazz;
}
public void run() throws ClassNotFoundException
{
for (CtField field : clazz.getDeclaredFields())
{
Object[] annotations = field.getAnnotations();
InjectionType type = null;
boolean reobfuscate = false;
for (Object obj : annotations)
{
reobfuscate = obj instanceof Reobfuscate || reobfuscate;
if (obj instanceof Inject)
{
type = InjectionType.INJECT;
}
else if (obj instanceof Append)
{
type = InjectionType.APPEND;
}
else if (obj instanceof Overwrite)
{
type = InjectionType.OVERWRITE;
}
else if (obj instanceof Prepend)
{
type = InjectionType.PREPEND;
}
else if (obj instanceof Provided)
{
type = InjectionType.PROVIDED;
}
}
String fieldOwner = field.getDeclaringClass().getSimpleName();
String fieldName = field.getName();
String fieldDescriptor = RefUtils.reobDescriptor(field.getSignature());
if (type == null)
{
throw new RuntimeException(
field.getDeclaringClass().getSimpleName() + "." + field.getName() + " is unannotated" +
"!");
}
if (type != InjectionType.PROVIDED && type != InjectionType.INJECT)
{
throw new RuntimeException(
field.getDeclaringClass().getSimpleName() + "." + field.getName() + " has an invalid " +
"annotation! @" + type);
}
if (reobfuscate)
{
isFieldTagged.put(fieldOwner + " " + fieldName + " " + fieldDescriptor, true);
}
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.parsers;
import us.runelitepl.mixinprocessor.util.WebUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class GamepackDownloader
{
private static final String CONFIG_URL = "http://oldschool.runescape.com/jav_config.ws";
private static String codebase;
private static String initial_jar;
public static void downloadGamepack(HashMap<String, byte[]> output) throws IOException
{
parseConfig();
byte[] gamepackJarAry = WebUtils.downloadFile(getGamepackUrl());
ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(gamepackJarAry));
byte[] buffer = new byte[2048];
ZipEntry entry;
ByteArrayOutputStream fileContent = new ByteArrayOutputStream(1024*1024*4);
while ((entry = zipInputStream.getNextEntry()) != null)
{
if (entry.getName().startsWith("META-INF"))
{
continue;
}
String key = entry.getName().replace(".class", "");
int len = 0;
while((len = zipInputStream.read(buffer)) > 0)
{
fileContent.write(buffer, 0, len);
}
output.put(key, fileContent.toByteArray());
fileContent.reset();
}
zipInputStream.close();
}
private static void parseConfig() throws IOException
{
String pageText = WebUtils.getUrlContent(CONFIG_URL);
for (String line : pageText.split("\n"))
{
if (line.startsWith("codebase="))
{
codebase = line.replace("codebase=", "");
}
else if (line.startsWith("initial_jar="))
{
initial_jar = line.replace("initial_jar=", "");
}
}
}
public static String getGamepackUrl()
{
return codebase + initial_jar;
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.parsers;
import us.runelitepl.mixinprocessor.MethodGarbageValue;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Map;
public class HooksParser
{
public static void run(File hooksFile, File opsFile) throws IOException, ParseException
{
JSONParser parser = new JSONParser();
//region hooksFile
String jsonContent = String.join("\n", Files.readAllLines(hooksFile.toPath()));
JSONArray array = (JSONArray) parser.parse(jsonContent);
for (Object object : array)
{
JSONObject rootObject = (JSONObject) object;
String c_obbedName = (String) rootObject.get("name");
String c_deobbedName = (String) rootObject.get("class");
MixinProcessorMojo.classNames.put(c_deobbedName, c_obbedName);
}
int failedFields = 0;
int failedMethods = 0;
for (Object object : array)
{
JSONObject rootObject = (JSONObject) object;
JSONArray fieldArray = (JSONArray) rootObject.get("fields");
for (Object fieldObj : fieldArray)
{
JSONObject field = (JSONObject) fieldObj;
String f_deobbedName = (String) field.get("field");
String f_obbedName = (String) field.get("name");
String f_descriptor = (String) field.get("descriptor");
String f_owner = (String) field.get("owner");
long f_decoder = (long) field.getOrDefault("decoder", (long) 1);
String f_deobbedOwner = null;
if(f_deobbedName.startsWith("__"))
{
continue;
}
for (Map.Entry<String, String> entry : MixinProcessorMojo.classNames.entrySet())
{
if (entry.getValue().equals(f_owner))
{
f_deobbedOwner = entry.getKey();
break;
}
}
if (f_deobbedOwner == null)
{
failedFields++;
//stderr("Failed to find deobbed owner for field %s.%s %s", f_owner, f_obbedName, f_descriptor);
continue;
}
MixinProcessorMojo.fieldNames.put(String.format("%s %s %s", f_deobbedOwner, f_deobbedName, f_descriptor),
String.format("%s %s", f_owner, f_obbedName));
MixinProcessorMojo.fieldDecoders.put(String.format("%s %s", f_deobbedOwner, f_deobbedName),
f_decoder);
}
JSONArray methodArray = (JSONArray) rootObject.get("methods");
for (Object methodObj : methodArray)
{
JSONObject method = (JSONObject) methodObj;
String m_deobbedName = (String) method.get("method");
String m_owner = (String) method.get("owner");
String m_deobbedOwner = null;
String m_obbedName = (String) method.get("name");
String m_descriptor = (String) method.get("descriptor");
if(m_deobbedName.startsWith("__"))
{
continue;
}
for (Map.Entry<String, String> entry : MixinProcessorMojo.classNames.entrySet())
{
if (entry.getValue().equals(m_owner))
{
m_deobbedOwner = entry.getKey();
break;
}
}
if (m_deobbedOwner == null)
{
failedMethods++;
//stderr("Failed to find deobbed owner for method %s.%s %s", m_owner, m_obbedName, m_descriptor);
continue;
}
MixinProcessorMojo.methodNames.put(String.format("%s %s %s", m_deobbedOwner, m_deobbedName, m_descriptor),
String.format("%s %s", m_owner, m_obbedName));
}
}
MixinProcessorMojo.log("%d unidentified fields", failedFields);
MixinProcessorMojo.log("%d unidentified methods", failedMethods);
//endregion
//region opsFile
String opsContent = String.join("\n", Files.readAllLines(opsFile.toPath()));
JSONObject opsRoot = (JSONObject) parser.parse(opsContent);
opsRoot.forEach((key, value) ->
{
String k = (String) key;
MixinProcessorMojo.methodGarbageValues.put(k, new MethodGarbageValue(Math.toIntExact((Long) value)));
});
//endregion
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.parsers;
import javassist.CtClass;
import javassist.CtMethod;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.annotations.Append;
import us.runelitepl.mixinprocessor.annotations.Inject;
import us.runelitepl.mixinprocessor.annotations.Overwrite;
import us.runelitepl.mixinprocessor.annotations.Prepend;
import us.runelitepl.mixinprocessor.annotations.Provided;
import us.runelitepl.mixinprocessor.annotations.Reobfuscate;
import us.runelitepl.mixinprocessor.enums.InjectionType;
import us.runelitepl.mixinprocessor.util.RefUtils;
import static us.runelitepl.mixinprocessor.MixinProcessorMojo.isMethodTagged;
public class MethodAnnotationParser
{
private final CtClass patch;
public MethodAnnotationParser(CtClass patch)
{
this.patch = patch;
}
public void run() throws ClassNotFoundException
{
for(CtMethod method : patch.getDeclaredMethods())
{
Object[] annotations = method.getAnnotations();
boolean reobfuscate = false;
InjectionType type = null;
for (Object obj : annotations)
{
reobfuscate = obj instanceof Reobfuscate || reobfuscate;
if (obj instanceof Inject)
{
type = InjectionType.INJECT;
}
else if (obj instanceof Append)
{
type = InjectionType.APPEND;
}
else if (obj instanceof Overwrite)
{
type = InjectionType.OVERWRITE;
}
else if (obj instanceof Prepend)
{
type = InjectionType.PREPEND;
}
else if (obj instanceof Provided)
{
type = InjectionType.PROVIDED;
}
}
if (type == null)
{
throw new RuntimeException(
method.getDeclaringClass().getSimpleName() + "." + method.getName() + " is unannotated" +
"!");
}
String methodName = method.getName();
if (type == InjectionType.PREPEND)
{
if (!methodName.startsWith("prepend$"))
{
throw new RuntimeException(
method.getDeclaringClass().getSimpleName() + "." + method.getName() + " has a @Prepend " +
"annotation without beginning with \"prepend$\"!");
}
}
else if (type == InjectionType.APPEND)
{
if (!methodName.startsWith("append$"))
{
throw new RuntimeException(
method.getDeclaringClass().getSimpleName() + "." + method.getName() + " has a @Append " +
"annotation without beginning with \"append$\"!");
}
}
if(reobfuscate)
{
MixinProcessorMojo.log("Marking: %s %s %s", method.getDeclaringClass().getSimpleName(), methodName,
RefUtils.reobMethodDescriptor(method.getSignature()));
String r = String.format("%s %s %s", method.getDeclaringClass().getSimpleName(), methodName,
RefUtils.reobMethodDescriptor(method.getSignature()));
isMethodTagged.put(r, true);
}
}
}
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.parsers;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.TypePath;
public class MethodReflector extends MethodVisitor
{
private MethodVisitor target;
public MethodReflector(MethodVisitor target)
{
super(Opcodes.ASM6);
this.target = target;
}
public void visitCode()
{
if (target != null)
{
target.visitCode();
}
super.visitCode();
}
public void visitEnd()
{
if (target != null)
{
target.visitEnd();
}
super.visitEnd();
}
public void visitParameter(String var1, int var2)
{
if (target != null)
{
target.visitParameter(var1, var2);
}
super.visitParameter(var1, var2);
}
public AnnotationVisitor visitAnnotationDefault()
{
if (target != null)
{
target.visitAnnotationDefault();
}
return super.visitAnnotationDefault();
}
public AnnotationVisitor visitAnnotation(String var1, boolean var2)
{
if (target != null)
{
target.visitAnnotation(var1, var2);
}
return super.visitAnnotation(var1, var2);
}
public AnnotationVisitor visitTypeAnnotation(int var1, TypePath var2, String var3, boolean var4)
{
if (target != null)
{
target.visitTypeAnnotation(var1, var2, var3, var4);
}
return super.visitTypeAnnotation(var1, var2, var3, var4);
}
public AnnotationVisitor visitParameterAnnotation(int var1, String var2, boolean var3)
{
if (target != null)
{
target.visitParameterAnnotation(var1, var2, var3);
}
return super.visitParameterAnnotation(var1, var2, var3);
}
public void visitAttribute(Attribute var1)
{
if (target != null)
{
target.visitAttribute(var1);
}
super.visitAttribute(var1);
}
public void visitFrame(int var1, int var2, Object[] var3, int var4, Object[] var5)
{
if (target != null)
{
target.visitFrame(var1, var2, var3, var4, var5);
}
super.visitFrame(var1, var2, var3, var4, var5);
}
public void visitInsn(int var1)
{
if (target != null)
{
target.visitInsn(var1);
}
super.visitInsn(var1);
}
public void visitIntInsn(int var1, int var2)
{
if (target != null)
{
target.visitIntInsn(var1, var2);
}
super.visitIntInsn(var1, var2);
}
public void visitVarInsn(int var1, int var2)
{
if (target != null)
{
target.visitVarInsn(var1, var2);
}
super.visitVarInsn(var1, var2);
}
public void visitTypeInsn(int var1, String var2)
{
if (target != null)
{
target.visitTypeInsn(var1, var2);
}
super.visitTypeInsn(var1, var2);
}
public void visitFieldInsn(int var1, String var2, String var3, String var4)
{
if (target != null)
{
target.visitFieldInsn(var1, var2, var3, var4);
}
super.visitFieldInsn(var1, var2, var3, var4);
}
/**
* @deprecated
*/
public void visitMethodInsn(int var1, String var2, String var3, String var4)
{
if (target != null)
{
target.visitMethodInsn(var1, var2, var3, var4);
}
super.visitMethodInsn(var1, var2, var3, var4);
}
public void visitMethodInsn(int var1, String var2, String var3, String var4, boolean var5)
{
if (target != null)
{
target.visitMethodInsn(var1, var2, var3, var4, var5);
}
super.visitMethodInsn(var1, var2, var3, var4, var5);
}
public void visitInvokeDynamicInsn(String var1, String var2, Handle var3, Object... var4)
{
if (target != null)
{
target.visitInvokeDynamicInsn(var1, var2, var3, var4);
}
super.visitInvokeDynamicInsn(var1, var2, var3, var4);
}
public void visitJumpInsn(int var1, Label var2)
{
if (target != null)
{
target.visitJumpInsn(var1, var2);
}
super.visitJumpInsn(var1, var2);
}
public void visitLabel(Label var1)
{
if (target != null)
{
target.visitLabel(var1);
}
super.visitLabel(var1);
}
public void visitLdcInsn(Object var1)
{
if (target != null)
{
target.visitLdcInsn(var1);
}
super.visitLdcInsn(var1);
}
public void visitIincInsn(int var1, int var2)
{
if (target != null)
{
target.visitIincInsn(var1, var2);
}
super.visitIincInsn(var1, var2);
}
public void visitTableSwitchInsn(int var1, int var2, Label var3, Label... var4)
{
if (target != null)
{
target.visitTableSwitchInsn(var1, var2, var3, var4);
}
super.visitTableSwitchInsn(var1, var2, var3, var4);
}
public void visitLookupSwitchInsn(Label var1, int[] var2, Label[] var3)
{
if (target != null)
{
target.visitLookupSwitchInsn(var1, var2, var3);
}
super.visitLookupSwitchInsn(var1, var2, var3);
}
public void visitMultiANewArrayInsn(String var1, int var2)
{
if (target != null)
{
target.visitMultiANewArrayInsn(var1, var2);
}
super.visitMultiANewArrayInsn(var1, var2);
}
public AnnotationVisitor visitInsnAnnotation(int var1, TypePath var2, String var3, boolean var4)
{
if (target != null)
{
target.visitInsnAnnotation(var1, var2, var3, var4);
}
return super.visitInsnAnnotation(var1, var2, var3, var4);
}
public void visitTryCatchBlock(Label var1, Label var2, Label var3, String var4)
{
if (target != null)
{
target.visitTryCatchBlock(var1, var2, var3, var4);
}
super.visitTryCatchBlock(var1, var2, var3, var4);
}
public AnnotationVisitor visitTryCatchAnnotation(int var1, TypePath var2, String var3, boolean var4)
{
if (target != null)
{
target.visitTryCatchAnnotation(var1, var2, var3, var4);
}
return super.visitTryCatchAnnotation(var1, var2, var3, var4);
}
public void visitLocalVariable(String var1, String var2, String var3, Label var4, Label var5, int var6)
{
if (target != null)
{
target.visitLocalVariable(var1, var2, var3, var4, var5, var6);
}
super.visitLocalVariable(var1, var2, var3, var4, var5, var6);
}
public AnnotationVisitor visitLocalVariableAnnotation(int var1, TypePath var2, Label[] var3, Label[] var4, int[] var5, String var6, boolean var7)
{
if (target != null)
{
target.visitLocalVariableAnnotation(var1, var2, var3, var4, var5, var6, var7);
}
return super.visitLocalVariableAnnotation(var1, var2, var3, var4, var5, var6, var7);
}
public void visitLineNumber(int var1, Label var2)
{
if (target != null)
{
target.visitLineNumber(var1, var2);
}
super.visitLineNumber(var1, var2);
}
public void visitMaxs(int var1, int var2)
{
if (target != null)
{
target.visitMaxs(var1, var2);
}
super.visitMaxs(var1, var2);
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class AnnotationRemoverTransformer extends AsmBaseTransformer
{
private final String className;
private final byte[] bytecode;
public AnnotationRemoverTransformer(String className, byte[] bytecode)
{
this.className = className;
this.bytecode = bytecode;
}
@Override
public byte[] transform()
{
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
MethodVisitor mv = new MethodVisitor(Opcodes.ASM6, visitor)
{
@Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean hidden)
{
if (descriptor.equals(makeAnnotationDescriptor("Reobfuscate")))
{
return null;
}
return super.visitAnnotation(descriptor, hidden);
}
};
return mv;
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value)
{
FieldVisitor visitor = super.visitField(access, name, descriptor, signature, value);
return new FieldVisitor(Opcodes.ASM6, visitor)
{
@Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean hidden)
{
if (descriptor.equals(makeAnnotationDescriptor("Reobfuscate")))
{
return null;
}
if (descriptor.equals(makeAnnotationDescriptor("Provided")))
{
return null;
}
return super.visitAnnotation(descriptor, hidden);
}
};
}
}, 0);
return cw.toByteArray();
}
public static String makeAnnotationDescriptor(String s)
{
return "Lus/runelitepl/mixinprocessor/annotations/" + s + ";";
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
public abstract class AsmBaseTransformer implements Opcodes
{
protected final ArrayList<String> validMethods = new ArrayList<>();
protected final ArrayList<String> validFields = new ArrayList<>();
protected void buildMethodList(){}
protected void buildFieldList(){}
public abstract byte[] transform();
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import us.runelitepl.mixinprocessor.MethodGarbageValue;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.util.RefUtils;
import java.sql.Ref;
import java.util.HashMap;
public class AsmMethodGarbageTransformer extends AsmBaseTransformer
{
private final String className;
private final byte[] bytecode;
private HashMap<String, byte[]> classSet;
public AsmMethodGarbageTransformer(String className, byte[] bytecode, HashMap<String, byte[]> classSet)
{
this.className = className;
this.bytecode = bytecode;
this.classSet = classSet;
}
@Override
public byte[] transform()
{
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
cr.accept(new ClassVisitor(ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodVisitor(ASM6, mv)
{
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf)
{
// get method owner.string(desc)
// check if method is annotated with @Reobfuscate
// brute force actual descriptor (check with shouldReobMethod(owner, name desc) )
// mv.visitLdcInsn(BIPUSH, constant);
// call super method with new descriptor
if(RefUtils.shouldReobMethod(owner, name, desc))
{
String nc = RefUtils.reobMethodName(owner, name, desc).split(" ")[0];
String nn = RefUtils.reobMethodName(owner, name, desc).split(" ")[1];
String nd = RefUtils.reobMethodDescriptor(desc);
MethodGarbageValue value;
if((value = MixinProcessorMojo.methodGarbageValues.getOrDefault(String.format("%s.%s%s",
nc, nn, nd), null)) != null)
{
switch (value.getType())
{
case "I":
super.visitLdcInsn(new Integer(value.getValue()));
break;
case "S":
super.visitIntInsn(SIPUSH, (short) value.getValue());
break;
case "B":
super.visitIntInsn(BIPUSH, (byte) value.getValue());
break;
}
}
}
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
};
}
}, 0);
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.util.RefUtils;
public class AsmMethodSignatureTransformer extends AsmBaseTransformer
{
private final String className;
private final byte[] bytecode;
public AsmMethodSignatureTransformer(String className, byte[] bytecode)
{
this.className = RefUtils.deobClassName(className);
this.bytecode = bytecode;
}
@Override
public byte[] transform()
{
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
cr.accept(new ClassVisitor(ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String sig, String[] exceptions)
{
MethodVisitor mv = super.visitMethod(access, name, fixMethodDesc(className, name, desc), sig, exceptions);
return new MethodVisitor(ASM6, mv)
{
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf)
{
super.visitMethodInsn(opcode, owner, name, fixMethodDesc(owner, name, desc), itf);
}
};
}
}, 0);
return cw.toByteArray();
}
private String fixMethodDesc(String className, String name, String desc)
{
if(className.startsWith(RefUtils.TYPE_PREFIX))
{
className = className.substring(RefUtils.TYPE_PREFIX.length());
}
if (RefUtils.shouldReobMethod(className, name, desc))
{
if (RefUtils.reobMethodName(className, name, desc) == null)
{
// get correct descriptor
String realDesc = null;
for (String s : RefUtils.POSSIBLE_GARBAGE_TYPES)
{
String check = RefUtils.reobMethodName(className, name, RefUtils.appendArgument(desc, s));
if (check != null)
{
realDesc = RefUtils.appendArgument(desc, s);
break;
}
}
if (realDesc == null)
{
MixinProcessorMojo.log("Failed to find actual method descriptor for %s.%s%s", className,
name, desc);
throw new RuntimeException();
}
// fixed = realDesc
MixinProcessorMojo.isMethodTagged.put(String.format("%s %s %s", className, name, realDesc), true);
return realDesc;
}
}
return desc;
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.Remapper;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.util.RefUtils;
public class AsmNameTransformer extends AsmBaseTransformer
{
private String className;
private byte[] bytecode;
public AsmNameTransformer(String className, byte[] bytecode)
{
this.className = className;
this.bytecode = bytecode;
}
@Override
public byte[] transform()
{
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, 0);
ClassRemapper remapper = new ClassRemapper(cw, new Remapper()
{
final String TYPE_PREFIX = "us/runelitepl/mixins/";
@Override
public String map(String internalName)
{
return super.map(internalName);
}
@Override
public String mapDesc(String descriptor)
{
return RefUtils.reobDescriptor(descriptor);
}
@Override
public String mapFieldName(String owner, String name, String descriptor)
{
String oldName = name;
String noPackage = owner.replace(TYPE_PREFIX, "");
descriptor = mapDesc(descriptor);
owner = RefUtils.reobClassName(owner);
if (RefUtils.shouldReobField(noPackage, name, descriptor))
{
name = RefUtils.reobFieldName(noPackage, name, descriptor);
if (name == null)
{
MixinProcessorMojo.log("Failed to reobfuscate field name %s.%s", noPackage, oldName);
throw new RuntimeException();
}
}
return super.mapFieldName(owner, name, descriptor);
}
@Override
public String mapInvokeDynamicMethodName(String name, String descriptor)
{
throw new UnsupportedOperationException("mapInvokeDynamicMethodName: Not implemented yet," +
"\nAsmNameTransformer#mapInvokeDynamicMethodName(" + name + ", " + descriptor + ")");
}
@Override
public String mapMethodDesc(String descriptor)
{
return RefUtils.reobMethodDescriptor(descriptor);
}
@Override
public String mapMethodName(String owner, String name, String descriptor)
{
String originalClass = owner;
if (originalClass.startsWith(TYPE_PREFIX))
{
originalClass = originalClass.substring(TYPE_PREFIX.length());
}
owner = RefUtils.reobClassName(owner);
if (name.startsWith("protect$"))
{
name = "1" + name;
}
// descriptor for reob checking is obfuscated
descriptor = mapMethodDesc(descriptor);
boolean reob = RefUtils.shouldReobMethod(originalClass, name, descriptor);
if (reob)
{
String originalName = name;
name = RefUtils.reobMethodName(originalClass, name, descriptor);
if (name == null)
{
MixinProcessorMojo.log("Failed to reobfuscate method: %s.%s%s", originalClass, originalName,
descriptor);
throw new RuntimeException();
}
}
//stderr("mapMethodName %s %s %s", owner, name, descriptor);
return super.mapMethodName(owner, name, descriptor);
}
@Override
public String mapPackageName(String name)
{
throw new UnsupportedOperationException("mapPackageName: Not implemented yet," +
"\nAsmNameTransformer#mapPackageName(" + name + ")");
}
@Override
public String mapSignature(String signature, boolean isTypeSig)
{
return super.mapSignature(signature, isTypeSig);
}
@Override
public String mapType(String internalName)
{
internalName = RefUtils.reobClassName(internalName);
return super.mapType(internalName);
}
@Override
public String[] mapTypes(String[] internalNames)
{
return super.mapTypes(internalNames);
}
@Override
public Object mapValue(Object value)
{
return super.mapValue(value);
}
});
cr.accept(remapper, 0);
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.util.RefUtils;
import static org.objectweb.asm.Opcodes.ASM6;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.PUTSTATIC;
public class AsmStaticUsageTransformer extends AsmBaseTransformer
{
private String className;
private byte[] bytecode;
private final String TYPE_PREFIX = "us/runelitepl/mixins/";
public AsmStaticUsageTransformer(String className, byte[] bytecode)
{
this.className = className;
this.bytecode = bytecode;
}
@Override
public byte[] transform()
{
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ClassVisitor(ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions)
{
MethodVisitor visitor = super.visitMethod(access, name, descriptor, signature, exceptions);
return new MethodVisitor(ASM6, visitor)
{
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor)
{
if ((opcode == GETSTATIC || opcode == PUTSTATIC) && owner.endsWith(RefUtils.STATICS_STRING))
{
String oldName = name;
String originalOwner = owner.replace(TYPE_PREFIX, "");
String temp = RefUtils.reobFieldNameDangerous(name, RefUtils.reobDescriptor(descriptor));
if (temp == null)
{
MixinProcessorMojo.log("Failed to reobfuscate class name for field %s %s %s", owner,
name, descriptor);
throw new RuntimeException();
}
owner = temp.split(" ")[0];
if (RefUtils.shouldReobField(originalOwner, name, RefUtils.reobDescriptor(descriptor)))
{
name = temp.split(" ")[1];
}
}
super.visitFieldInsn(opcode, owner, name, descriptor);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface)
{
if(opcode == INVOKESTATIC && owner.endsWith(RefUtils.STATICS_STRING))
{
String originalOwner = owner.replace(TYPE_PREFIX, "");
String temp = RefUtils.reobMethodName(RefUtils.STATICS_STRING, name, descriptor);
if (temp == null)
{
MixinProcessorMojo.log("Failed to reobfuscate class name for method %s %s %s", owner,
name, descriptor);
throw new RuntimeException();
}
owner = temp.split(" ")[0];
if (RefUtils.shouldReobMethod(originalOwner, name, descriptor))
{
name = temp.split(" ")[1];
}
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
};
}
};
cr.accept(cv, 0);
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
public class DoNothingTransformer extends AsmBaseTransformer
{
private final String className;
private final byte[] bytecode;
public DoNothingTransformer(String className, byte[] bytecode)
{
this.className = className;
this.bytecode = bytecode;
}
@Override
public byte[] transform()
{
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
cr.accept(new ClassVisitor(ASM6, cw)
{}, 0);
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import us.runelitepl.mixinprocessor.util.RefUtils;
public class GetFieldDecoderTransformer extends AsmBaseTransformer
{
private final String className;
private final byte[] classFileBytecode;
public GetFieldDecoderTransformer(String className, byte[] bytes)
{
this.className = className;
this.classFileBytecode = bytes;
}
@Override
public void buildMethodList()
{
ClassReader cr = new ClassReader(classFileBytecode);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions)
{
final boolean[] valid = {true};
MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodVisitor(Opcodes.ASM6, visitor)
{
int opcodeCount = 0;
@Override
public void visitEnd()
{
if (valid[0])
{
MixinProcessorMojo.log("Valid method: %s %s %s %s", access, name, desc, signature);
validMethods.add(access + " " + name + " " + desc + " " + signature);
}
}
@Override
public void visitVarInsn(int opcode, int var)
{
if (opcode != Opcodes.ALOAD || var != 0 || opcodeCount != 0)
{
valid[0] = false;
}
opcodeCount++;
super.visitVarInsn(opcode, var);
}
@Override
public void visitFieldInsn(int opcode, String owner, String fieldName, String signature)
{
if (opcode != Opcodes.GETFIELD || opcodeCount != 1)
{
valid[0] = false;
}
opcodeCount++;
super.visitFieldInsn(opcode, owner, fieldName, signature);
}
@Override
public void visitLdcInsn(Object o)
{
if (!(o instanceof Integer) && !(o instanceof Long))
{
valid[0] = false;
}
if (opcodeCount != 2)
{
valid[0] = false;
}
opcodeCount++;
super.visitLdcInsn(o);
}
@Override
public void visitInsn(int opcode)
{
switch (opcode)
{
case Opcodes.IMUL:
if (opcodeCount != 3)
{
valid[0] = false;
}
break;
case Opcodes.IRETURN:
if (opcodeCount != 4)
{
valid[0] = false;
}
break;
default:
valid[0] = false;
break;
}
opcodeCount++;
super.visitInsn(opcode);
}
};
}
}, 0);
}
public byte[] transform()
{
buildMethodList();
ClassReader cr = new ClassReader(classFileBytecode);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
if (!validMethods.contains(access + " " + name + " " + desc + " " + signature))
{
return visitor;
}
return new MethodVisitor(Opcodes.ASM6, visitor)
{
String target = null;
@Override
public void visitFieldInsn(int opcode, String owner, String fieldName, String signature)
{
target = fieldName;
super.visitFieldInsn(opcode, owner, fieldName, signature);
}
@Override
public void visitLdcInsn(Object o)
{
if (target != null)
{
if (o instanceof Long)
{
o = MixinProcessorMojo.fieldDecoders.getOrDefault(
RefUtils.deobClassName(className) + " " + target, 1L);
}
else
{
o = Math.toIntExact(MixinProcessorMojo.fieldDecoders.getOrDefault(RefUtils.deobClassName(className) +
" " + target,
1L));
}
}
MixinProcessorMojo.log("\tGetFieldDecoderTransformer: %s %s %s %s %s",
RefUtils.deobClassName(className), name, target, desc, o);
super.visitLdcInsn(o);
}
};
}
}, 0);
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.transformers;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
public class ProvidedRemoverTransformer extends AsmBaseTransformer
{
private final String className;
private final byte[] bytecode;
public ProvidedRemoverTransformer(String className, byte[] bytecode)
{
this.className = className;
this.bytecode = bytecode;
}
public void buildMethodList()
{
ClassReader cr = new ClassReader(bytecode);
ClassNode node = new ClassNode();
cr.accept(node, 0);
for(Object obj : node.methods)
{
MethodNode method = (MethodNode) obj;
if(method == null)
{
MixinProcessorMojo.log("ProvidedRemoverTransformer: Method null?");
continue;
}
if(method.visibleAnnotations == null)
{
continue;
}
for(Object obj2 : method.visibleAnnotations)
{
AnnotationNode annot = (AnnotationNode) obj2;
if(annot.desc.equals(AnnotationRemoverTransformer.makeAnnotationDescriptor("Provided")))
{
validMethods.add(method.access + " " + method.desc + " " + method.name);
}
}
}
}
@Override
public byte[] transform()
{
buildMethodList();
ClassReader cr = new ClassReader(bytecode);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM6, cw)
{
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions)
{
if(validMethods.contains(access + " " + desc + " " + name))
{
return null;
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}, 0);
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.util;
import javassist.CannotCompileException;
import javassist.CtClass;
import java.io.IOException;
public class JavassistUtils
{
public static byte[] getClassBytecode(CtClass clazz) throws IOException, CannotCompileException
{
clazz.stopPruning(true);
byte[] retVal = clazz.toBytecode();
clazz.defrost();
return retVal;
}
}

View File

@@ -0,0 +1,347 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.util;
import us.runelitepl.mixinprocessor.MixinProcessorMojo;
import java.util.Map;
public class RefUtils
{
public static final String TYPE_PREFIX = "us/runelitepl/mixins/";
public static final String STATICS_STRING = "_Statics_";
public static final String[] POSSIBLE_GARBAGE_TYPES = {"I", "B", "S"};
public static String deobClassName(String obbed)
{
for (Map.Entry<String, String> entry : MixinProcessorMojo.classNames.entrySet())
{
if (entry.getValue().equals(obbed))
{
return entry.getKey();
}
}
return obbed;
}
public static String getObbedClassName(String deob)
{
return MixinProcessorMojo.classNames.getOrDefault(deob, deob);
}
public static String reobClassName(String deobbed)
{
String old = deobbed;
if (deobbed.contains("/"))
{
deobbed = deobbed.replaceAll(TYPE_PREFIX, "");
deobbed = getObbedClassName(deobbed);
if (deobbed == null)
{
return old;
}
}
return deobbed;
}
@Deprecated
public static String reobFieldNameDangerous(String deob, String desc)
{
int i = 0;
Map.Entry<String, String> e1 = null;
for (Map.Entry<String, String> entry : MixinProcessorMojo.fieldNames.entrySet())
{
if (entry.getKey().endsWith(deob + " " + desc))
{
i++;
e1 = entry;
}
}
if (i == 1)
{
return e1.getValue();
}
return null;
}
@Deprecated
public static String reobMethodNameDangerous(String deob, String signature)
{
int i = 0;
Map.Entry<String, String> e1 = null;
for (Map.Entry<String, String> entry : MixinProcessorMojo.methodNames.entrySet())
{
if (entry.getKey().endsWith(" " + deob + " " + signature))
{
i++;
e1 = entry;
}
}
if (i == 1)
{
return e1.getValue();
}
return null;
}
public static String reobFieldName(String owner, String deob, String desc)
{
if (owner.equals(RefUtils.STATICS_STRING))
{
return reobFieldNameDangerous(deob, desc);
}
String asd = MixinProcessorMojo.fieldNames.getOrDefault(owner + " " + deob + " " + desc, null);
if (asd == null)
{
return null;
}
return asd.split(" ")[1];
}
public static String reobMethodName(String owner, String deob, String signature)
{
String prefix = "";
if(owner.startsWith(RefUtils.TYPE_PREFIX))
{
owner = owner.substring(RefUtils.TYPE_PREFIX.length());
}
if (deob.startsWith("prepend$"))
{
prefix = "prepend$";
deob = deob.substring("prepend$".length());
}
else if (deob.startsWith("append$"))
{
prefix = "append$";
deob = deob.substring("append$".length());
}
if (owner.equals(RefUtils.STATICS_STRING))
{
String retVal = reobMethodNameDangerous(deob, signature);
if (retVal == null)
{
return null;
}
String[] split = retVal.split(" ");
split[1] = prefix + split[1];
return String.join(" ", split);
}
String asd = MixinProcessorMojo.methodNames.getOrDefault(owner + " " + deob + " " + signature, null);
if (asd == null)
{
return null;
}
return prefix + asd.split(" ")[1];
}
@Deprecated
public static boolean shouldReobFieldDangerous(String deob, String desc)
{
int i = 0;
for (Map.Entry<String, Boolean> entry : MixinProcessorMojo.isFieldTagged.entrySet())
{
if (entry.getKey().endsWith(deob + " " + desc))
{
i++;
}
}
if (i == 1)
{
return true;
}
return false;
}
@Deprecated
public static boolean shouldReobMethodDangerous(String deob, String desc)
{
int i = 0;
for (Map.Entry<String, Boolean> entry : MixinProcessorMojo.isMethodTagged.entrySet())
{
if (entry.getKey().endsWith(" " + deob + " " + desc))
{
i++;
}
}
if (i == 1)
{
return true;
}
return false;
}
public static boolean shouldReobField(String owner, String deob, String desc)
{
if (owner.equals(RefUtils.STATICS_STRING))
{
return shouldReobFieldDangerous(deob, desc);
}
return MixinProcessorMojo.isFieldTagged.getOrDefault(owner + " " + deob + " " + desc, false);
}
public static boolean shouldReobMethod(String owner, String deob, String desc)
{
if(owner.startsWith(RefUtils.TYPE_PREFIX))
{
owner = owner.substring(RefUtils.TYPE_PREFIX.length());
}
if (owner.equals(RefUtils.STATICS_STRING))
{
return shouldReobMethodDangerous(deob, desc);
}
return MixinProcessorMojo.isMethodTagged.getOrDefault(owner + " " + deob + " " + desc, false);
}
public static String reobDescriptor(String descriptor)
{
if (!descriptor.startsWith("L"))
{
return descriptor;
}
if (!descriptor.contains("us/runelitepl/mixins/"))
{
return descriptor;
}
String orig = descriptor;
descriptor = descriptor.replace("us/runelitepl/mixins/", "");
descriptor = descriptor.substring(1, descriptor.length() - 1);
descriptor = getObbedClassName(descriptor);
if (descriptor == null)
{
return orig;
}
return "L" + descriptor + ";";
}
public static String reobMethodDescriptor(String descriptor)
{
int strIndex = 0;
if (descriptor.charAt(0) != '(')
{
throw new IllegalArgumentException("sig is not a method signature: " + descriptor);
}
StringBuilder deobbed = new StringBuilder(1024 * 1024);
while (strIndex < descriptor.length())
{
switch (descriptor.charAt(strIndex))
{
case '(':
case ')':
case 'I':
case 'B':
case 'J':
case 'S':
case 'D':
case 'F':
case 'C':
case 'Z':
case 'V':
case '[':
deobbed.append(descriptor.charAt(strIndex));
strIndex++;
break;
case 'L':
try
{
String sigPart = descriptor.substring(strIndex, descriptor.indexOf(";", strIndex) + 1);
String className = sigPart.substring(1, sigPart.length() - 1);
className = className.replace(TYPE_PREFIX, "");
String obbedName = MixinProcessorMojo.classNames.getOrDefault(className, null);
if (obbedName == null)
{
obbedName = className;
}
deobbed.append("L" + obbedName + ";");
strIndex += sigPart.length();
}
catch (StringIndexOutOfBoundsException ex)
{
System.err.println(
"Method signature %s is probably missing a semi-colon".replace("%s", descriptor));
throw ex;
}
break;
default:
throw new IllegalArgumentException("signature is invalid: " + descriptor);
}
}
return deobbed.toString();
}
public static String appendArgument(String desc, String append)
{
int strIndex = 0;
if (desc.charAt(0) != '(')
{
throw new IllegalArgumentException("sig is not a method signature: " + desc);
}
StringBuilder deobbed = new StringBuilder(1024 * 1024);
while (strIndex < desc.length())
{
switch (desc.charAt(strIndex))
{
case ')':
deobbed.append(append);
deobbed.append(")");
strIndex++;
break;
case '(':
case 'I':
case 'B':
case 'J':
case 'S':
case 'D':
case 'F':
case 'C':
case 'Z':
case 'V':
case '[':
deobbed.append(desc.charAt(strIndex));
strIndex++;
break;
case 'L':
try
{
String sigPart = desc.substring(strIndex, desc.indexOf(";", strIndex) + 1);
deobbed.append(sigPart);
strIndex += sigPart.length();
}
catch (StringIndexOutOfBoundsException ex)
{
System.err.println(
"Method signature %s is probably missing a semi-colon".replace("%s", desc));
throw ex;
}
break;
default:
throw new IllegalArgumentException("signature is invalid: " + desc);
}
}
return deobbed.toString();
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package us.runelitepl.mixinprocessor.util;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
public class WebUtils
{
public static String getUrlContent(String url) throws IOException
{
String pageText;
URLConnection conn = new URL(url).openConnection();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)))
{
pageText = reader.lines().collect(Collectors.joining("\n"));
}
return pageText;
}
public static byte[] downloadFile(String urlText) throws IOException {
URL url = new URL(urlText);
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (InputStream inputStream = url.openStream()) {
int n = 0;
byte [] buffer = new byte[ 1024 ];
while (-1 != (n = inputStream.read(buffer))) {
output.write(buffer, 0, n);
}
}
return output.toByteArray();
}
}

View File

@@ -0,0 +1,22 @@
Copyright (c) 2019, ThatGamerBlue <thatgamerblue@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.