├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github └── workflows │ ├── test.yml │ └── publish.yml ├── com.pocolifo.jarremapper ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── pocolifo │ │ │ └── jarremapper │ │ │ ├── engine │ │ │ ├── standard │ │ │ │ ├── IRemappingPlugin.java │ │ │ │ ├── ParameterEnhancedRemapper.java │ │ │ │ ├── MappingProvider.java │ │ │ │ └── StandardRemappingEngine.java │ │ │ └── AbstractRemappingEngine.java │ │ │ ├── Utility.java │ │ │ ├── reader │ │ │ ├── MappingUtility.java │ │ │ ├── tiny │ │ │ │ ├── Tiny1MappingReader.java │ │ │ │ └── Tiny2MappingReader.java │ │ │ └── mcp │ │ │ │ └── McpMappingReader.java │ │ │ ├── mapping │ │ │ ├── FieldMapping.java │ │ │ ├── MethodMapping.java │ │ │ ├── JarMapping.java │ │ │ └── ClassMapping.java │ │ │ └── JarRemapper.java │ └── test │ │ └── java │ │ └── com │ │ └── pocolifo │ │ └── jarremapper │ │ ├── SimpleProgressListener.java │ │ └── Remappers.java └── build.gradle ├── com.pocolifo.jarremapper.extensions ├── src │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── pocolifo │ │ │ └── jarremapper │ │ │ └── extensions │ │ │ └── Remappers.java │ └── main │ │ └── java │ │ └── com │ │ └── pocolifo │ │ └── jarremapper │ │ └── extensions │ │ ├── SpecialSourceEngine.java │ │ ├── ExtensionUtility.java │ │ └── TinyRemapperEngine.java ├── build.gradle └── README.md ├── README.md ├── gradlew.bat ├── gradlew └── LICENSE /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'com.pocolifo.jarremapper' 2 | include 'com.pocolifo.jarremapper.extensions' 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | .idea/ 3 | build/ 4 | *.iml 5 | 6 | output.jar 7 | 8 | jars 9 | mappings 10 | autogen -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pocolifo/jar-remapper/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | container: 9 | image: gradle:jdk8 10 | steps: 11 | - uses: actions/checkout@v2 12 | name: Check out 13 | 14 | - run: gradle generateTests test 15 | name: Test -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/engine/standard/IRemappingPlugin.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.engine.standard; 2 | 3 | import com.pocolifo.jarremapper.mapping.ClassMapping; 4 | 5 | import java.util.zip.ZipFile; 6 | 7 | public interface IRemappingPlugin { 8 | void onBeginRemap(ZipFile remappingJar); 9 | 10 | void onBeforeRemapClass(ClassMapping remappingClass); 11 | 12 | void onAfterRemapClass(ClassMapping classRemapped); 13 | 14 | void onDoneRemap(); 15 | } 16 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/Utility.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | public class Utility { 8 | public static byte[] readInputStream(InputStream stream) throws IOException { 9 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 10 | byte[] buffer = new byte[1024]; 11 | 12 | for (int length; (length = stream.read(buffer)) != -1;) { 13 | outputStream.write(buffer, 0, length); 14 | } 15 | 16 | return outputStream.toByteArray(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | container: 12 | image: gradle:jdk8 13 | steps: 14 | - uses: actions/checkout@v2 15 | name: Check out 16 | 17 | - run: gradle publishMavenPublicationToPocolifoRepository 18 | name: Publish 19 | env: 20 | RELEASE_VERSION: ${{ github.ref_name }} 21 | REPO_URL: ${{ secrets.REPO_URL }} 22 | REPO_USERNAME: ${{ secrets.REPO_USERNAME }} 23 | REPO_PASSWORD: ${{ secrets.REPO_PASSWORD }} -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/reader/MappingUtility.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.reader; 2 | 3 | public class MappingUtility { 4 | public static String getNameAfterLastSlash(String str) { 5 | return str.substring(str.lastIndexOf("/") + 1); 6 | } 7 | 8 | public static String getFromClassName(String field) { 9 | return field.substring(0, field.lastIndexOf("/")); 10 | } 11 | 12 | public static String getMethodName(String str) { 13 | return str.split(" ")[0]; 14 | } 15 | 16 | public static String getMethodDescriptor(String str) { 17 | return str.split(" ")[1]; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/mapping/FieldMapping.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.mapping; 2 | 3 | public class FieldMapping { 4 | public final String fromFieldName; 5 | public final String toFieldName; 6 | public final ClassMapping parentClass; 7 | 8 | public FieldMapping(String fromFieldName, String toFieldName, ClassMapping parentClass) { 9 | this.fromFieldName = fromFieldName; 10 | this.toFieldName = toFieldName; 11 | this.parentClass = parentClass; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return this.fromFieldName + " | " + this.toFieldName + " (" + this.parentClass 17 | + ")"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/engine/AbstractRemappingEngine.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.engine; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import com.pocolifo.jarremapper.mapping.JarMapping; 7 | 8 | public abstract class AbstractRemappingEngine { 9 | protected File inputFile; 10 | protected File outputFile; 11 | protected JarMapping mapping; 12 | 13 | public void setInputFile(File inputFile) { 14 | this.inputFile = inputFile; 15 | } 16 | 17 | public void setOutputFile(File outputFile) { 18 | this.outputFile = outputFile; 19 | } 20 | 21 | public void setMapping(JarMapping mapping) { 22 | this.mapping = mapping; 23 | } 24 | 25 | public abstract void remap() throws IOException; 26 | } 27 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/mapping/MethodMapping.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.mapping; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | public class MethodMapping { 8 | public final String fromMethodName; 9 | public final String fromMethodDescriptor; 10 | public final String toMethodName; 11 | public final String toMethodDescriptor; 12 | public final ClassMapping parentClass; 13 | 14 | public final List exceptions = new ArrayList<>(); 15 | public final List parameterNames = new LinkedList<>(); 16 | 17 | public MethodMapping(String fromMethodName, String fromMethodDescriptor, String toMethodName, 18 | String toMethodDescriptor, ClassMapping parentClass) { 19 | this.fromMethodName = fromMethodName; 20 | this.fromMethodDescriptor = fromMethodDescriptor; 21 | this.toMethodName = toMethodName; 22 | this.toMethodDescriptor = toMethodDescriptor; 23 | this.parentClass = parentClass; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return this.fromMethodName + " " + this.fromMethodDescriptor + " | " + this.toMethodName + " " + 29 | this.toMethodDescriptor + " (" + this.parentClass + ")"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'maven-publish' 4 | id 'com.pocolifo.jarremapper.devplugin' 5 | } 6 | 7 | group 'com.pocolifo' 8 | version '2.0.2' 9 | 10 | sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | implementation 'org.ow2.asm:asm-commons:9.2' 18 | 19 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' 20 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' 21 | } 22 | 23 | test { 24 | useJUnitPlatform() 25 | } 26 | 27 | publishing { 28 | publications { 29 | maven(MavenPublication) { 30 | pom { 31 | name = 'JAR Remapper' 32 | description = 'Library for remapping JARs' 33 | artifactId = 'jarremapper' 34 | 35 | licenses { 36 | license { 37 | name = 'Mozilla Public License 2.0' 38 | url = 'https://www.mozilla.org/en-US/MPL/2.0/' 39 | } 40 | } 41 | 42 | developers { 43 | developer { 44 | id = 'youngermax' 45 | } 46 | } 47 | } 48 | 49 | from components['java'] 50 | } 51 | } 52 | 53 | repositories { 54 | maven { 55 | url System.getenv("REPO_URL") 56 | name 'pocolifo' 57 | 58 | credentials { 59 | username = System.getenv("REPO_USERNAME") 60 | password = System.getenv("REPO_PASSWORD") 61 | } 62 | 63 | authentication { 64 | basic(BasicAuthentication) 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper.extensions/src/test/java/com/pocolifo/jarremapper/extensions/Remappers.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.extensions; 2 | 3 | import com.pocolifo.jarremapper.engine.standard.StandardRemappingEngine; 4 | import com.pocolifo.jarremapper.mapping.JarMapping; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.util.Optional; 9 | 10 | public class Remappers { 11 | public static final File OUTPUT = new File("output.jar"); 12 | 13 | public static void remapSpecialSource(File inputFile, JarMapping mapping) throws IOException { 14 | SpecialSourceEngine engine = new SpecialSourceEngine(); 15 | engine.setInputFile(inputFile); 16 | engine.setOutputFile(OUTPUT); 17 | engine.setMapping(mapping); 18 | engine.remap(); 19 | } 20 | 21 | public static void remapTinyRemapper(File inputFile, JarMapping mapping) throws IOException { 22 | TinyRemapperEngine engine = new TinyRemapperEngine(); 23 | engine.setInputFile(inputFile); 24 | engine.setOutputFile(OUTPUT); 25 | engine.setMapping(mapping); 26 | engine.remap(); 27 | } 28 | 29 | public static void remapTinyRemapperExcludeMetaInf(File inputFile, JarMapping mapping) throws IOException { 30 | TinyRemapperEngine engine = new TinyRemapperEngine(); 31 | engine.setInputFile(inputFile); 32 | engine.setOutputFile(OUTPUT); 33 | engine.setMapping(mapping); 34 | engine.excludeMetaInf(); 35 | engine.remap(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/test/java/com/pocolifo/jarremapper/SimpleProgressListener.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper; 2 | 3 | import com.pocolifo.jarremapper.mapping.ClassMapping; 4 | import com.pocolifo.jarremapper.engine.standard.IRemappingPlugin; 5 | 6 | import java.util.Enumeration; 7 | import java.util.zip.ZipEntry; 8 | import java.util.zip.ZipFile; 9 | 10 | public class SimpleProgressListener implements IRemappingPlugin { 11 | 12 | private long start; 13 | private long startClass; 14 | 15 | private int classCount; 16 | private int remappedCount; 17 | 18 | @Override 19 | public void onBeginRemap(ZipFile remappingJar) { 20 | this.start = System.currentTimeMillis(); 21 | 22 | Enumeration entries = remappingJar.entries(); 23 | 24 | while (entries.hasMoreElements()) { 25 | if (entries.nextElement().getName().endsWith(".class")) this.classCount++; 26 | } 27 | 28 | System.out.println("Beginning remap"); 29 | } 30 | 31 | @Override 32 | public void onBeforeRemapClass(ClassMapping classMapping) { 33 | this.startClass = System.currentTimeMillis(); 34 | } 35 | 36 | @Override 37 | public void onAfterRemapClass(ClassMapping classRemapped) { 38 | this.remappedCount++; 39 | 40 | // exact progress 41 | // System.out.println( 42 | // ((System.currentTimeMillis() - this.startClass) / 1000f) + "s | " + 43 | // (classRemapped == null ? "(class mapping not found) " : classRemapped.toClassName) + " | " + 44 | // ((float) this.remappedCount / (float) this.classCount) * 100f + "% complete"); 45 | } 46 | 47 | @Override 48 | public void onDoneRemap() { 49 | System.out.println("Done remapping, took " + ((System.currentTimeMillis() - start) / 1000f) + "s"); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/test/java/com/pocolifo/jarremapper/Remappers.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper; 2 | 3 | import com.pocolifo.jarremapper.engine.standard.StandardRemappingEngine; 4 | import com.pocolifo.jarremapper.mapping.JarMapping; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | public class Remappers { 10 | public static final File OUTPUT = new File("output.jar"); 11 | 12 | public static void remapNormal(File inputFile, JarMapping mapping) throws IOException { 13 | StandardRemappingEngine engine = new StandardRemappingEngine(); 14 | engine.setInputFile(inputFile); 15 | engine.setOutputFile(OUTPUT); 16 | engine.setMapping(mapping); 17 | engine.remap(); 18 | } 19 | 20 | public static void remapExcludeMetaInf(File inputFile, JarMapping mapping) throws IOException { 21 | StandardRemappingEngine engine = new StandardRemappingEngine(); 22 | engine.excludeMetaInf(); 23 | engine.setInputFile(inputFile); 24 | engine.setOutputFile(OUTPUT); 25 | engine.setMapping(mapping); 26 | engine.remap(); 27 | } 28 | 29 | public static void remapNormalWithPlugin(File inputFile, JarMapping mapping) throws IOException { 30 | StandardRemappingEngine engine = new StandardRemappingEngine(); 31 | engine.setRemappingPlugin(new SimpleProgressListener()); 32 | engine.setInputFile(inputFile); 33 | engine.setOutputFile(OUTPUT); 34 | engine.setMapping(mapping); 35 | engine.remap(); 36 | } 37 | 38 | public static void remapExcludeMetaInfWithPlugin(File inputFile, JarMapping mapping) throws IOException { 39 | StandardRemappingEngine engine = new StandardRemappingEngine(); 40 | engine.excludeMetaInf(); 41 | engine.setRemappingPlugin(new SimpleProgressListener()); 42 | engine.setInputFile(inputFile); 43 | engine.setOutputFile(OUTPUT); 44 | engine.setMapping(mapping); 45 | engine.remap(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper.extensions/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'maven-publish' 4 | id 'com.pocolifo.jarremapper.devplugin' 5 | } 6 | 7 | group 'com.pocolifo.jarremapper' 8 | version '1.2.1' 9 | 10 | repositories { 11 | mavenCentral() 12 | mavenLocal() 13 | 14 | maven { 15 | url 'https://maven.fabricmc.net' 16 | } 17 | } 18 | 19 | dependencies { 20 | implementation project(':com.pocolifo.jarremapper') 21 | implementation 'net.fabricmc:tiny-remapper:0.9.0' 22 | implementation 'net.md-5:SpecialSource:1.11.0' 23 | 24 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' 25 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' 26 | } 27 | 28 | test { 29 | useJUnitPlatform() 30 | } 31 | 32 | publishing { 33 | publications { 34 | maven(MavenPublication) { 35 | pom { 36 | name = 'JAR Remapper Extensions' 37 | description = 'Extra features for JAR Remapper' 38 | artifactId = 'extensions' 39 | version = System.getenv("RELEASE_VERSION") == null ? project.version : System.getenv("RELEASE_VERSION") 40 | 41 | licenses { 42 | license { 43 | name = 'MIT License' 44 | url = 'https://spdx.org/licenses/MIT.html' 45 | } 46 | } 47 | 48 | developers { 49 | developer { 50 | id = 'youngermax' 51 | } 52 | } 53 | } 54 | 55 | from components['java'] 56 | } 57 | } 58 | 59 | repositories { 60 | maven { 61 | url System.getenv("REPO_URL") 62 | name 'pocolifo' 63 | 64 | credentials { 65 | username = System.getenv("REPO_USERNAME") 66 | password = System.getenv("REPO_PASSWORD") 67 | } 68 | 69 | authentication { 70 | basic(BasicAuthentication) 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/JarRemapper.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | 7 | import com.pocolifo.jarremapper.engine.standard.StandardRemappingEngine; 8 | import com.pocolifo.jarremapper.mapping.JarMapping; 9 | import com.pocolifo.jarremapper.engine.AbstractRemappingEngine; 10 | 11 | public class JarRemapper { 12 | private AbstractRemappingEngine remappingEngine = new StandardRemappingEngine(); 13 | private File inputFile; 14 | private File outputFile; 15 | private JarMapping mappings; 16 | private boolean overwriteOutputFile; 17 | 18 | public static JarRemapper newRemap() { 19 | return new JarRemapper(); 20 | } 21 | 22 | public JarRemapper withRemappingEngine(AbstractRemappingEngine remappingEngine) { 23 | this.remappingEngine = remappingEngine; 24 | return this; 25 | } 26 | 27 | public JarRemapper withMappings(JarMapping mappings) { 28 | this.mappings = mappings; 29 | return this; 30 | } 31 | 32 | public JarRemapper withInputFile(File inputFile) { 33 | this.inputFile = inputFile; 34 | return this; 35 | } 36 | 37 | public JarRemapper withOutputFile(File outputFile) { 38 | this.outputFile = outputFile; 39 | return this; 40 | } 41 | 42 | public JarRemapper overwriteOutputFile() { 43 | this.overwriteOutputFile = !this.overwriteOutputFile; 44 | return this; 45 | } 46 | 47 | public void remap() throws IOException { 48 | assert this.inputFile != null; 49 | assert this.inputFile.exists(); 50 | assert this.inputFile.isFile(); 51 | 52 | assert this.outputFile != null; 53 | 54 | if (this.overwriteOutputFile) { 55 | Files.deleteIfExists(this.outputFile.toPath()); 56 | } 57 | 58 | assert !this.outputFile.exists(); 59 | 60 | assert this.mappings != null; 61 | 62 | this.remappingEngine.setInputFile(this.inputFile); 63 | this.remappingEngine.setOutputFile(this.outputFile); 64 | this.remappingEngine.setMapping(this.mappings); 65 | 66 | this.remappingEngine.remap(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper.extensions/README.md: -------------------------------------------------------------------------------- 1 | # JAR Remapper Extension 2 | 3 | Extra features for [JAR Remapper](https://github.com/pocolifo/jar-remapper) 4 | 5 | ## Features 6 | 7 | #### More Remapping Engines 8 | - [Tiny Remapper](https://github.com/FabricMC/tiny-remapper) by FabricMC 9 | - [Special Source](https://github.com/md-5/SpecialSource) by MD-5 10 | 11 | 12 | ## Mapping Engine Support 13 | | Remapping Engine | Classes | Fields | Methods | Parameters | 14 | |------------------|---------|--------|---------|-------------| 15 | | Standard | X | X | X | X | 16 | | Tiny Remapper | X | X | X | Coming Soon | 17 | | Special Source | X | X | X | | 18 | 19 | `X` = Support 20 | 21 | ## Coming Soon 22 | - Parameter name remapping for Tiny Remapper 23 | 24 | ## Getting Started 25 | 26 | #### Tiny Remapper Remapping Engine 27 | 28 | Append the `withRemappingEngine` option to JAR Remapper. 29 | 30 | ```java 31 | JarRemapper.newRemap() 32 | .withRemappingEngine(new TinyRemapperEngine() 33 | // (required) 34 | // Use any options you'd like from Tiny Remapper 35 | // except for: withMappings and ignoreFieldDesc 36 | // These are automatically set. 37 | .setOptions(TinyRemapper.newRemapper()) 38 | 39 | // (optional) 40 | // Excludes the META-INF directory from output JAR 41 | .excludeMetaInf() 42 | ) 43 | // ...whatever other options you use for JAR Remapper... 44 | ``` 45 | 46 | #### Special Source Remapping Engine 47 | 48 | Append the `withRemappingEngine` option to JAR Remapper. 49 | 50 | ```java 51 | JarRemapper.newRemap() 52 | .withRemappingEngine(new SpecialSourceEngine() 53 | // (optional) 54 | // Excludes the META-INF directory from output JAR 55 | .excludeMetaInf() 56 | ) 57 | // ...whatever other options you use for JAR Remapper... 58 | ``` 59 | 60 | # Develop 61 | 62 | 1. Clone this repository 63 | 2. Import the project into IntelliJ IDEA 64 | 65 | ### To test 66 | 1. Edit the `jarremapper` extension configuration in [build.gradle](./build.gradle) to add readers and engines 67 | 2. Run the `generateTests` Gradle task under the `jarremapperdev` group to generate test classes 68 | 3. Test like normal 69 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/mapping/JarMapping.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.mapping; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class JarMapping { 7 | public final List classMappings = new ArrayList<>(); 8 | 9 | public ClassMapping getClassByFromName(String fromName) { 10 | for (ClassMapping classMapping : this.classMappings) { 11 | if (classMapping.fromClassName.equals(fromName)) return classMapping; 12 | } 13 | 14 | return null; 15 | } 16 | 17 | public ClassMapping getClassByToName(String toName) { 18 | for (ClassMapping classMapping : this.classMappings) { 19 | if (classMapping.toClassName.equals(toName)) return classMapping; 20 | } 21 | 22 | return null; 23 | } 24 | 25 | public void reverse() { 26 | List reversed = new ArrayList<>(); 27 | 28 | for (ClassMapping oldClassMapping : this.classMappings) { 29 | ClassMapping newClassMapping = new ClassMapping(oldClassMapping.toClassName, oldClassMapping.fromClassName, 30 | this); 31 | 32 | for (MethodMapping oldMethodMapping : oldClassMapping.methodMappings) { 33 | MethodMapping newMethodMapping = new MethodMapping(oldMethodMapping.toMethodName, 34 | oldMethodMapping.toMethodDescriptor, oldMethodMapping.fromMethodName, 35 | oldMethodMapping.fromMethodDescriptor, newClassMapping); 36 | 37 | for (int i = 0; i < oldMethodMapping.parameterNames.size(); i++) { 38 | newMethodMapping.parameterNames.add("var" + i); 39 | } 40 | 41 | newClassMapping.methodMappings.add(newMethodMapping); 42 | } 43 | 44 | for (FieldMapping oldFieldMapping : oldClassMapping.fieldMappings) { 45 | FieldMapping newFieldMapping = new FieldMapping(oldFieldMapping.toFieldName, 46 | oldFieldMapping.fromFieldName, newClassMapping); 47 | 48 | newClassMapping.fieldMappings.add(newFieldMapping); 49 | } 50 | 51 | 52 | reversed.add(newClassMapping); 53 | } 54 | 55 | this.classMappings.clear(); 56 | this.classMappings.addAll(reversed); 57 | reversed.clear(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper.extensions/src/main/java/com/pocolifo/jarremapper/extensions/SpecialSourceEngine.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.extensions; 2 | 3 | import java.io.IOException; 4 | 5 | import com.pocolifo.jarremapper.engine.AbstractRemappingEngine; 6 | import com.pocolifo.jarremapper.mapping.ClassMapping; 7 | import com.pocolifo.jarremapper.mapping.FieldMapping; 8 | import com.pocolifo.jarremapper.mapping.MethodMapping; 9 | import net.md_5.specialsource.Jar; 10 | import net.md_5.specialsource.JarMapping; 11 | import net.md_5.specialsource.JarRemapper; 12 | import net.md_5.specialsource.provider.JarProvider; 13 | import net.md_5.specialsource.provider.JointProvider; 14 | 15 | public class SpecialSourceEngine extends AbstractRemappingEngine { 16 | private boolean excludeMetaInf; 17 | 18 | public SpecialSourceEngine excludeMetaInf() { 19 | this.excludeMetaInf = !this.excludeMetaInf; 20 | return this; 21 | } 22 | 23 | @Override 24 | public void remap() throws IOException { 25 | JarMapping jarMapping = this.convertJarMapping(); 26 | Jar jar = Jar.init(this.inputFile); 27 | 28 | JointProvider inheritanceProviders = new JointProvider(); 29 | inheritanceProviders.add(new JarProvider(jar)); 30 | jarMapping.setFallbackInheritanceProvider(inheritanceProviders); 31 | 32 | JarRemapper remapper = new JarRemapper(jarMapping); 33 | remapper.remapJar(jar, this.outputFile); 34 | 35 | ExtensionUtility.copyResources(this.inputFile, this.outputFile); 36 | if (this.excludeMetaInf) ExtensionUtility.removeMetaInf(this.outputFile); 37 | } 38 | 39 | public JarMapping convertJarMapping() { 40 | JarMapping jarMapping = new JarMapping(); 41 | 42 | for (ClassMapping classMapping : this.mapping.classMappings) { 43 | jarMapping.classes.put(classMapping.fromClassName, classMapping.toClassName); 44 | 45 | for (FieldMapping fieldMapping : classMapping.fieldMappings) { 46 | jarMapping.fields.put(String.format("%s/%s", classMapping.fromClassName, 47 | fieldMapping.fromFieldName), fieldMapping.toFieldName); 48 | } 49 | 50 | for (MethodMapping methodMapping : classMapping.methodMappings) { 51 | jarMapping.methods.put( 52 | String.format("%s/%s %s", 53 | classMapping.fromClassName, 54 | methodMapping.fromMethodName, 55 | methodMapping.fromMethodDescriptor), 56 | methodMapping.toMethodName); 57 | } 58 | 59 | } 60 | 61 | return jarMapping; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/engine/standard/ParameterEnhancedRemapper.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.engine.standard; 2 | 3 | import com.pocolifo.jarremapper.mapping.ClassMapping; 4 | import com.pocolifo.jarremapper.mapping.JarMapping; 5 | import com.pocolifo.jarremapper.mapping.MethodMapping; 6 | import org.objectweb.asm.commons.ClassRemapper; 7 | import org.objectweb.asm.tree.ClassNode; 8 | import org.objectweb.asm.tree.LocalVariableNode; 9 | import org.objectweb.asm.tree.MethodNode; 10 | 11 | public class ParameterEnhancedRemapper extends ClassRemapper { 12 | private final JarMapping mapping; 13 | private final MappingProvider mappingProvider; 14 | 15 | private String currentClass; 16 | 17 | public ParameterEnhancedRemapper(MappingProvider remapper, ClassNode node, JarMapping mapping) { 18 | super(node, remapper); 19 | 20 | this.mapping = mapping; 21 | this.mappingProvider = remapper; 22 | } 23 | 24 | @Override 25 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 26 | this.currentClass = name; 27 | 28 | super.visit(version, access, name, signature, superName, interfaces); 29 | } 30 | 31 | @Override 32 | public void visitEnd() { 33 | ClassMapping classMapping = this.mapping.getClassByFromName(this.currentClass); 34 | ClassNode cn = (ClassNode) this.cv; 35 | 36 | for (MethodNode method : cn.methods) { 37 | if (method.localVariables == null) continue; 38 | 39 | MethodMapping methodMapping = null; 40 | if (classMapping != null) methodMapping = classMapping.getMethodByToName(method.name, method.desc); 41 | 42 | for (int i = 0; method.localVariables.size() > i; i++) { 43 | LocalVariableNode lvn = method.localVariables.get(i); 44 | 45 | // TODO: remove this, seems to be working fine 46 | // if (lvn.name.charAt(0) != 0x2603) { 47 | // continue; 48 | // } 49 | 50 | // TODO: often misses first parameter name, fix 51 | if (methodMapping != null && methodMapping.parameterNames.size() > i) { 52 | lvn.name = methodMapping.parameterNames.get(i); 53 | } else { 54 | lvn.name = "var" + i; 55 | } 56 | } 57 | } 58 | 59 | super.visitEnd(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper.extensions/src/main/java/com/pocolifo/jarremapper/extensions/ExtensionUtility.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.extensions; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.net.URI; 7 | import java.nio.file.*; 8 | import java.nio.file.attribute.BasicFileAttributes; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.zip.ZipEntry; 12 | import java.util.zip.ZipInputStream; 13 | 14 | import com.pocolifo.jarremapper.Utility; 15 | 16 | public class ExtensionUtility { 17 | private static Map getEnvironment() { 18 | Map env = new HashMap<>(); 19 | env.put("create", "true"); 20 | return env; 21 | } 22 | 23 | private static FileSystem getFileSystem(File targetFile) throws IOException { 24 | URI uri = URI.create("jar:" + targetFile.toURI()); 25 | return FileSystems.newFileSystem(uri, getEnvironment()); 26 | } 27 | 28 | public static void copyResources(File inputFile, File outputFile) throws IOException { 29 | try (FileSystem fileSystem = getFileSystem(outputFile)) { 30 | try (ZipInputStream stream = new ZipInputStream(new FileInputStream(inputFile))) { 31 | for (ZipEntry entry; (entry = stream.getNextEntry()) != null;) { 32 | if (entry.isDirectory()) continue; 33 | if (entry.getName().endsWith(".class")) continue; 34 | 35 | Path path = fileSystem.getPath(entry.getName()); 36 | 37 | if (path.getParent() != null) { 38 | Files.createDirectories(path.getParent()); 39 | } 40 | 41 | Files.write(path, Utility.readInputStream(stream)); 42 | } 43 | } 44 | } 45 | } 46 | 47 | private static void recursivelyRemovePath(Path path) throws IOException { 48 | if (!Files.isDirectory(path)) return; 49 | 50 | Files.walkFileTree(path, new SimpleFileVisitor() { 51 | @Override 52 | public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { 53 | return Files.deleteIfExists(path) ? FileVisitResult.CONTINUE : FileVisitResult.TERMINATE; 54 | } 55 | 56 | @Override 57 | public FileVisitResult postVisitDirectory(Path path, IOException e) throws IOException { 58 | return Files.deleteIfExists(path) ? FileVisitResult.CONTINUE : FileVisitResult.TERMINATE; 59 | } 60 | }); 61 | } 62 | 63 | public static void removeMetaInf(File file) throws IOException { 64 | try (FileSystem fileSystem = getFileSystem(file)) { 65 | recursivelyRemovePath(fileSystem.getPath("META-INF")); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/mapping/ClassMapping.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.mapping; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ClassMapping { 7 | public final String fromClassName; 8 | public final String toClassName; 9 | public final JarMapping parentJar; 10 | 11 | 12 | // field mappings inside this class 13 | public final List fieldMappings = new ArrayList<>(); 14 | 15 | // method mappings inside this class 16 | public final List methodMappings = new ArrayList<>(); 17 | 18 | public ClassMapping(String fromClassName, String toClassName, JarMapping parentJar) { 19 | this.fromClassName = fromClassName; 20 | this.toClassName = toClassName; 21 | this.parentJar = parentJar; 22 | } 23 | 24 | public MethodMapping getMethodByFromName(String fromName, String fromDesc) { 25 | for (MethodMapping methodMapping : this.methodMappings) { 26 | if (methodMapping.fromMethodName.equals(fromName)) { 27 | if (fromDesc == null) { 28 | return methodMapping; 29 | } else if (methodMapping.fromMethodDescriptor.equals(fromDesc)) { 30 | return methodMapping; 31 | } 32 | } 33 | } 34 | 35 | return null; 36 | } 37 | 38 | public MethodMapping getMethodByToName(String toName, String toDesc) { 39 | for (MethodMapping methodMapping : this.methodMappings) { 40 | if (methodMapping.toMethodName.equals(toName)) { 41 | if (toDesc == null) { 42 | return methodMapping; 43 | } else if (methodMapping.toMethodDescriptor.equals(toDesc)) { 44 | return methodMapping; 45 | } 46 | } 47 | } 48 | 49 | return null; 50 | } 51 | 52 | public FieldMapping getFieldByFromName(String fromName) { 53 | for (FieldMapping fieldMapping : this.fieldMappings) { 54 | if (fieldMapping.fromFieldName.equals(fromName)) return fieldMapping; 55 | } 56 | 57 | return null; 58 | } 59 | 60 | public FieldMapping getFieldByToName(String toName) { 61 | for (FieldMapping fieldMapping : this.fieldMappings) { 62 | if (fieldMapping.toFieldName.equals(toName)) return fieldMapping; 63 | } 64 | 65 | return null; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return this.fromClassName + " | " + this.toClassName; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pocolifo's JAR Remapper 2 | 3 | Making remapping JARs easy, organized, and painless 4 | 5 | ## Features 6 | 7 | #### Remapping Engines 8 | - Multiple different engines to remap JARs 9 | - StandardRemappingEngine by the devs of JAR Remapper 10 | - FabricMC's TinyRemapper using a Remapping Engine (*requires additional dependency, see [jar-remapper-extension](https://github.com/pocolifo/jar-remapper-extension)*) 11 | 12 | #### Remapping 13 | - Class remapping 14 | - Method remapping 15 | - Field remapping 16 | - Parameter remapping 17 | 18 | #### Common mapping formats 19 | - Built-in ModCoderPack's SRG/MCP mapping support 20 | - Built-in Tiny v1/v2 mapping support 21 | 22 | #### Flexible API 23 | - Custom Mapping Readers 24 | - Custom Remapping Engines 25 | 26 | ## Coming Soon 27 | - Built-in Proguard mapping support 28 | 29 | 30 | # Getting Started 31 | 32 | Load in your favorite mapping format 33 | 34 | ```java 35 | JarMapping mappings; 36 | 37 | // MCP mappings 38 | mappings = new McpMappingReader( 39 | new File("joined.srg"), 40 | new File("joined.exc"), 41 | 42 | new File("methods.csv"), 43 | new File("fields.csv"), 44 | new File("params.csv") 45 | ).read(); 46 | 47 | // Tiny v1 mappings 48 | mappings = new Tiny1MappingReader( 49 | new File("mappings-tiny-v1.tiny") 50 | ).read("remapFromThisNamespace", "remapToThisNamespace"); 51 | 52 | // Tiny v2 mappings 53 | mappings = new Tiny2MappingReader( 54 | new File("mappings-tiny-v2.tiny") 55 | ).read("remapFromThisNamespace", "remapToThisNamespace"); 56 | ``` 57 | 58 | With your mappings, remap your JAR file 59 | 60 | ```java 61 | JarRemapper.newRemap() 62 | // (required) 63 | // The JAR to be remap 64 | .withInputFile(new File("input.jar")) 65 | 66 | // (required) 67 | // The output of the remapped JAR 68 | .withOutputFile(new File("output.jar")) 69 | 70 | // (required) 71 | // The mappings to remap the JAR with 72 | .withMappings(mappings) 73 | 74 | // (optional) 75 | // The Remapping Engine to remap the JAR with 76 | // default: StandardRemappingEngine 77 | .withRemappingEngine(new StandardRemappingEngine()) 78 | 79 | // (optional) 80 | // Automatically deletes the output file before remapping 81 | // default: false 82 | .overwriteOutputFile() 83 | 84 | // Begin remapping the JAR! 85 | .remap(); 86 | ``` 87 | 88 | # Develop 89 | 90 | 1. Clone this repository 91 | 2. Import the project into IntelliJ IDEA 92 | 93 | ### To test 94 | 1. Edit the `jarremapper` extension configuration in [build.gradle](com.pocolifo.jarremapper/build.gradle) to add readers and engines 95 | 2. Run the `generateTests` Gradle task under the `jarremapperdev` group to generate test classes 96 | 3. Test like normal -------------------------------------------------------------------------------- /com.pocolifo.jarremapper.extensions/src/main/java/com/pocolifo/jarremapper/extensions/TinyRemapperEngine.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.extensions; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | 6 | import com.pocolifo.jarremapper.engine.AbstractRemappingEngine; 7 | import com.pocolifo.jarremapper.mapping.ClassMapping; 8 | import com.pocolifo.jarremapper.mapping.FieldMapping; 9 | import com.pocolifo.jarremapper.mapping.JarMapping; 10 | import com.pocolifo.jarremapper.mapping.MethodMapping; 11 | import net.fabricmc.tinyremapper.IMappingProvider; 12 | import net.fabricmc.tinyremapper.OutputConsumerPath; 13 | import net.fabricmc.tinyremapper.TinyRemapper; 14 | 15 | public class TinyRemapperEngine extends AbstractRemappingEngine { 16 | private TinyRemapper.Builder options = TinyRemapper.newRemapper(); 17 | private boolean excludeMetaInf; 18 | private Path[] classpath; 19 | 20 | public TinyRemapperEngine setOptions(TinyRemapper.Builder options) { 21 | this.options = options; 22 | return this; 23 | } 24 | 25 | public TinyRemapperEngine excludeMetaInf() { 26 | this.excludeMetaInf = !this.excludeMetaInf; 27 | return this; 28 | } 29 | 30 | public TinyRemapperEngine setClasspath(Path... classpath) { 31 | this.classpath = classpath; 32 | return this; 33 | } 34 | 35 | @Override 36 | public void remap() throws IOException { 37 | TinyRemapper remapper = this.options 38 | .withMappings(createProvider(this.mapping)) 39 | .ignoreFieldDesc(true) 40 | .build(); 41 | 42 | remapper.readInputs(this.inputFile.toPath()); 43 | if (this.classpath != null) remapper.readClassPath(this.classpath); 44 | 45 | try (OutputConsumerPath path = new OutputConsumerPath.Builder(this.outputFile.toPath()).build()) { 46 | remapper.apply(path); 47 | } finally { 48 | remapper.finish(); 49 | } 50 | 51 | // copy resources 52 | ExtensionUtility.copyResources(this.inputFile, this.outputFile); 53 | if (this.excludeMetaInf) ExtensionUtility.removeMetaInf(this.outputFile); 54 | } 55 | 56 | public static IMappingProvider createProvider(JarMapping mapping) { 57 | return acceptor -> { 58 | for (ClassMapping cls : mapping.classMappings) { 59 | acceptor.acceptClass(cls.fromClassName, cls.toClassName); 60 | 61 | for (FieldMapping fld : cls.fieldMappings) { 62 | acceptor.acceptField(new IMappingProvider.Member(cls.fromClassName, fld.fromFieldName, null), fld.toFieldName); 63 | } 64 | 65 | for (MethodMapping mtd : cls.methodMappings) { 66 | IMappingProvider.Member mtdMember = new IMappingProvider.Member(cls.fromClassName, mtd.fromMethodName, mtd.fromMethodDescriptor); 67 | 68 | acceptor.acceptMethod(mtdMember, mtd.toMethodName); 69 | 70 | // TODO: Method parameters 71 | } 72 | } 73 | }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/reader/tiny/Tiny1MappingReader.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.reader.tiny; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.util.*; 7 | 8 | import com.pocolifo.jarremapper.mapping.ClassMapping; 9 | import com.pocolifo.jarremapper.mapping.FieldMapping; 10 | import com.pocolifo.jarremapper.mapping.JarMapping; 11 | import com.pocolifo.jarremapper.mapping.MethodMapping; 12 | 13 | public class Tiny1MappingReader { 14 | private final File file; 15 | private final List namespaces; 16 | private final JarMapping mapping; 17 | 18 | public Tiny1MappingReader(File file) { 19 | this.file = file; 20 | this.namespaces = new LinkedList<>(); 21 | this.mapping = new JarMapping(); 22 | } 23 | 24 | public JarMapping read(String fromNamespace, String toNamespace) throws IOException { 25 | int lineNumber = 0; 26 | 27 | for (String line : Files.readAllLines(this.file.toPath())) { 28 | String[] fields = line.split("\t"); 29 | 30 | if (lineNumber == 0) { 31 | assert fields[0].equals("v1"); 32 | this.namespaces.addAll(Arrays.asList(fields).subList(1, fields.length)); 33 | } else { 34 | String type = fields[0].toLowerCase(); 35 | 36 | switch (type) { 37 | case "class": { 38 | int i = 0; 39 | Map namespaceClassMap = new LinkedHashMap<>(); 40 | 41 | for (String mapping : Arrays.asList(fields).subList(1, fields.length)) { 42 | namespaceClassMap.put(this.namespaces.get(i), mapping); 43 | i++; 44 | } 45 | 46 | this.mapping.classMappings.add(new ClassMapping(namespaceClassMap.get(fromNamespace), namespaceClassMap.get(toNamespace), this.mapping)); 47 | break; 48 | } 49 | case "field": { 50 | int i = 0; 51 | Map namespaceFieldMap = new LinkedHashMap<>(); 52 | 53 | for (String mapping : Arrays.asList(fields).subList(3, fields.length)) { 54 | namespaceFieldMap.put(this.namespaces.get(i), mapping); 55 | i++; 56 | } 57 | 58 | ClassMapping parentClass = this.mapping.getClassByFromName(fields[1]); 59 | parentClass.fieldMappings.add(new FieldMapping(namespaceFieldMap.get(fromNamespace), namespaceFieldMap.get(toNamespace), parentClass)); 60 | break; 61 | } 62 | case "method": { 63 | int i = 0; 64 | Map namespaceMethodMap = new LinkedHashMap<>(); 65 | 66 | for (String mapping : Arrays.asList(fields).subList(3, fields.length)) { 67 | namespaceMethodMap.put(this.namespaces.get(i), mapping); 68 | i++; 69 | } 70 | 71 | ClassMapping parentClass = this.mapping.getClassByFromName(fields[1]); 72 | parentClass.methodMappings.add(new MethodMapping(namespaceMethodMap.get(fromNamespace), fields[2], namespaceMethodMap.get(toNamespace), fields[2], parentClass)); 73 | break; 74 | } 75 | } 76 | } 77 | 78 | lineNumber++; 79 | } 80 | 81 | return this.mapping; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/reader/tiny/Tiny2MappingReader.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.reader.tiny; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.util.Arrays; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | import com.pocolifo.jarremapper.mapping.ClassMapping; 11 | import com.pocolifo.jarremapper.mapping.FieldMapping; 12 | import com.pocolifo.jarremapper.mapping.JarMapping; 13 | import com.pocolifo.jarremapper.mapping.MethodMapping; 14 | 15 | public class Tiny2MappingReader { 16 | private final File mappingFile; 17 | private final List namespaces; 18 | 19 | public Tiny2MappingReader(File mappingFile) { 20 | this.mappingFile = mappingFile; 21 | 22 | this.namespaces = new LinkedList<>(); 23 | } 24 | 25 | public JarMapping read(String fromNamespace, String toNamespace) throws IOException { 26 | int lineNumber = 0; 27 | 28 | JarMapping mapping = new JarMapping(); 29 | 30 | ClassMapping currentClass = null; 31 | MethodMapping currentMethod = null; 32 | 33 | int fromIndex = 0; 34 | int toIndex = 0; 35 | 36 | for (String line : Files.readAllLines(this.mappingFile.toPath())) { 37 | String[] fields = line.split("\t"); 38 | 39 | if (lineNumber == 0) { 40 | assert fields[0].equals("tiny") && fields[1].equals("2"); 41 | this.namespaces.addAll(Arrays.asList(fields).subList(3, fields.length)); 42 | 43 | fromIndex = this.namespaces.indexOf(fromNamespace); 44 | toIndex = this.namespaces.indexOf(toNamespace); 45 | } else { 46 | if (fields[0].equals("c")) { 47 | if (currentMethod != null) { 48 | currentClass.methodMappings.add(currentMethod); 49 | } 50 | 51 | if (currentClass != null) { 52 | mapping.classMappings.add(currentClass); 53 | currentClass = null; 54 | } 55 | 56 | currentClass = new ClassMapping(fields[fromIndex + 1], fields[toIndex + 1], mapping); 57 | } else if (fields[0].isEmpty() && fields[1].equals("f")) { 58 | if (currentMethod != null) { 59 | currentClass.methodMappings.add(currentMethod); 60 | } 61 | 62 | currentClass.fieldMappings.add(new FieldMapping(fields[fromIndex + 3], fields[toIndex + 3], currentClass)); 63 | } else if (fields[0].isEmpty() && fields[1].equals("m")) { 64 | if (currentMethod != null) { 65 | currentClass.methodMappings.add(currentMethod); 66 | currentMethod = null; 67 | } 68 | 69 | currentMethod = new MethodMapping(fields[fromIndex + 3], fields[2], fields[toIndex + 3], fields[2], currentClass); 70 | } else if (fields[0].isEmpty() && fields[1].isEmpty() && fields[2].equals("p")) { 71 | int index = Integer.parseInt(fields[3]); 72 | 73 | while (index + 1 > currentMethod.parameterNames.size()) { 74 | currentMethod.parameterNames.add("var" + index); 75 | } 76 | 77 | currentMethod.parameterNames.set(index, fields[fields.length - 1]); 78 | } 79 | } 80 | 81 | lineNumber++; 82 | } 83 | 84 | if (currentMethod != null) { 85 | currentClass.methodMappings.add(currentMethod); 86 | } 87 | 88 | mapping.classMappings.add(currentClass); 89 | 90 | return mapping; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/engine/standard/MappingProvider.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.engine.standard; 2 | 3 | import com.pocolifo.jarremapper.mapping.ClassMapping; 4 | import com.pocolifo.jarremapper.mapping.FieldMapping; 5 | import com.pocolifo.jarremapper.mapping.JarMapping; 6 | import com.pocolifo.jarremapper.mapping.MethodMapping; 7 | import org.objectweb.asm.commons.Remapper; 8 | import org.objectweb.asm.tree.ClassNode; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class MappingProvider extends Remapper { 14 | private final JarMapping jarMapping; 15 | private final StandardRemappingEngine jarRemapper; 16 | 17 | private final ClassNode currentClass; 18 | 19 | public MappingProvider(JarMapping mapping, ClassNode currentClass, StandardRemappingEngine remapper) { 20 | this.jarMapping = mapping; 21 | this.jarRemapper = remapper; 22 | 23 | this.currentClass = currentClass; 24 | } 25 | 26 | @Override 27 | public String mapMethodName(String owner, String name, String descriptor) { 28 | String methodName = this.getMethodName(owner, name, descriptor); 29 | return methodName == null ? super.mapMethodName(owner, name, descriptor) : methodName; 30 | } 31 | 32 | private String getMethodName(String owner_fromName, String name_fromName, String descriptor) { 33 | ClassMapping cm = this.jarMapping.getClassByFromName(owner_fromName); 34 | 35 | if (cm == null) return name_fromName; // most likely from a Minecraft dependency 36 | 37 | MethodMapping mm = cm.getMethodByFromName(name_fromName, descriptor); 38 | 39 | if (mm == null) { // most likely in a parent class 40 | for (String parentClass : this.getParents(this.jarRemapper.getClassNode(owner_fromName))) { 41 | String methodName = this.getMethodName(parentClass, name_fromName, descriptor); 42 | if (!methodName.equals(name_fromName)) return methodName; 43 | } 44 | } 45 | 46 | return mm == null ? name_fromName : mm.toMethodName; 47 | } 48 | 49 | @Override 50 | public String mapFieldName(String owner, String name, String descriptor) { 51 | String fieldName = this.getFieldName(owner, name, descriptor); 52 | return fieldName == null ? super.mapFieldName(owner, name, descriptor) : fieldName; 53 | } 54 | 55 | private String getFieldName(String owner_fromName, String name_fromName, String descriptor) { 56 | ClassMapping cm = this.jarMapping.getClassByFromName(owner_fromName); 57 | if (cm == null) return name_fromName; // most likely from a Minecraft dependency 58 | 59 | FieldMapping fm = cm.getFieldByFromName(name_fromName); 60 | 61 | if (fm == null) { // most likely in a parent class 62 | for (String parentClass : this.getParents(this.jarRemapper.getClassNode(owner_fromName))) { 63 | String fieldName = this.getFieldName(parentClass, name_fromName, descriptor); 64 | if (!fieldName.equals(name_fromName)) return fieldName; 65 | } 66 | } 67 | 68 | return fm == null ? name_fromName : fm.toFieldName; 69 | } 70 | 71 | @Override 72 | public String map(String internalName) { 73 | ClassMapping cls = this.jarMapping.getClassByFromName(internalName); 74 | 75 | if (cls != null) return cls.toClassName; 76 | 77 | return super.map(internalName); 78 | } 79 | 80 | private List getParents(ClassNode currentClass) { 81 | List parents = new ArrayList<>(); 82 | 83 | if (currentClass.superName != null) { 84 | parents.add(currentClass.superName); 85 | } 86 | 87 | parents.addAll(currentClass.interfaces); 88 | 89 | 90 | return parents; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/engine/standard/StandardRemappingEngine.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.engine.standard; 2 | 3 | import java.io.FileOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.util.Enumeration; 7 | import java.util.zip.ZipEntry; 8 | import java.util.zip.ZipFile; 9 | import java.util.zip.ZipOutputStream; 10 | 11 | import com.pocolifo.jarremapper.Utility; 12 | import com.pocolifo.jarremapper.engine.AbstractRemappingEngine; 13 | import org.objectweb.asm.ClassReader; 14 | import org.objectweb.asm.ClassWriter; 15 | import org.objectweb.asm.commons.ClassRemapper; 16 | import org.objectweb.asm.tree.ClassNode; 17 | 18 | public class StandardRemappingEngine extends AbstractRemappingEngine { 19 | private IRemappingPlugin remappingPlugin; 20 | private boolean excludeMetaInf; 21 | private ZipFile zipFile; 22 | 23 | public StandardRemappingEngine setRemappingPlugin(IRemappingPlugin remappingPlugin) { 24 | this.remappingPlugin = remappingPlugin; 25 | return this; 26 | } 27 | 28 | public StandardRemappingEngine excludeMetaInf() { 29 | this.excludeMetaInf = !this.excludeMetaInf; 30 | return this; 31 | } 32 | 33 | // getters 34 | public IRemappingPlugin getRemappingPlugin() { 35 | return this.remappingPlugin; 36 | } 37 | 38 | public boolean isExcludingMetaInf() { 39 | return this.excludeMetaInf; 40 | } 41 | 42 | @Override 43 | public void remap() throws IOException { 44 | this.zipFile = new ZipFile(this.inputFile); 45 | 46 | // actually remap the jar 47 | 48 | // output stream for output jar 49 | 50 | try (ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(this.outputFile))) { 51 | // zip file to read the input jar 52 | try (ZipFile file = new ZipFile(this.inputFile)) { 53 | this.zipFile = file; 54 | 55 | // beginning to remap the jar 56 | if (this.remappingPlugin != null) this.remappingPlugin.onBeginRemap(this.zipFile); 57 | 58 | Enumeration entries = file.entries(); 59 | 60 | // loop through every file in the jar 61 | while (entries.hasMoreElements()) { 62 | // get the file entry in the jar 63 | ZipEntry entry = entries.nextElement(); 64 | 65 | if (this.excludeMetaInf && entry.getName().startsWith("META-INF")) { 66 | outputStream.closeEntry(); 67 | continue; 68 | } 69 | 70 | // information about the class to insert into the 71 | // remapped jar 72 | ZipEntry newEntry; 73 | byte[] newBytes; 74 | 75 | // get the input stream for the current zip entry 76 | try (InputStream stream = file.getInputStream(entry)) { 77 | if (entry.getName().endsWith(".class")) { 78 | // it's a class 79 | 80 | // --------------------- // 81 | // GET CLASS INFORMATION // 82 | // --------------------- // 83 | 84 | // initialize a class node to store class information 85 | ClassNode currentClass = new ClassNode(); 86 | 87 | // make a class reader and give it the class input stream 88 | ClassReader classReader = new ClassReader(stream); 89 | 90 | // read the class information and store it in the class node! 91 | classReader.accept(currentClass, ClassReader.SKIP_CODE); 92 | 93 | if (this.remappingPlugin != null) 94 | this.remappingPlugin.onBeforeRemapClass( 95 | this.mapping.getClassByFromName(currentClass.name)); 96 | 97 | // -------------------- // 98 | // MANIPULATE THE CLASS // 99 | // -------------------- // 100 | ClassNode remappedClass = new ClassNode(); 101 | 102 | MappingProvider remapper = new MappingProvider(this.mapping, remappedClass, this); 103 | 104 | ClassRemapper classRemapper = new ParameterEnhancedRemapper(remapper, remappedClass, this.mapping); 105 | classReader.accept(classRemapper, ClassReader.EXPAND_FRAMES); // must be EXPAND_FRAMES to fully read the class 106 | 107 | // ----------------------- // 108 | // WRITE OUT THE NEW CLASS // 109 | // ----------------------- // 110 | ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); 111 | remappedClass.accept(classWriter); 112 | 113 | // ------------------------ // 114 | // ADD THE CLASS TO THE JAR // 115 | // ------------------------ // 116 | newEntry = new ZipEntry(remappedClass.name + ".class"); 117 | newBytes = classWriter.toByteArray(); 118 | 119 | // done remapping class 120 | if (this.remappingPlugin != null) 121 | this.remappingPlugin.onAfterRemapClass( 122 | this.mapping.getClassByToName(remappedClass.name)); 123 | } else { 124 | // copy the file into the new jar -- it's a resource 125 | 126 | newEntry = entry; 127 | newBytes = Utility.readInputStream(stream); 128 | } 129 | 130 | // write out the new/remapped zip entry 131 | outputStream.putNextEntry(newEntry); 132 | outputStream.write(newBytes); 133 | outputStream.closeEntry(); 134 | } 135 | } 136 | } 137 | } catch (IOException e) { 138 | e.printStackTrace(); 139 | } 140 | 141 | // done remapping the jar 142 | if (this.remappingPlugin != null) this.remappingPlugin.onDoneRemap(); 143 | } 144 | 145 | ClassNode getClassNode(String fromName) { 146 | try { 147 | // initialize a class node to store class information 148 | ClassNode currentClass = new ClassNode(); 149 | 150 | // make a class reader and give it the class input stream 151 | ClassReader classReader = new ClassReader(this.zipFile.getInputStream( 152 | this.zipFile.getEntry(fromName + ".class"))); 153 | 154 | // read the class information and store it in the class node! 155 | classReader.accept(currentClass, ClassReader.SKIP_CODE); 156 | 157 | return currentClass; 158 | } catch (IOException e) { 159 | e.printStackTrace(); 160 | return null; 161 | } 162 | } 163 | } 164 | 165 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /com.pocolifo.jarremapper/src/main/java/com/pocolifo/jarremapper/reader/mcp/McpMappingReader.java: -------------------------------------------------------------------------------- 1 | package com.pocolifo.jarremapper.reader.mcp; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.util.*; 7 | 8 | import com.pocolifo.jarremapper.mapping.ClassMapping; 9 | import com.pocolifo.jarremapper.mapping.FieldMapping; 10 | import com.pocolifo.jarremapper.mapping.JarMapping; 11 | import com.pocolifo.jarremapper.mapping.MethodMapping; 12 | import com.pocolifo.jarremapper.reader.MappingUtility; 13 | import org.objectweb.asm.Type; 14 | 15 | public class McpMappingReader { 16 | private final File srgFile; 17 | private final File excFile; 18 | 19 | private final File methodsCsv; 20 | private final File fieldsCsv; 21 | private final File paramsCsv; 22 | 23 | public final Map classes = new HashMap<>(); 24 | public final Map methods = new HashMap<>(); 25 | public final Map fields = new HashMap<>(); 26 | public final Map params = new HashMap<>(); 27 | 28 | private final Map srgMethods = new HashMap<>(); 29 | 30 | public McpMappingReader(File srgFile, File excFile, File methodsCsv, File fieldsCsv, File paramsCsv) { 31 | this.srgFile = srgFile; 32 | this.excFile = excFile; 33 | 34 | this.methodsCsv = methodsCsv; 35 | this.fieldsCsv = fieldsCsv; 36 | this.paramsCsv = paramsCsv; 37 | } 38 | 39 | public JarMapping read() throws IOException { 40 | this.readSrg(); 41 | 42 | this.srgMethods.putAll(this.methods); 43 | 44 | this.readCsv(this.methodsCsv, this.methods); 45 | this.readCsv(this.fieldsCsv, this.fields); 46 | 47 | // Read the parameters CSV 48 | for (String line : Files.readAllLines(this.paramsCsv.toPath())) { 49 | if (line.contains("searge")) continue; 50 | if (!line.contains(",")) continue; 51 | 52 | String[] split = line.split(","); 53 | 54 | this.params.put(split[0], split[1]); 55 | } 56 | 57 | JarMapping mapping = this.convertToJarMapping(); 58 | 59 | this.readExc(mapping); // for constructor params? 60 | 61 | return mapping; 62 | } 63 | 64 | private void renameParameters(MethodMapping method) { 65 | for (int i = 0; method.parameterNames.size() > i; i++) { 66 | String parameterName = method.parameterNames.get(i); 67 | String newName = this.params.get(parameterName); 68 | 69 | method.parameterNames.set(i, newName == null ? parameterName : newName); 70 | } 71 | } 72 | 73 | private void readCsv(File csvFile, Map map) throws IOException { 74 | Map srgNamedMap = new HashMap<>(); 75 | Map emptyMap = new HashMap<>(); 76 | 77 | for (String line : Files.readAllLines(csvFile.toPath())) { 78 | if (line.contains("searge")) continue; 79 | if (!line.contains(",")) continue; 80 | 81 | String[] split = line.split(","); 82 | 83 | srgNamedMap.put(split[0], split[1]); 84 | } 85 | 86 | for (Map.Entry fromNameSrgName : map.entrySet()) { 87 | String srg = MappingUtility.getNameAfterLastSlash(MappingUtility.getMethodName(fromNameSrgName.getValue())); 88 | 89 | String named = srgNamedMap.get( 90 | MappingUtility.getNameAfterLastSlash(MappingUtility.getMethodName(fromNameSrgName.getValue())) 91 | ); 92 | 93 | if (named == null) named = srg; 94 | 95 | emptyMap.put(fromNameSrgName.getKey(), fromNameSrgName.getValue().replace( 96 | srg, 97 | named 98 | )); 99 | } 100 | 101 | map.clear(); 102 | map.putAll(emptyMap); 103 | } 104 | 105 | private void readExc(JarMapping mapping) throws IOException { 106 | for (String line : Files.readAllLines(this.excFile.toPath())) { 107 | String[] split = line.split("="); 108 | 109 | int beginMethodName = split[0].lastIndexOf('.'); 110 | int endMethodName = split[0].lastIndexOf('('); 111 | 112 | if (beginMethodName > -1 && endMethodName > -1) { 113 | String className = split[0].substring(0, beginMethodName); 114 | String methodName = split[0].substring(beginMethodName + 1, endMethodName); 115 | String methodDescriptor = split[0].substring(endMethodName); 116 | 117 | ClassMapping cls = mapping.getClassByToName(className); 118 | if (cls == null) continue; 119 | 120 | MethodMapping method = cls.getMethodByToName(methodName, methodDescriptor); 121 | 122 | if (method == null) { 123 | method = new MethodMapping(methodName, methodDescriptor, methodName, methodDescriptor, cls); 124 | } 125 | 126 | if (split[1].charAt(0) == '|') { 127 | // param 128 | method.parameterNames.addAll(Arrays.asList(split[1].replaceAll("\\|", "").split(","))); 129 | } else { 130 | // exception 131 | method.exceptions.addAll(Arrays.asList(split[1].replaceAll("\\|", "").split(","))); 132 | } 133 | 134 | this.renameParameters(method); 135 | 136 | cls.methodMappings.add(method); 137 | mapping.classMappings.add(cls); 138 | } 139 | } 140 | } 141 | 142 | private void readSrg() throws IOException { 143 | List classEntries = new ArrayList<>(); 144 | List fieldEntries = new ArrayList<>(); 145 | List methodEntries = new ArrayList<>(); 146 | 147 | // get everything 148 | for (String line : Files.readAllLines(this.srgFile.toPath())) { 149 | String[] fields = line.split(" "); 150 | 151 | switch (fields[0]) { 152 | case "CL:": 153 | classEntries.add(fields); 154 | break; 155 | 156 | case "FD:": 157 | fieldEntries.add(fields); 158 | break; 159 | 160 | case "MD:": 161 | methodEntries.add(fields); 162 | break; 163 | 164 | // PK mappings don't make a difference 165 | } 166 | } 167 | 168 | for (String[] fields : classEntries) { 169 | this.classes.put(fields[1], fields[2]); 170 | } 171 | 172 | for (String[] fields : fieldEntries) { 173 | this.fields.put(fields[1], fields[2]); 174 | } 175 | 176 | for (String[] fields : methodEntries) { 177 | this.methods.put(fields[1] + " " + fields[2], fields[3] + " " + fields[4]); 178 | } 179 | } 180 | 181 | private List inferParameterNames(String srgName, String methodDescriptor) { 182 | if (srgName.matches("func_\\d+_.+")) { 183 | List params = new ArrayList<>(); 184 | 185 | // TODO: Last parameter does not get named sometimes, FIX 186 | // tried Type.getArgumentsAndReturnSizes(methodDescriptor), works better, but not the best 187 | 188 | Type[] arguments = Type.getArgumentTypes(methodDescriptor); 189 | for (int i = 0; arguments.length > i; i++) { 190 | params.add("p_" + srgName.substring(5, 191 | srgName.indexOf('_', 5)) + "_" + i + "_"); 192 | } 193 | 194 | return params; 195 | } 196 | 197 | return Collections.emptyList(); 198 | } 199 | 200 | public JarMapping convertToJarMapping() { 201 | JarMapping mapping = new JarMapping(); 202 | 203 | for (Map.Entry cls : this.classes.entrySet()) { 204 | mapping.classMappings.add(new ClassMapping(cls.getKey(), cls.getValue(), mapping)); 205 | } 206 | 207 | for (Map.Entry md : this.methods.entrySet()) { 208 | String from_cls = MappingUtility.getFromClassName(MappingUtility.getMethodName(md.getKey())); 209 | String from_name = MappingUtility.getNameAfterLastSlash(MappingUtility.getMethodName(md.getKey())); 210 | String from_desc = MappingUtility.getMethodDescriptor(md.getKey()); 211 | 212 | String to_cls = MappingUtility.getFromClassName(MappingUtility.getMethodName(md.getValue())); 213 | String to_name = MappingUtility.getNameAfterLastSlash(MappingUtility.getMethodName(md.getValue())); 214 | String to_desc = MappingUtility.getMethodDescriptor(md.getValue()); 215 | 216 | ClassMapping cls = mapping.getClassByFromName(from_cls); 217 | 218 | MethodMapping method = new MethodMapping(from_name, from_desc, to_name, to_desc, cls); 219 | 220 | method.parameterNames.addAll(this.inferParameterNames( 221 | MappingUtility.getNameAfterLastSlash(MappingUtility.getMethodName(this.srgMethods.get(md.getKey()))), 222 | from_desc)); 223 | 224 | this.renameParameters(method); 225 | 226 | cls.methodMappings.add(method); 227 | } 228 | 229 | for (Map.Entry fd : this.fields.entrySet()) { 230 | String from_cls = MappingUtility.getFromClassName(fd.getKey()); 231 | String from_name = MappingUtility.getNameAfterLastSlash(fd.getKey()); 232 | 233 | String to_cls = MappingUtility.getFromClassName(fd.getValue()); 234 | String to_name = MappingUtility.getNameAfterLastSlash(fd.getValue()); 235 | 236 | ClassMapping cls = mapping.getClassByFromName(from_cls); 237 | cls.fieldMappings.add(new FieldMapping(from_name, to_name, cls)); 238 | } 239 | 240 | return mapping; 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------