Skip to content

Commit

Permalink
Add CSRG, TSRG and TSRG2 writers (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
NebelNidas authored Mar 7, 2024
1 parent 1cd9184 commit f7ace94
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/fabricmc/mappingio/MappingWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,18 @@ public enum MappingFormat {
/**
* The {@code CSRG} ("Compact SRG", since it saves disk space over SRG) mapping format, as specified <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L196-L207">here</a>.
*/
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 <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L196-L213">here</a>.
* 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 <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L262-L285">here</a>.
*/
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 <a href="https://www.guardsquare.com/manual/tools/retrace">here</a>.
Expand Down
145 changes: 145 additions & 0 deletions src/main/java/net/fabricmc/mappingio/format/srg/CsrgFileWriter.java
Original file line number Diff line number Diff line change
@@ -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<MappingFlag> getFlags() {
return flags;
}

@Override
public void visitNamespaces(String srcNamespace, List<String> 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<MappingFlag> flags = EnumSet.of(MappingFlag.NEEDS_SRC_METHOD_DESC);

private final Writer writer;
private String classSrcName;
private String memberSrcName;
private String methodSrcDesc;
private String dstName;
}
202 changes: 202 additions & 0 deletions src/main/java/net/fabricmc/mappingio/format/srg/TsrgFileWriter.java
Original file line number Diff line number Diff line change
@@ -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<MappingFlag> getFlags() {
return tsrg2 ? tsrg2Flags : tsrgFlags;
}

@Override
public void visitNamespaces(String srcNamespace, List<String> 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<MappingFlag> tsrgFlags = EnumSet.of(MappingFlag.NEEDS_ELEMENT_UNIQUENESS, MappingFlag.NEEDS_SRC_METHOD_DESC);
private static final Set<MappingFlag> 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;
}
Loading

0 comments on commit f7ace94

Please sign in to comment.