Skip to content

Commit

Permalink
Add JAM reader and writer
Browse files Browse the repository at this point in the history
  • Loading branch information
NebelNidas committed Dec 7, 2023
1 parent 7e7e77e commit 1b75a05
Show file tree
Hide file tree
Showing 15 changed files with 458 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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 JAM reader and writer

## [0.5.1] - 2023-11-30
- Improved documentation
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/net/fabricmc/mappingio/MappingReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import net.fabricmc.mappingio.format.enigma.EnigmaDirReader;
import net.fabricmc.mappingio.format.enigma.EnigmaFileReader;
import net.fabricmc.mappingio.format.proguard.ProGuardFileReader;
import net.fabricmc.mappingio.format.srg.JamFileReader;
import net.fabricmc.mappingio.format.srg.SrgFileReader;
import net.fabricmc.mappingio.format.srg.TsrgFileReader;
import net.fabricmc.mappingio.format.tiny.Tiny1FileReader;
Expand Down Expand Up @@ -85,6 +86,8 @@ public static MappingFormat detectFormat(Reader reader) throws IOException {
case "MD:":
case "FD:":
return detectSrgOrXsrg(br);
case "CL ":
return MappingFormat.JAM_FILE;
}

String headerStr = String.valueOf(buffer, 0, pos);
Expand Down Expand Up @@ -261,6 +264,9 @@ public static void read(Reader reader, MappingFormat format, MappingVisitor visi
case XSRG_FILE:
SrgFileReader.read(reader, visitor);
break;
case JAM_FILE:
JamFileReader.read(reader, visitor);
break;
case CSRG_FILE:
case TSRG_FILE:
case TSRG_2_FILE:
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/fabricmc/mappingio/MappingWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import net.fabricmc.mappingio.format.enigma.EnigmaDirWriter;
import net.fabricmc.mappingio.format.enigma.EnigmaFileWriter;
import net.fabricmc.mappingio.format.proguard.ProGuardFileWriter;
import net.fabricmc.mappingio.format.srg.JamFileWriter;
import net.fabricmc.mappingio.format.srg.SrgFileWriter;
import net.fabricmc.mappingio.format.tiny.Tiny1FileWriter;
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter;
Expand Down Expand Up @@ -55,6 +56,7 @@ 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 JAM_FILE: return new JamFileWriter(writer);
case PROGUARD_FILE: return new ProGuardFileWriter(writer);
default: return null;
}
Expand Down
22 changes: 18 additions & 4 deletions src/main/java/net/fabricmc/mappingio/format/MappingFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@
* <td>✔</td>
* <td>src</td>
* <td>✔</td>
* <td></td>
* <td></td>
* <td>lvIdx & srcName</td>
* <td>lvIdx, lvtIdx, startOpIdx & srcName</td>
* <td>✔</td>
* </tr>
* <tr>
* <td>Enigma</td>
* <td>-</td>
* <td>src</td>
* <td>✔</td>
* <td></td>
* <td>lvIdx</td>
* <td>-</td>
* <td>-</td>
* </tr>
Expand All @@ -76,6 +76,15 @@
* <td>-</td>
* </tr>
* <tr>
* <td>JAM</td>
* <td>-</td>
* <td>src</td>
* <td>-</td>
* <td>argPos</td>
* <td>-</td>
* <td>-</td>
* </tr>
* <tr>
* <td>CSRG/TSRG</td>
* <td>-</td>
* <td>-</td>
Expand All @@ -89,7 +98,7 @@
* <td>✔</td>
* <td>src</td>
* <td>-</td>
* <td></td>
* <td>lvIdx & srcName</td>
* <td>-</td>
* <td>-</td>
* </tr>
Expand Down Expand Up @@ -137,6 +146,11 @@ public enum MappingFormat {
*/
XSRG_FILE("XSRG file", "xsrg", false, true, false, false, false),

/**
* The {@code JAM} ("Java Associated Mapping"; formerly {@code SRGX}) mapping format, as specified <a href="https://github.com/caseif/JAM">here</a>.
*/
JAM_FILE("JAM file", "jam", false, true, false, true, false),

/**
* 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>.
*/
Expand Down
171 changes: 171 additions & 0 deletions src/main/java/net/fabricmc/mappingio/format/srg/JamFileReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* 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.Reader;
import java.util.Collections;
import java.util.Set;

import net.fabricmc.mappingio.MappedElementKind;
import net.fabricmc.mappingio.MappingFlag;
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;

/**
* {@linkplain MappingFormat#JAM_FILE JAM file} reader.
*
* <p>Crashes if a second visit pass is requested without
* {@link MappingFlag#NEEDS_MULTIPLE_PASSES} having been passed beforehand.
*/
public final class JamFileReader {
private JamFileReader() {
}

public static void read(Reader reader, MappingVisitor visitor) throws IOException {
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);
}

private static void read(ColumnFileReader reader, String sourceNs, String targetNs, MappingVisitor visitor) throws IOException {
Set<MappingFlag> flags = visitor.getFlags();
MappingVisitor parentVisitor = null;

if (flags.contains(MappingFlag.NEEDS_ELEMENT_UNIQUENESS)) {
parentVisitor = visitor;
visitor = new MemoryMappingTree();
} else if (flags.contains(MappingFlag.NEEDS_MULTIPLE_PASSES)) {
reader.mark();
}

for (;;) {
boolean visitHeader = visitor.visitHeader();

if (visitHeader) {
visitor.visitNamespaces(sourceNs, Collections.singletonList(targetNs));
}

if (visitor.visitContent()) {
String lastClass = null;
boolean visitLastClass = false;

do {
boolean isMethod;
boolean isArg = false;

if (reader.nextCol("CL")) { // class: CL <src> <dst>
String srcName = reader.nextCol();
if (srcName == null || srcName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber());

if (!srcName.equals(lastClass)) {
lastClass = srcName;
visitLastClass = visitor.visitClass(srcName);

if (visitLastClass) {
String dstName = reader.nextCol();
if (dstName == null || dstName.isEmpty()) throw new IOException("missing class-name-b in line "+reader.getLineNumber());

visitor.visitDstName(MappedElementKind.CLASS, 0, dstName);
visitLastClass = visitor.visitElementContent(MappedElementKind.CLASS);
}
}
} else if ((isMethod = reader.nextCol("MD")) || reader.nextCol("FD") // method/field: MD/FD <cls-a> <name-a> <desc-a> <name-b>
|| (isArg = reader.nextCol("MP"))) { // parameter: MP <cls-a> <name-a> <desc-a> <cls-b> <name-b>
String clsSrcClsName = reader.nextCol();
if (clsSrcClsName == null) throw new IOException("missing class-name-a in line "+reader.getLineNumber());

String memberSrcName = reader.nextCol();
if (memberSrcName == null || memberSrcName.isEmpty()) throw new IOException("missing member-name-a in line "+reader.getLineNumber());

String memberSrcDesc = reader.nextCol();
if (memberSrcDesc == null || memberSrcDesc.isEmpty()) throw new IOException("missing member-desc-a in line "+reader.getLineNumber());

String col5 = reader.nextCol();
String col6 = reader.nextCol();
String col7 = reader.nextCol();

int argSrcPos = -1;
String dstName;
String argSrcDesc;

if (!isArg) {
dstName = col5;
} else {
argSrcPos = Integer.parseInt(col5);

if (col7 == null || col7.isEmpty()) {
dstName = col6;
} else {
argSrcDesc = col6;
if (argSrcDesc == null || argSrcDesc.isEmpty()) throw new IOException("missing parameter-desc-a in line "+reader.getLineNumber());

dstName = col7;
}
}

if (dstName == null || dstName.isEmpty()) throw new IOException("missing name-b in line "+reader.getLineNumber());

if (!clsSrcClsName.equals(lastClass)) {
lastClass = clsSrcClsName;
visitLastClass = visitor.visitClass(clsSrcClsName);

if (visitLastClass) {
visitLastClass = visitor.visitElementContent(MappedElementKind.CLASS);
}
}

if (!visitLastClass) continue;
boolean visitMethod = false;

if (isMethod || isArg) {
visitMethod = visitor.visitMethod(memberSrcName, memberSrcDesc);
}

if (visitMethod) {
if (isMethod) {
visitor.visitDstName(MappedElementKind.METHOD, 0, dstName);
visitor.visitElementContent(MappedElementKind.METHOD);
} else {
visitor.visitMethodArg(argSrcPos, -1, null);
visitor.visitDstName(MappedElementKind.METHOD_ARG, 0, dstName);
visitor.visitElementContent(MappedElementKind.METHOD_ARG);
}
} else if (!isMethod && !isArg && visitor.visitField(memberSrcName, memberSrcDesc)) {
visitor.visitDstName(MappedElementKind.FIELD, 0, dstName);
visitor.visitElementContent(MappedElementKind.FIELD);
}
}
} while (reader.nextLine(0));
}

if (visitor.visitEnd()) break;

reader.reset();
}

if (parentVisitor != null) {
((MappingTree) visitor).accept(parentVisitor);
}
}
}
Loading

0 comments on commit 1b75a05

Please sign in to comment.