Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add readers for XSRG and CSRG #55

Merged
merged 3 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 62 additions & 26 deletions src/main/java/net/fabricmc/mappingio/MappingReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,38 +54,72 @@ public static MappingFormat detectFormat(Reader reader) throws IOException {
int pos = 0;
int len;

while (pos < buffer.length
&& (len = reader.read(buffer, pos, buffer.length - pos)) >= 0) {
pos += len;
}
try (BufferedReader br = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader)) {
br.mark(DETECT_HEADER_LEN);

while (pos < buffer.length
&& (len = br.read(buffer, pos, buffer.length - pos)) >= 0) {
pos += len;
}

br.reset();
if (pos < 3) return null;

switch (String.valueOf(buffer, 0, 3)) {
case "v1\t":
return MappingFormat.TINY_FILE;
case "tin":
return MappingFormat.TINY_2_FILE;
case "tsr": // tsrg2 <nsA> <nsB> ..<nsN>
return MappingFormat.TSRG_2_FILE;
case "CLA":
return MappingFormat.ENIGMA_FILE;
case "PK:":
case "CL:":
case "MD:":
case "FD:":
return detectSrgOrXsrg(br);
}

String headerStr = String.valueOf(buffer, 0, pos);

if (headerStr.contains(" -> ")) {
return MappingFormat.PROGUARD_FILE;
} else if (headerStr.contains("\n\t")) {
return MappingFormat.TSRG_FILE;
}

if (pos < 3) return null;

switch (String.valueOf(buffer, 0, 3)) {
case "v1\t":
return MappingFormat.TINY_FILE;
case "tin":
return MappingFormat.TINY_2_FILE;
case "tsr": // tsrg2 <nsA> <nsB> ..<nsN>
return MappingFormat.TSRG_2_FILE;
case "CLA":
return MappingFormat.ENIGMA_FILE;
case "PK:":
case "CL:":
case "MD:":
case "FD:":
return MappingFormat.SRG_FILE;
// TODO: CSRG

return null; // unknown format or corrupted
}
}

