Initial commit.
This commit is contained in:
commit
e5af484c54
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
# Eclipse stuff
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
|
||||
# netbeans
|
||||
/nbproject
|
||||
/nbactions.xml
|
||||
/nb-configuration.xml
|
||||
|
||||
# we use maven!
|
||||
/build.xml
|
||||
|
||||
# maven
|
||||
/target
|
||||
/dependency-reduced-pom.xml
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
# various other potential build files
|
||||
/build
|
||||
/bin
|
||||
/dist
|
||||
/manifest.mf
|
||||
|
||||
# Mac filesystem dust
|
||||
/.DS_Store
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# other files
|
||||
*.csv
|
||||
*.jar
|
||||
*.log
|
||||
*.rg
|
||||
*.srg
|
||||
*.txt
|
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright (c) 2012, md_5
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 <COPYRIGHT HOLDER> 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.
|
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
||||
Special Source
|
||||
==============
|
||||
|
||||
Automatic generator and renamer of jar obfuscation mappings.
|
126
pom.xml
Normal file
126
pom.xml
Normal file
@ -0,0 +1,126 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>7</version>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>SpecialSource</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>SpecialSource</name>
|
||||
<description>A jar compare and renaming engine designed for comparing and remapping 2 jars of differnent obfuscation mappings. Can also be useful for reobfuscation.</description>
|
||||
<url>https://github.com/md-5/SpecialSource</url>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The BSD 3-Clause License</name>
|
||||
<url>http://opensource.org/licenses/BSD-3-Clause</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>md_5</id>
|
||||
<name>Michael Dardis</name>
|
||||
<email>md_5@live.com.au</email>
|
||||
<timezone>+10</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:md-5/SpecialSource.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:md-5/SpecialSource.git</developerConnection>
|
||||
<url>git@github.com:md-5/SpecialSource.git</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
<system>GitHub</system>
|
||||
<url>https://github.com/md-5/SpecialSource/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-all</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>0.11.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila.maven-license-plugin</groupId>
|
||||
<artifactId>maven-license-plugin</artifactId>
|
||||
<version>1.10.b1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>clean</phase>
|
||||
<goals>
|
||||
<goal>format</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<strictCheck>true</strictCheck>
|
||||
<header>${basedir}/LICENSE</header>
|
||||
<includes>
|
||||
<include>src/**</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Main-Class>${main.class}</Main-Class>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
104
src/main/java/net/md_5/specialsource/Jar.java
Normal file
104
src/main/java/net/md_5/specialsource/Jar.java
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
/**
|
||||
* This class wraps a {@link JarFile} enabling quick access to the jar's main
|
||||
* class, as well as the ability to get the {@link InputStream} of a class file,
|
||||
* and speedy lookups to see if the jar contains the specified class.
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Jar {
|
||||
|
||||
public final JarFile file;
|
||||
public final String main;
|
||||
private final Set<String> contains = new HashSet<>();
|
||||
private final Map<String, ClassNode> classes = new HashMap<>();
|
||||
|
||||
public boolean containsClass(String clazz) {
|
||||
return contains.contains(clazz) ? true : getClass(clazz) != null;
|
||||
}
|
||||
|
||||
public InputStream getClass(String clazz) {
|
||||
try {
|
||||
ZipEntry e = file.getEntry(clazz + ".class");
|
||||
if (e != null) {
|
||||
contains.add(clazz);
|
||||
}
|
||||
return e == null ? null : file.getInputStream(e);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassNode getNode(String clazz) {
|
||||
try {
|
||||
ClassNode cache = classes.get(clazz);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
InputStream is = getClass(clazz);
|
||||
if (is != null) {
|
||||
ClassReader cr = new ClassReader(getClass(clazz));
|
||||
ClassNode node = new ClassNode();
|
||||
cr.accept(node, 0);
|
||||
classes.put(clazz, node);
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
System.out.println(clazz);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Jar init(String jar) throws IOException {
|
||||
File file = new File(jar);
|
||||
JarFile jarFile = new JarFile(file);
|
||||
String main = jarFile.getManifest().getMainAttributes().getValue("Main-Class").replace('.', '/');
|
||||
return new Jar(jarFile, main);
|
||||
}
|
||||
}
|
126
src/main/java/net/md_5/specialsource/JarComparer.java
Normal file
126
src/main/java/net/md_5/specialsource/JarComparer.java
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class JarComparer extends ClassVisitor {
|
||||
|
||||
private final MethodReferenceFinder methodVisitor = new MethodReferenceFinder();
|
||||
public final Jar jar;
|
||||
private String myName;
|
||||
public int iterDepth;
|
||||
public NoDupeList<String> classes = new NoDupeList<>();
|
||||
public NoDupeList<Ownable> fields = new NoDupeList<>();
|
||||
public NoDupeList<Ownable> methods = new NoDupeList<>();
|
||||
|
||||
private void visitType(Type type) {
|
||||
// FIXME: Scan arrays too!
|
||||
if (type.getSort() == Type.OBJECT) {
|
||||
String name = type.getInternalName();
|
||||
if (jar.containsClass(name)) {
|
||||
classes.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JarComparer(Jar jar) {
|
||||
super(Opcodes.ASM4);
|
||||
this.jar = jar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
myName = name;
|
||||
// FIXME: Scan the super class too!
|
||||
for (String implement : interfaces) {
|
||||
if (jar.containsClass(implement)) {
|
||||
classes.add(implement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||
Ownable field = new Ownable(NodeType.FIELD, myName, name, desc);
|
||||
fields.add(field);
|
||||
return null; // No need to get more info about a field!
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
// Check for initializers
|
||||
if (!name.equals("<init>") && !name.equals("<clinit>")) {
|
||||
Ownable method = new Ownable(NodeType.METHOD, myName, name, desc);
|
||||
methods.add(method);
|
||||
}
|
||||
// FIXME: Scan return types too!
|
||||
for (Type t : Type.getArgumentTypes(desc)) {
|
||||
visitType(t);
|
||||
}
|
||||
return methodVisitor;
|
||||
}
|
||||
|
||||
private class MethodReferenceFinder extends MethodVisitor {
|
||||
|
||||
public MethodReferenceFinder() {
|
||||
super(Opcodes.ASM4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
if (jar.containsClass(owner)) {
|
||||
classes.add(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst) {
|
||||
if (cst instanceof Type) {
|
||||
visitType((Type) cst);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||
if (jar.containsClass(owner)) {
|
||||
classes.add(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
if (jar.containsClass(type)) {
|
||||
classes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
188
src/main/java/net/md_5/specialsource/JarRemapper.java
Normal file
188
src/main/java/net/md_5/specialsource/JarRemapper.java
Normal file
@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.commons.RemappingClassAdapter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class JarRemapper extends Remapper {
|
||||
|
||||
private static final int CLASS_LEN = ".class".length();
|
||||
private static final String HEADER = ""
|
||||
+ "# THESE ARE AUTOMATICALLY GENERATED MAPPINGS BETWEEN {0} and {1}\n"
|
||||
+ "# THEY WERE GENERATED ON {2} USING Special Source (c) md_5 2012.\n"
|
||||
+ "# PLEASE DO NOT REMOVE THIS HEADER OR DISTRIBUTE THIS FILE WITHOUT PERMISSION!\n";
|
||||
private final JarComparer oldJar;
|
||||
private final JarComparer newJar;
|
||||
private final Jar self;
|
||||
private final Map<String, String> classes = new HashMap<>();
|
||||
private final Map<String, String> fields = new HashMap<>();
|
||||
private final Map<String, String> methods = new HashMap<>();
|
||||
|
||||
private JarRemapper(JarComparer oldJar, JarComparer newJar, Jar self, File logfile) throws IOException {
|
||||
SpecialSource.validate(oldJar, newJar);
|
||||
this.oldJar = oldJar;
|
||||
this.newJar = newJar;
|
||||
this.self = self;
|
||||
|
||||
List<String> searge = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < oldJar.classes.size(); i++) {
|
||||
String oldClass = oldJar.classes.get(i);
|
||||
String newClass = newJar.classes.get(i);
|
||||
classes.put(oldClass, newClass);
|
||||
if (!Objects.equals(oldClass, newClass)) {
|
||||
searge.add("CL: " + oldClass + " " + newClass);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < oldJar.fields.size(); i++) {
|
||||
Ownable oldField = oldJar.fields.get(i);
|
||||
Ownable newField = newJar.fields.get(i);
|
||||
fields.put(oldField.owner + "/" + oldField.name, newField.name);
|
||||
if (!Objects.equals(oldField, newField)) {
|
||||
searge.add("FD: " + oldField.owner + "/" + oldField.name + " " + newField.owner + "/" + newField.name);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < oldJar.methods.size(); i++) {
|
||||
Ownable oldMethod = oldJar.methods.get(i);
|
||||
Ownable newMethod = newJar.methods.get(i);
|
||||
methods.put(oldMethod.owner + "/" + oldMethod.name + " " + oldMethod.descriptor, newMethod.name);
|
||||
if (!Objects.equals(oldMethod, newMethod)) {
|
||||
searge.add("MD: " + oldMethod.owner + "/" + oldMethod.name + " " + oldMethod.descriptor + " " + newMethod.owner + "/" + newMethod.name + " " + newMethod.descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(searge);
|
||||
try (PrintWriter out = new PrintWriter(logfile)) {
|
||||
out.println(MessageFormat.format(HEADER, oldJar.jar.file.getName(), newJar.jar.file.getName(), new Date()));
|
||||
for (String s : searge) {
|
||||
out.println(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String typeName) {
|
||||
int index = typeName.indexOf('$');
|
||||
String key = (index == -1) ? typeName : typeName.substring(0, index);
|
||||
String mapped = classes.get(key);
|
||||
return mapped != null ? mapped + (index == -1 ? "" : typeName.substring(index, typeName.length())) : typeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
String mapped = tryClimb(fields, NodeType.FIELD, owner, name);
|
||||
return mapped == null ? name : mapped;
|
||||
}
|
||||
|
||||
private String tryClimb(Map<String, String> map, NodeType type, String owner, String name) {
|
||||
String key = owner + "/" + name;
|
||||
if (key.contains("findNearestMapFeature")) {
|
||||
System.out.println();
|
||||
}
|
||||
String mapped = map.get(key);
|
||||
if (mapped == null) {
|
||||
ClassNode node = self.getNode(owner);
|
||||
if (node != null) {
|
||||
for (String iface : (List<String>) node.interfaces) {
|
||||
mapped = tryClimb(map, type, iface, name);
|
||||
if (mapped != null) {
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
return tryClimb(map, type, node.superName, name);
|
||||
}
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
String mapped = tryClimb(methods, NodeType.METHOD, owner, name + " " + desc);
|
||||
return mapped == null ? name : mapped;
|
||||
}
|
||||
|
||||
public static void renameJar(Jar jar, File target, JarComparer oldNames, JarComparer newNames) throws IOException {
|
||||
try (JarOutputStream out = new JarOutputStream(new FileOutputStream(target))) {
|
||||
JarRemapper self = new JarRemapper(oldNames, newNames, jar, new File(target.getPath() + ".srg"));
|
||||
for (Enumeration<JarEntry> entr = jar.file.entries(); entr.hasMoreElements();) {
|
||||
JarEntry entry = entr.nextElement();
|
||||
try (InputStream is = jar.file.getInputStream(entry)) {
|
||||
String name = entry.getName();
|
||||
byte[] data;
|
||||
if (name.endsWith(".class")) {
|
||||
name = name.substring(0, name.length() - CLASS_LEN);
|
||||
|
||||
ClassReader reader = new ClassReader(is);
|
||||
ClassWriter wr = new ClassWriter(0);
|
||||
RemappingClassAdapter mapper = new RemappingClassAdapter(wr, self);
|
||||
reader.accept(mapper, ClassReader.EXPAND_FRAMES);
|
||||
data = wr.toByteArray();
|
||||
String newName = self.map(name);
|
||||
|
||||
entry = new JarEntry(newName == null ? name : newName + ".class");
|
||||
|
||||
} else {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int n;
|
||||
byte[] b = new byte[1 << 15]; // Max class file size, arbritrary number
|
||||
while ((n = is.read(b, 0, b.length)) != -1) {
|
||||
buffer.write(b, 0, n);
|
||||
}
|
||||
buffer.flush();
|
||||
data = buffer.toByteArray();
|
||||
}
|
||||
entry.setTime(0);
|
||||
out.putNextEntry(entry);
|
||||
out.write(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
src/main/java/net/md_5/specialsource/NoDupeList.java
Normal file
69
src/main/java/net/md_5/specialsource/NoDupeList.java
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A pseudo class implementing the {@link List} like, but does not allow
|
||||
* duplicates. Is backed by an {@link ArrayList} and {@link HashSet} for speedy
|
||||
* contains lookups.
|
||||
*
|
||||
* @param <E> the type of elements contained in this 'list'
|
||||
*/
|
||||
public class NoDupeList<E> implements Iterable<E> {
|
||||
|
||||
private final Set<E> set = new HashSet<>();
|
||||
private final List<E> backing = new ArrayList<>();
|
||||
|
||||
public boolean add(E e) {
|
||||
if (set.contains(e)) {
|
||||
return false;
|
||||
} else {
|
||||
set.add(e);
|
||||
backing.add(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public E get(int index) {
|
||||
return backing.get(index);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return backing.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return backing.iterator();
|
||||
}
|
||||
}
|
32
src/main/java/net/md_5/specialsource/NodeType.java
Normal file
32
src/main/java/net/md_5/specialsource/NodeType.java
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
public enum NodeType {
|
||||
|
||||
FIELD, METHOD;
|
||||
}
|
42
src/main/java/net/md_5/specialsource/Ownable.java
Normal file
42
src/main/java/net/md_5/specialsource/Ownable.java
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* A class which can be used to represent a field, method, or anything else
|
||||
* which has an owner, a name and a descriptor.
|
||||
*/
|
||||
@Data
|
||||
public class Ownable {
|
||||
|
||||
final NodeType type;
|
||||
final String owner;
|
||||
final String name;
|
||||
final String descriptor;
|
||||
}
|
46
src/main/java/net/md_5/specialsource/Pair.java
Normal file
46
src/main/java/net/md_5/specialsource/Pair.java
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* A class representing a set of 2 objects as defined by the type parameters.
|
||||
*
|
||||
* @param <T1> First type
|
||||
* @param <T2> Second type
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
public class Pair<T1, T2> {
|
||||
|
||||
public final T1 first;
|
||||
public final T2 second;
|
||||
}
|
100
src/main/java/net/md_5/specialsource/SpecialSource.java
Normal file
100
src/main/java/net/md_5/specialsource/SpecialSource.java
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2012, md_5
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the <organization> nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* 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 <COPYRIGHT HOLDER> 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 net.md_5.specialsource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarFile;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
public class SpecialSource {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
args = new String[]{"jars/1.4.5/bukkit.jar", "jars/1.4.5/vanilla.jar", "jars/1.4.5/craftbukkit-1.4.5-R0.3-SNAPSHOT.jar"};
|
||||
if (args.length != 3) {
|
||||
System.err.println("SpecialSource takes 3 arguments. It will take 2 jars to generate a difference between, and a 3rd jar based on the first jar to rename to the second jar.");
|
||||
System.err.println("Usage: java -jar SpecialSource.jar <first jar> <second jar> <jar of first names>");
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Reading jars");
|
||||
Jar jar1 = Jar.init(args[0]);
|
||||
Jar jar2 = Jar.init(args[1]);
|
||||
|
||||
System.out.println("Creating jar compare");
|
||||
JarComparer visitor1 = new JarComparer(jar1);
|
||||
JarComparer visitor2 = new JarComparer(jar2);
|
||||
visit(new Pair<>(jar1, jar2), new Pair<>(visitor1, visitor2), new Pair<>(jar1.main, jar2.main));
|
||||
|
||||
System.out.println("Checking vailidity");
|
||||
if (visitor1.classes.size() != 1004 || visitor2.classes.size() != 1004) {
|
||||
throw new IllegalStateException("classes");
|
||||
}
|
||||
if (visitor1.fields.size() != 3582 || visitor2.fields.size() != 3582) {
|
||||
throw new IllegalStateException("fields");
|
||||
}
|
||||
if (visitor1.methods.size() != 6531 + 4 || visitor2.methods.size() != 6531 + 4) { // 3 broken enums (EnumEntitySize, EnumFacing, EnumGameType), and 1 main method
|
||||
throw new IllegalStateException("methods");
|
||||
}
|
||||
|
||||
System.out.println("Renaming final jar");
|
||||
JarRemapper.renameJar(Jar.init(args[2]), new File("out.jar"), visitor1, visitor2);
|
||||
}
|
||||
|
||||
private static void visit(Pair<Jar, Jar> jars, Pair<JarComparer, JarComparer> visitors, Pair<String, String> classes) throws IOException {
|
||||
JarComparer visitor1 = visitors.first;
|
||||
JarComparer visitor2 = visitors.second;
|
||||
|
||||
ClassReader clazz1 = new ClassReader(jars.first.getClass(classes.first));
|
||||
ClassReader clazz2 = new ClassReader(jars.second.getClass(classes.second));
|
||||
clazz1.accept(visitor1, 0);
|
||||
clazz2.accept(visitor2, 0);
|
||||
|
||||
validate(visitor1, visitor2);
|
||||
|
||||
while (visitor1.iterDepth < visitor1.classes.size()) {
|
||||
String className1 = visitor1.classes.get(visitor1.iterDepth);
|
||||
String className2 = visitor2.classes.get(visitor1.iterDepth);
|
||||
Pair<String, String> pair = new Pair<>(className1, className2);
|
||||
visitor1.iterDepth++;
|
||||
visit(jars, visitors, pair);
|
||||
}
|
||||
}
|
||||
|
||||
public static void validate(JarComparer visitor1, JarComparer visitor2) {
|
||||
if (visitor1.classes.size() != visitor2.classes.size()) {
|
||||
throw new IllegalStateException("classes");
|
||||
}
|
||||
if (visitor1.fields.size() != visitor2.fields.size()) {
|
||||
throw new IllegalStateException("fields");
|
||||
}
|
||||
if (visitor1.methods.size() != visitor2.methods.size()) {
|
||||
throw new IllegalStateException("methods");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user