diff --git a/CHANGELOG.md b/CHANGELOG.md index bd60d251..60545ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Added CSRG writer +- Added TSRG and TSRG2 writer - Added Recaf Simple reader and writer - Added `MappingFormat#hasWriter` boolean diff --git a/src/main/java/net/fabricmc/mappingio/MappingWriter.java b/src/main/java/net/fabricmc/mappingio/MappingWriter.java index 94832e3d..0e973ee4 100644 --- a/src/main/java/net/fabricmc/mappingio/MappingWriter.java +++ b/src/main/java/net/fabricmc/mappingio/MappingWriter.java @@ -29,7 +29,9 @@ import net.fabricmc.mappingio.format.enigma.EnigmaFileWriter; import net.fabricmc.mappingio.format.proguard.ProGuardFileWriter; import net.fabricmc.mappingio.format.simple.RecafSimpleFileWriter; +import net.fabricmc.mappingio.format.srg.CsrgFileWriter; import net.fabricmc.mappingio.format.srg.SrgFileWriter; +import net.fabricmc.mappingio.format.srg.TsrgFileWriter; import net.fabricmc.mappingio.format.tiny.Tiny1FileWriter; import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter; @@ -56,6 +58,9 @@ static MappingWriter create(Writer writer, MappingFormat format) throws IOExcept case ENIGMA_FILE: return new EnigmaFileWriter(writer); case SRG_FILE: return new SrgFileWriter(writer, false); case XSRG_FILE: return new SrgFileWriter(writer, true); + case CSRG_FILE: return new CsrgFileWriter(writer); + case TSRG_FILE: return new TsrgFileWriter(writer, false); + case TSRG_2_FILE: return new TsrgFileWriter(writer, true); case PROGUARD_FILE: return new ProGuardFileWriter(writer); case RECAF_SIMPLE_FILE: return new RecafSimpleFileWriter(writer); default: return null; diff --git a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java index 5d35cfcc..73ab0a50 100644 --- a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java +++ b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java @@ -151,18 +151,18 @@ public enum MappingFormat { /** * The {@code CSRG} ("Compact SRG", since it saves disk space over SRG) mapping format, as specified here. */ - CSRG_FILE("CSRG file", "csrg", false, false, false, false, false, false), + CSRG_FILE("CSRG file", "csrg", false, false, false, false, false, true), /** * The {@code TSRG} ("Tiny SRG", since it saves disk space over SRG) mapping format, as specified here. * Same as CSRG, but hierarchical instead of flat. */ - TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false, false), + TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false, true), /** * The {@code TSRG v2} mapping format, as specified here. */ - TSRG_2_FILE("TSRG2 file", "tsrg", true, true, false, true, false, false), + TSRG_2_FILE("TSRG2 file", "tsrg", true, true, false, true, false, true), /** * ProGuard's mapping format, as specified here. diff --git a/src/main/java/net/fabricmc/mappingio/format/srg/CsrgFileWriter.java b/src/main/java/net/fabricmc/mappingio/format/srg/CsrgFileWriter.java new file mode 100644 index 00000000..a434d4cf --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/srg/CsrgFileWriter.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio.format.srg; + +import java.io.IOException; +import java.io.Writer; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingFlag; +import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.format.MappingFormat; + +/** + * {@linkplain MappingFormat#CSRG_FILE CSRG file} writer. + */ +public final class CsrgFileWriter implements MappingWriter { + public CsrgFileWriter(Writer writer) { + this.writer = writer; + } + + @Override + public void close() throws IOException { + writer.close(); + } + + @Override + public Set getFlags() { + return flags; + } + + @Override + public void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException { + // not supported, skip + } + + @Override + public boolean visitClass(String srcName) throws IOException { + classSrcName = srcName; + + return true; + } + + @Override + public boolean visitField(String srcName, @Nullable String srcDesc) throws IOException { + memberSrcName = srcName; + + return true; + } + + @Override + public boolean visitMethod(String srcName, @Nullable String srcDesc) throws IOException { + memberSrcName = srcName; + methodSrcDesc = srcDesc; + + return true; + } + + @Override + public boolean visitMethodArg(int argPosition, int lvIndex, @Nullable String srcName) throws IOException { + return false; // not supported, skip + } + + @Override + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName) throws IOException { + return false; // not supported, skip + } + + @Override + public void visitDstName(MappedElementKind targetKind, int namespace, String name) { + if (namespace != 0) return; + + dstName = name; + } + + @Override + public boolean visitElementContent(MappedElementKind targetKind) throws IOException { + if (dstName == null) return false; + + write(classSrcName); + + if (targetKind != MappedElementKind.CLASS) { + writeSpace(); + write(memberSrcName); + + if (targetKind == MappedElementKind.METHOD) { + writeSpace(); + write(methodSrcDesc); + } + + memberSrcName = methodSrcDesc = null; + } + + writeSpace(); + write(dstName); + writeLn(); + + dstName = null; + + return targetKind == MappedElementKind.CLASS; // only members are supported, skip anything but class contents + } + + @Override + public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + // not supported, skip + } + + private void write(String str) throws IOException { + writer.write(str); + } + + private void writeSpace() throws IOException { + writer.write(' '); + } + + private void writeLn() throws IOException { + writer.write('\n'); + } + + private static final Set flags = EnumSet.of(MappingFlag.NEEDS_SRC_METHOD_DESC); + + private final Writer writer; + private String classSrcName; + private String memberSrcName; + private String methodSrcDesc; + private String dstName; +} diff --git a/src/main/java/net/fabricmc/mappingio/format/srg/TsrgFileWriter.java b/src/main/java/net/fabricmc/mappingio/format/srg/TsrgFileWriter.java new file mode 100644 index 00000000..e1726e73 --- /dev/null +++ b/src/main/java/net/fabricmc/mappingio/format/srg/TsrgFileWriter.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.mappingio.format.srg; + +import java.io.IOException; +import java.io.Writer; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingFlag; +import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.format.MappingFormat; + +/** + * {@linkplain MappingFormat#TSRG_FILE TSRG file} and + * {@linkplain MappingFormat#TSRG_2_FILE TSRG2 file} writer. + */ +public final class TsrgFileWriter implements MappingWriter { + public TsrgFileWriter(Writer writer, boolean tsrg2) { + this.writer = writer; + this.tsrg2 = tsrg2; + } + + @Override + public void close() throws IOException { + writer.close(); + } + + @Override + public Set getFlags() { + return tsrg2 ? tsrg2Flags : tsrgFlags; + } + + @Override + public void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException { + dstNames = new String[dstNamespaces.size()]; + + if (tsrg2) { + write("tsrg2 "); + write(srcNamespace); + + for (String dstNamespace : dstNamespaces) { + writeSpace(); + write(dstNamespace); + } + + writeLn(); + } + } + + @Override + public void visitMetadata(String key, @Nullable String value) throws IOException { + // TODO: Support the static method marker once https://github.com/FabricMC/mapping-io/pull/41 is merged + } + + @Override + public boolean visitClass(String srcName) throws IOException { + this.srcName = srcName; + + return true; + } + + @Override + public boolean visitField(String srcName, @Nullable String srcDesc) throws IOException { + this.srcName = srcName; + this.srcDesc = srcDesc; + + return true; + } + + @Override + public boolean visitMethod(String srcName, @Nullable String srcDesc) throws IOException { + this.srcName = srcName; + this.srcDesc = srcDesc; + + return true; + } + + @Override + public boolean visitMethodArg(int argPosition, int lvIndex, @Nullable String srcName) throws IOException { + if (tsrg2) { + this.srcName = srcName; + this.lvIndex = lvIndex; + return true; + } + + return false; + } + + @Override + public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName) throws IOException { + return false; // not supported, skip + } + + @Override + public void visitDstName(MappedElementKind targetKind, int namespace, String name) { + if (!tsrg2 && namespace != 0) return; + + dstNames[namespace] = name; + } + + @Override + public boolean visitElementContent(MappedElementKind targetKind) throws IOException { + switch (targetKind) { + case CLASS: + break; + case FIELD: + case METHOD: + writeTab(); + break; + case METHOD_ARG: + assert tsrg2; + writeTab(); + writeTab(); + write(Integer.toString(lvIndex)); + writeSpace(); + case METHOD_VAR: + assert tsrg2; + break; + } + + write(srcName); + + if (targetKind == MappedElementKind.METHOD + || (targetKind == MappedElementKind.FIELD && tsrg2)) { + writeSpace(); + write(srcDesc); + } + + int dstNsCount = tsrg2 ? dstNames.length : 1; + + for (int i = 0; i < dstNsCount; i++) { + String dstName = dstNames[i]; + writeSpace(); + write(dstName != null ? dstName : srcName); + } + + writeLn(); + + srcName = srcDesc = null; + Arrays.fill(dstNames, null); + lvIndex = -1; + + return targetKind == MappedElementKind.CLASS + || (tsrg2 && targetKind == MappedElementKind.METHOD); + } + + @Override + public void visitComment(MappedElementKind targetKind, String comment) throws IOException { + // not supported, skip + } + + private void write(String str) throws IOException { + writer.write(str); + } + + private void writeTab() throws IOException { + writer.write('\t'); + } + + private void writeSpace() throws IOException { + writer.write(' '); + } + + private void writeLn() throws IOException { + writer.write('\n'); + } + + private static final Set tsrgFlags = EnumSet.of(MappingFlag.NEEDS_ELEMENT_UNIQUENESS, MappingFlag.NEEDS_SRC_METHOD_DESC); + private static final Set tsrg2Flags; + + static { + tsrg2Flags = EnumSet.copyOf(tsrgFlags); + tsrg2Flags.add(MappingFlag.NEEDS_SRC_FIELD_DESC); + } + + private final Writer writer; + private final boolean tsrg2; + private String srcName; + private String srcDesc; + private String[] dstNames; + private int lvIndex = -1; +} diff --git a/src/test/java/net/fabricmc/mappingio/write/WriteTest.java b/src/test/java/net/fabricmc/mappingio/write/WriteTest.java index dc8083f6..425101c6 100644 --- a/src/test/java/net/fabricmc/mappingio/write/WriteTest.java +++ b/src/test/java/net/fabricmc/mappingio/write/WriteTest.java @@ -73,6 +73,21 @@ public void xsrgFile() throws Exception { check(MappingFormat.XSRG_FILE); } + @Test + public void csrgFile() throws Exception { + check(MappingFormat.CSRG_FILE); + } + + @Test + public void tsrgFile() throws Exception { + check(MappingFormat.TSRG_FILE); + } + + @Test + public void tsrg2File() throws Exception { + check(MappingFormat.TSRG_2_FILE); + } + @Test public void proguardFile() throws Exception { check(MappingFormat.PROGUARD_FILE);