private static MappingFormat detectSrgOrXsrg(BufferedReader reader) throws IOException {
String line;

while ((line = reader.readLine()) != null) {
if (line.startsWith("FD:")) {
String[] parts = line.split(" ");

String headerStr = String.valueOf(buffer, 0, pos);
if (parts.length >= 5) {
if (isEmptyOrStartsWithHash(parts[3]) || isEmptyOrStartsWithHash(parts[4])) {
continue;
}

if (headerStr.contains(" -> ")) {
return MappingFormat.PROGUARD_FILE;
} else if (headerStr.contains("\n\t")) {
return MappingFormat.TSRG_FILE;
return MappingFormat.XSRG_FILE;
} else {
break;
}
}
}

return null; // unknown format or corrupted
return MappingFormat.SRG_FILE;
}

private static boolean isEmptyOrStartsWithHash(String string) {
if (string.isEmpty() || string.startsWith("#")) return true;
return false;
}

public static List<String> getNamespaces(Path file) throws IOException {
Expand Down Expand Up @@ -189,8 +223,10 @@ public static void read(Reader reader, MappingFormat format, MappingVisitor visi
EnigmaFileReader.read(reader, visitor);
break;
case SRG_FILE:
case XSRG_FILE:
SrgFileReader.read(reader, visitor);
break;
case CSRG_FILE:
case TSRG_FILE:
case TSRG_2_FILE:
TsrgFileReader.read(reader, visitor);
Expand Down
23 changes: 22 additions & 1 deletion src/main/java/net/fabricmc/mappingio/format/MappingFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,16 @@
* <td>✖</td>
* </tr>
* <tr>
* <td>TSRG</td>
* <td>XSRG</td>
* <td>✖</td>
* <td>✔</td>
* <td>✖</td>
* <td>✖</td>
* <td>✖</td>
* <td>✖</td>
* </tr>
* <tr>
* <td>CSRG/TSRG</td>
* <td>✖</td>
* <td>✖</td>
* <td>✖</td>
Expand Down Expand Up @@ -120,8 +129,20 @@ public enum MappingFormat {
*/
SRG_FILE("SRG file", "srg", false, false, false, false, false),

/**
* The {@code XSRG} ({@code Extended SRG}) mapping format, as specified <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L69-L84">here</a>.
* Same as SRG, but with field descriptors..
*/
XSRG_FILE("XSRG file", "xsrg", false, true, false, false, false),

/**
* The {@code CSRG} ({@code 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),

/**
* The {@code TSRG} ({@code 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),

Expand Down
32 changes: 24 additions & 8 deletions src/main/java/net/fabricmc/mappingio/format/srg/SrgFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import net.fabricmc.mappingio.MappingUtil;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.format.ColumnFileReader;
import net.fabricmc.mappingio.format.MappingFormat;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;

Expand All @@ -44,6 +45,7 @@ public static void read(Reader reader, String sourceNs, String targetNs, Mapping
private static void read(ColumnFileReader reader, String sourceNs, String targetNs, MappingVisitor visitor) throws IOException {
Set<MappingFlag> flags = visitor.getFlags();
MappingVisitor parentVisitor = null;
MappingFormat format = MappingFormat.SRG_FILE;

if (flags.contains(MappingFlag.NEEDS_ELEMENT_UNIQUENESS)) {
parentVisitor = visitor;
Expand Down Expand Up @@ -89,20 +91,33 @@ private static void read(ColumnFileReader reader, String sourceNs, String target
int srcSepPos = src.lastIndexOf('/');
if (srcSepPos <= 0 || srcSepPos == src.length() - 1) throw new IOException("invalid class/name a in line "+reader.getLineNumber());

String[] cols = new String[3];

for (int i = 0; i < 3; i++) {
cols[i] = reader.nextCol();
}

if (!isMethod && cols[1] != null && cols[2] != null) format = MappingFormat.XSRG_FILE;
String srcDesc;
String dstName;
String dstDesc;

if (isMethod) {
srcDesc = reader.nextCol();
if (isMethod || format == MappingFormat.XSRG_FILE) {
srcDesc = cols[0];
if (srcDesc == null || srcDesc.isEmpty()) throw new IOException("missing desc a in line "+reader.getLineNumber());
dstName = cols[1];
dstDesc = cols[2];
if (dstDesc == null || dstDesc.isEmpty()) throw new IOException("missing desc b in line "+reader.getLineNumber());
} else {
srcDesc = null;
dstName = cols[0];
dstDesc = null;
}

String dst = reader.nextCol();
if (dst == null) throw new IOException("missing class/name b in line "+reader.getLineNumber());
if (dstName == null) throw new IOException("missing class/name b in line "+reader.getLineNumber());

int dstSepPos = dst.lastIndexOf('/');
if (dstSepPos <= 0 || dstSepPos == dst.length() - 1) throw new IOException("invalid class/name b in line "+reader.getLineNumber());
int dstSepPos = dstName.lastIndexOf('/');
if (dstSepPos <= 0 || dstSepPos == dstName.length() - 1) throw new IOException("invalid class/name b in line "+reader.getLineNumber());

String srcOwner = src.substring(0, srcSepPos);

Expand All @@ -111,7 +126,7 @@ private static void read(ColumnFileReader reader, String sourceNs, String target
visitLastClass = visitor.visitClass(srcOwner);

if (visitLastClass) {
visitor.visitDstName(MappedElementKind.CLASS, 0, dst.substring(0, dstSepPos));
visitor.visitDstName(MappedElementKind.CLASS, 0, dstName.substring(0, dstSepPos));
visitLastClass = visitor.visitElementContent(MappedElementKind.CLASS);
}
}
Expand All @@ -122,7 +137,8 @@ private static void read(ColumnFileReader reader, String sourceNs, String target
if (isMethod && visitor.visitMethod(srcName, srcDesc)
|| !isMethod && visitor.visitField(srcName, srcDesc)) {
MappedElementKind kind = isMethod ? MappedElementKind.METHOD : MappedElementKind.FIELD;
visitor.visitDstName(kind, 0, dst.substring(dstSepPos + 1));
visitor.visitDstName(kind, 0, dstName.substring(dstSepPos + 1));
visitor.visitDstDesc(kind, 0, dstDesc);
visitor.visitElementContent(kind);
}
}
Expand Down
103 changes: 87 additions & 16 deletions src/main/java/net/fabricmc/mappingio/format/srg/TsrgFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package net.fabricmc.mappingio.format.srg;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
Expand All @@ -28,6 +29,7 @@
import net.fabricmc.mappingio.MappingUtil;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.format.ColumnFileReader;
import net.fabricmc.mappingio.format.MappingFormat;

public final class TsrgFileReader {
private TsrgFileReader() {
Expand Down Expand Up @@ -56,16 +58,32 @@ public static void read(Reader reader, MappingVisitor visitor) throws IOExceptio
read(reader, MappingUtil.NS_SOURCE_FALLBACK, MappingUtil.NS_TARGET_FALLBACK, visitor);
}

public static void read(Reader reader, String sourceNs, String targetNs, MappingVisitor visitor) throws IOException {
read(new ColumnFileReader(reader, ' '), sourceNs, targetNs, visitor);
}
public static void read(Reader r, String sourceNs, String targetNs, MappingVisitor visitor) throws IOException {
ColumnFileReader reader;
CharArrayReader parentReader = null;

if (visitor.getFlags().contains(MappingFlag.NEEDS_MULTIPLE_PASSES)) {
char[] buffer = new char[100_000];
int pos = 0;
int len;

while ((len = r.read(buffer, pos, buffer.length - pos)) >= 0) {
pos += len;
if (pos == buffer.length) buffer = Arrays.copyOf(buffer, buffer.length * 2);
}

private static void read(ColumnFileReader reader, String sourceNs, String targetNs, MappingVisitor visitor) throws IOException {
boolean isTsrg2 = reader.nextCol("tsrg2");
parentReader = new CharArrayReader(buffer, 0, pos);
reader = new ColumnFileReader(parentReader, ' ');
} else {
reader = new ColumnFileReader(r, ' ');
}

MappingFormat format = MappingFormat.TSRG_FILE;
if (reader.nextCol("tsrg2")) format = MappingFormat.TSRG_2_FILE;
String srcNamespace;
List<String> dstNamespaces;

if (isTsrg2) {
if (format == MappingFormat.TSRG_2_FILE) { // tsrg2 magic
srcNamespace = reader.nextCol();
dstNamespaces = new ArrayList<>();
String dstNamespace;
Expand All @@ -81,11 +99,6 @@ private static void read(ColumnFileReader reader, String sourceNs, String target
}

int dstNsCount = dstNamespaces.size();

if (visitor.getFlags().contains(MappingFlag.NEEDS_MULTIPLE_PASSES)) {
reader.mark();
}

List<String> nameTmp = dstNamespaces.size() > 1 ? new ArrayList<>(dstNamespaces.size() - 1) : null;

for (;;) {
Expand All @@ -96,28 +109,84 @@ private static void read(ColumnFileReader reader, String sourceNs, String target
}

if (visitor.visitContent()) {
String lastClass = null;
boolean visitLastClass = false; // Only used for CSRG

do {
if (reader.hasExtraIndents()) continue;
reader.mark();
String line = reader.nextCols(false);
if (line == null && reader.isAtEof()) continue;
reader.reset();
String[] parts = line.split("((?<= )|(?= ))"); // Split on spaces, but keep them

if (format != MappingFormat.TSRG_2_FILE && parts.length >= 4 && !parts[3].startsWith("#")) { // CSRG
format = MappingFormat.CSRG_FILE;
String clsName = parts[0];
if (clsName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber());

if (!clsName.equals(lastClass)) {
lastClass = clsName;
visitLastClass = visitor.visitClass(clsName) && visitor.visitElementContent(MappedElementKind.CLASS);
}

if (!visitLastClass) continue;
String dstName;

if (parts.length >= 6 && !parts[5].startsWith("#")) { // method
dstName = parts.length == 6 ? null : parts[6];

if (dstName == null || !dstName.startsWith("#")) {
if (visitor.visitMethod(parts[2], parts[4])) {
visitor.visitDstName(MappedElementKind.METHOD, 0, dstName);
}

continue;
}
} else if (parts.length >= 4) { // field
dstName = parts.length == 4 ? null : parts[4];

if (dstName == null || !dstName.startsWith("#")) {
if (visitor.visitField(parts[2], null)) {
visitor.visitDstName(MappedElementKind.FIELD, 0, dstName);
}

continue;
}
}

throw new IllegalStateException("invalid CSRG line: "+line);
}

String srcName = reader.nextCol();
if (srcName == null || srcName.endsWith("/")) continue;
if (srcName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber());

if (visitor.visitClass(srcName)) {
readClass(reader, isTsrg2, dstNsCount, nameTmp, visitor);
if (!srcName.equals(lastClass)) {
lastClass = srcName;
visitLastClass = visitor.visitClass(srcName);

if (visitLastClass) {
visitLastClass = readClass(reader, format == MappingFormat.TSRG_2_FILE, dstNsCount, nameTmp, visitor);
}
}
} while (reader.nextLine(0));
}

if (visitor.visitEnd()) break;

reader.reset();
if (parentReader == null) {
throw new IllegalStateException("repeated visitation requested without NEEDS_MULTIPLE_PASSES");
} else {
parentReader.reset();
reader = new ColumnFileReader(parentReader, ' ');
}
}
}

private static void readClass(ColumnFileReader reader, boolean isTsrg2, int dstNsCount, List<String> nameTmp, MappingVisitor visitor) throws IOException {
private static boolean readClass(ColumnFileReader reader, boolean isTsrg2, int dstNsCount, List<String> nameTmp, MappingVisitor visitor) throws IOException {
readDstNames(reader, MappedElementKind.CLASS, 0, dstNsCount, visitor);
if (!visitor.visitElementContent(MappedElementKind.CLASS)) return;
if (!visitor.visitElementContent(MappedElementKind.CLASS)) return false;

while (reader.nextLine(1)) {
if (reader.hasExtraIndents()) continue;
Expand Down Expand Up @@ -176,6 +245,8 @@ private static void readClass(ColumnFileReader reader, boolean isTsrg2, int dstN
if (nameTmp != null) nameTmp.clear();
}
}

return true;
}

private static void readMethod(ColumnFileReader reader, int dstNsCount, MappingVisitor visitor) throws IOException {
Expand Down
Loading