diff --git a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java
index 056020ed..da650649 100644
--- a/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java
+++ b/src/main/java/net/fabricmc/mappingio/FlatMappingVisitor.java
@@ -57,16 +57,23 @@ default boolean visitContent() throws IOException {
}
boolean visitClass(String srcName, String[] dstNames) throws IOException;
+ void visitClassMetadata(String srcName, String[] dstNames, String propertyKey, String[] propertyValues) throws IOException;
void visitClassComment(String srcName, String[] dstNames, String comment) throws IOException;
boolean visitField(String srcClsName, String srcName, String srcDesc,
String[] dstClsNames, String[] dstNames, String[] dstDescs) throws IOException;
+ void visitFieldMetadata(String srcClsName, String srcName, String srcDesc,
+ String[] dstClsNames, String[] dstNames, String[] dstDescs,
+ String propertyKey, String[] propertyValues) throws IOException;
void visitFieldComment(String srcClsName, String srcName, String srcDesc,
String[] dstClsNames, String[] dstNames, String[] dstDescs,
String comment) throws IOException;
boolean visitMethod(String srcClsName, String srcName, String srcDesc,
String[] dstClsNames, String[] dstNames, String[] dstDescs) throws IOException;
+ void visitMethodMetadata(String srcClsName, String srcName, String srcDesc,
+ String[] dstClsNames, String[] dstNames, String[] dstDescs,
+ String propertyKey, String[] propertyValues) throws IOException;
void visitMethodComment(String srcClsName, String srcName, String srcDesc,
String[] dstClsNames, String[] dstNames, String[] dstDescs,
String comment) throws IOException;
@@ -74,6 +81,10 @@ void visitMethodComment(String srcClsName, String srcName, String srcDesc,
boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc,
int argPosition, int lvIndex, String srcArgName,
String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames) throws IOException;
+ void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int argPosition, int lvIndex, String srcArgName,
+ String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames,
+ String propertyKey, String[] propertyValues) throws IOException;
void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int argPosition, int lvIndex, String srcArgName,
String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames,
@@ -82,6 +93,10 @@ void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMe
boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames) throws IOException;
+ void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
+ String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames,
+ String propertyKey, String[] propertyValues) throws IOException;
void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames,
@@ -135,37 +150,53 @@ default boolean visitMethodVar(String srcClsName, String srcMethodName, String s
// convenience / potentially higher efficiency visit methods for only one dst name
+ // Class
default boolean visitClass(String srcName, String dstName) throws IOException {
return visitClass(srcName, toArray(dstName));
}
-
+ default void visitClassMetadata(String srcName, String propertyKey, String[] propertyValues) throws IOException {
+ visitClassMetadata(srcName, (String) null, propertyKey, propertyValues);
+ }
+ default void visitClassMetadata(String srcName, String dstName, String propertyKey, String[] propertyValues) throws IOException {
+ visitClassMetadata(srcName, toArray(dstName), propertyKey, propertyValues);
+ }
default void visitClassComment(String srcName, String comment) throws IOException {
visitClassComment(srcName, (String) null, comment);
}
-
default void visitClassComment(String srcName, String dstName, String comment) throws IOException {
visitClassComment(srcName, toArray(dstName), comment);
}
+ // Field
default boolean visitField(String srcClsName, String srcName, String srcDesc,
String dstName) throws IOException {
return visitField(srcClsName, srcName, srcDesc,
null, dstName, null);
}
-
default boolean visitField(String srcClsName, String srcName, String srcDesc,
String dstClsName, String dstName, String dstDesc) throws IOException {
return visitField(srcClsName, srcName, srcDesc,
toArray(dstClsName), toArray(dstName), toArray(dstDesc));
}
-
+ default void visitFieldMetadata(String srcClsName, String srcName, String srcDesc,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitFieldMetadata(srcClsName, srcName, srcDesc,
+ (String) null, null, null,
+ propertyKey, propertyValues);
+ }
+ default void visitFieldMetadata(String srcClsName, String srcName, String srcDesc,
+ String dstClsName, String dstName, String dstDesc,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitFieldMetadata(srcClsName, srcName, srcDesc,
+ toArray(dstClsName), toArray(dstName), toArray(dstDesc),
+ propertyKey, propertyValues);
+ }
default void visitFieldComment(String srcClsName, String srcName, String srcDesc,
String comment) throws IOException {
visitFieldComment(srcClsName, srcName, srcDesc,
(String) null, null, null,
comment);
}
-
default void visitFieldComment(String srcClsName, String srcName, String srcDesc,
String dstClsName, String dstName, String dstDesc,
String comment) throws IOException {
@@ -174,25 +205,36 @@ default void visitFieldComment(String srcClsName, String srcName, String srcDesc
comment);
}
+ // Method
default boolean visitMethod(String srcClsName, String srcName, String srcDesc,
String dstName) throws IOException {
return visitMethod(srcClsName, srcName, srcDesc,
null, dstName, null);
}
-
default boolean visitMethod(String srcClsName, String srcName, String srcDesc,
String dstClsName, String dstName, String dstDesc) throws IOException {
return visitMethod(srcClsName, srcName, srcDesc,
toArray(dstClsName), toArray(dstName), toArray(dstDesc));
}
-
+ default void visitMethodMetadata(String srcClsName, String srcName, String srcDesc,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitMethodMetadata(srcClsName, srcName, srcDesc,
+ (String) null, null, null,
+ propertyKey, propertyValues);
+ }
+ default void visitMethodMetadata(String srcClsName, String srcName, String srcDesc,
+ String dstClsName, String dstName, String dstDesc,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitMethodMetadata(srcClsName, srcName, srcDesc,
+ toArray(dstClsName), toArray(dstName), toArray(dstDesc),
+ propertyKey, propertyValues);
+ }
default void visitMethodComment(String srcClsName, String srcName, String srcDesc,
String comment) throws IOException {
visitMethodComment(srcClsName, srcName, srcDesc,
(String) null, null, null,
comment);
}
-
default void visitMethodComment(String srcClsName, String srcName, String srcDesc,
String dstClsName, String dstName, String dstDesc,
String comment) throws IOException {
@@ -201,6 +243,7 @@ default void visitMethodComment(String srcClsName, String srcName, String srcDes
comment);
}
+ // Method Arg
default boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc,
int argPosition, int lvIndex, String srcArgName,
String dstArgName) throws IOException {
@@ -208,7 +251,6 @@ default boolean visitMethodArg(String srcClsName, String srcMethodName, String s
argPosition, lvIndex, srcArgName,
null, null, null, dstArgName);
}
-
default boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc,
int argPosition, int lvIndex, String srcArgName,
String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName) throws IOException {
@@ -216,7 +258,22 @@ default boolean visitMethodArg(String srcClsName, String srcMethodName, String s
argPosition, lvIndex, srcArgName,
toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstArgName));
}
-
+ default void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int argPosition, int lvIndex, String srcArgName,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitMethodArgMetadata(srcClsName, srcMethodName, srcMethodDesc,
+ argPosition, lvIndex, srcArgName,
+ (String) null, null, null, null,
+ propertyKey, propertyValues);
+ }
+ default void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int argPosition, int lvIndex, String srcArgName,
+ String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitMethodArgMetadata(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName,
+ toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstArgName),
+ propertyKey, propertyValues);
+ }
default void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int argPosition, int lvIndex, String srcArgName,
String comment) throws IOException {
@@ -225,7 +282,6 @@ default void visitMethodArgComment(String srcClsName, String srcMethodName, Stri
(String) null, null, null, null,
comment);
}
-
default void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int argPosition, int lvIndex, String srcArgName,
String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName,
@@ -235,6 +291,7 @@ default void visitMethodArgComment(String srcClsName, String srcMethodName, Stri
comment);
}
+ // Method Var
default boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
String dstVarName) throws IOException {
@@ -242,7 +299,6 @@ default boolean visitMethodVar(String srcClsName, String srcMethodName, String s
lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName,
null, null, null, dstVarName);
}
-
default boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName) throws IOException {
@@ -250,7 +306,23 @@ default boolean visitMethodVar(String srcClsName, String srcMethodName, String s
lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName,
toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstVarName));
}
-
+ default void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitMethodVarMetadata(srcClsName, srcMethodName, srcMethodDesc,
+ lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName,
+ (String) null, null, null, null,
+ propertyKey, propertyValues);
+ }
+ default void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
+ String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName,
+ String propertyKey, String[] propertyValues) throws IOException {
+ visitMethodVarMetadata(srcClsName, srcMethodName, srcMethodDesc,
+ lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName,
+ toArray(dstClsName), toArray(dstMethodName), toArray(dstMethodDesc), toArray(dstVarName),
+ propertyKey, propertyValues);
+ }
default void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
String comment) throws IOException {
@@ -259,7 +331,6 @@ default void visitMethodVarComment(String srcClsName, String srcMethodName, Stri
(String) null, null, null, null,
comment);
}
-
default void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName,
diff --git a/src/main/java/net/fabricmc/mappingio/MappingReader.java b/src/main/java/net/fabricmc/mappingio/MappingReader.java
index 65dae0b4..fd6e1b1d 100644
--- a/src/main/java/net/fabricmc/mappingio/MappingReader.java
+++ b/src/main/java/net/fabricmc/mappingio/MappingReader.java
@@ -29,6 +29,7 @@
import net.fabricmc.mappingio.format.MappingFormat;
import net.fabricmc.mappingio.format.enigma.EnigmaDirReader;
import net.fabricmc.mappingio.format.enigma.EnigmaFileReader;
+import net.fabricmc.mappingio.format.match.MatchFileReader;
import net.fabricmc.mappingio.format.proguard.ProGuardFileReader;
import net.fabricmc.mappingio.format.srg.SrgFileReader;
import net.fabricmc.mappingio.format.tiny.Tiny1FileReader;
@@ -75,6 +76,8 @@ public static MappingFormat detectFormat(Reader reader) throws IOException {
case "MD:":
case "FD:":
return MappingFormat.SRG_FILE;
+ case "Mat":
+ return MappingFormat.MATCH_FILE;
}
String headerStr = String.valueOf(buffer, 0, pos);
@@ -200,6 +203,9 @@ public static void read(Reader reader, MappingFormat format, MappingVisitor visi
case PROGUARD_FILE:
ProGuardFileReader.read(reader, visitor);
break;
+ case MATCH_FILE:
+ MatchFileReader.read(reader, visitor);
+ break;
default:
throw new IllegalStateException();
}
diff --git a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java
index 5c2455ce..f14752ee 100644
--- a/src/main/java/net/fabricmc/mappingio/MappingVisitor.java
+++ b/src/main/java/net/fabricmc/mappingio/MappingVisitor.java
@@ -27,11 +27,11 @@
*
- overall: header -> content -> End -> overall
*
- header: Header -> Namespaces [-> Metadata]*
*
- content: Content [-> class|Metadata]*
- *
- class: Class [-> DstName]* -> ElementContent [-> field|method|Comment]*
- *
- field: Field [-> DstName|DstDesc]* -> ElementContent [-> Comment]
- *
- method: Method [-> DstName|DstDesc]* -> ElementContent [-> arg|var|Comment]*
- *
- arg: Arg [-> DstName]* -> ElementContent [-> Comment]
- *
- var: Var [-> DstName]* -> ElementContent [-> Comment]
+ *
- class: Class [-> DstName]* -> ElementContent [-> ElementMetadata|field|method|Comment]*
+ *
- field: Field [-> DstName|DstDesc]* -> ElementContent [-> ElementMetadata|Comment]*
+ *
- method: Method [-> DstName|DstDesc]* -> ElementContent [-> ElementMetadata|arg|var|Comment]*
+ *
- arg: Arg [-> DstName]* -> ElementContent [-> ElementMetadata|Comment]*
+ *
- var: Var [-> DstName]* -> ElementContent [-> ElementMetadata|Comment]*
*
*
* The elements with a skip-return (Header/Content/Class/Field/Method/Arg/Var/ElementContent) abort processing the
@@ -118,6 +118,11 @@ default boolean visitElementContent(MappedElementKind targetKind) throws IOExcep
return true;
}
+ /**
+ * Metadata for the specified element (last content-visited or any parent).
+ */
+ default void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException { }
+
/**
* Comment for the specified element (last content-visited or any parent).
*
diff --git a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java
index 34da310f..0a681934 100644
--- a/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java
+++ b/src/main/java/net/fabricmc/mappingio/adapter/FlatAsRegularMappingVisitor.java
@@ -18,7 +18,9 @@
import java.io.IOException;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import net.fabricmc.mappingio.FlatMappingVisitor;
@@ -75,7 +77,8 @@ public boolean visitContent() throws IOException {
}
@Override
- public boolean visitClass(String srcName) {
+ public boolean visitClass(String srcName) throws IOException {
+ relayPendingElementMetadata();
this.srcClsName = srcName;
Arrays.fill(dstNames, null);
@@ -85,7 +88,8 @@ public boolean visitClass(String srcName) {
}
@Override
- public boolean visitField(String srcName, String srcDesc) {
+ public boolean visitField(String srcName, String srcDesc) throws IOException {
+ relayPendingElementMetadata();
this.srcMemberName = srcName;
this.srcMemberDesc = srcDesc;
@@ -97,7 +101,8 @@ public boolean visitField(String srcName, String srcDesc) {
}
@Override
- public boolean visitMethod(String srcName, String srcDesc) {
+ public boolean visitMethod(String srcName, String srcDesc) throws IOException {
+ relayPendingElementMetadata();
this.srcMemberName = srcName;
this.srcMemberDesc = srcDesc;
@@ -109,7 +114,8 @@ public boolean visitMethod(String srcName, String srcDesc) {
}
@Override
- public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) {
+ public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) throws IOException {
+ relayPendingElementMetadata();
this.srcMemberSubName = srcName;
this.argIdx = argPosition;
this.lvIndex = lvIndex;
@@ -120,7 +126,8 @@ public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) {
}
@Override
- public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) {
+ public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) throws IOException {
+ relayPendingElementMetadata();
this.srcMemberSubName = srcName;
this.argIdx = lvtRowIndex;
this.lvIndex = lvIndex;
@@ -134,6 +141,7 @@ public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int
@Override
public boolean visitEnd() throws IOException {
+ relayPendingElementMetadata();
return next.visitEnd();
}
@@ -149,6 +157,7 @@ public void visitDstDesc(MappedElementKind targetKind, int namespace, String des
@Override
public boolean visitElementContent(MappedElementKind targetKind) throws IOException {
+ currentElementKind = targetKind;
boolean relay;
switch (targetKind) {
@@ -181,8 +190,17 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept
return relay;
}
+ @Override
+ public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) {
+ String[] values = elementMetadata.getOrDefault(key, new String[dstNames.length + 1]);
+ values[namespace] = value;
+ elementMetadata.put(key, values);
+ }
+
@Override
public void visitComment(MappedElementKind targetKind, String comment) throws IOException {
+ relayPendingElementMetadata();
+
switch (targetKind) {
case CLASS:
next.visitClassComment(srcClsName, dstClassNames, comment);
@@ -206,8 +224,46 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO
}
}
+ private void relayPendingElementMetadata() throws IOException {
+ if (elementMetadata.isEmpty()) return;
+
+ for (Map.Entry entry : elementMetadata.entrySet()) {
+ String key = entry.getKey();
+ String[] values = entry.getValue();
+
+ switch (currentElementKind) {
+ case CLASS:
+ next.visitClassMetadata(srcClsName, dstClassNames, key, values);
+ break;
+ case FIELD:
+ next.visitFieldMetadata(srcClsName, srcMemberName, srcMemberDesc,
+ dstClassNames, dstMemberNames, dstMemberDescs, key, values);
+ break;
+ case METHOD:
+ next.visitMethodMetadata(srcClsName, srcMemberName, srcMemberDesc,
+ dstClassNames, dstMemberNames, dstMemberDescs, key, values);
+ break;
+ case METHOD_ARG:
+ next.visitMethodArgMetadata(srcClsName, srcMemberName, srcMemberDesc, argIdx, lvIndex, srcMemberSubName,
+ dstClassNames, dstMemberNames, dstMemberDescs, dstNames, key, values);
+ break;
+ case METHOD_VAR:
+ next.visitMethodVarMetadata(srcClsName, srcMemberName, srcMemberDesc, argIdx, lvIndex, startOpIdx, endOpIdx, srcMemberSubName,
+ dstClassNames, dstMemberNames, dstMemberDescs, dstNames, key, values);
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ elementMetadata.clear();
+ currentElementKind = null;
+ }
+
private final FlatMappingVisitor next;
+ private final LinkedHashMap elementMetadata = new LinkedHashMap<>();
+ private MappedElementKind currentElementKind;
private String srcClsName;
private String srcMemberName;
private String srcMemberDesc;
diff --git a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java
index 71d9574f..b06b617c 100644
--- a/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java
+++ b/src/main/java/net/fabricmc/mappingio/adapter/ForwardingMappingVisitor.java
@@ -107,6 +107,11 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept
return next.visitElementContent(targetKind);
}
+ @Override
+ public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException {
+ next.visitElementMetadata(targetKind, key, namespace, value);
+ }
+
@Override
public void visitComment(MappedElementKind targetKind, String comment) throws IOException {
next.visitComment(targetKind, comment);
diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java
index b0232d25..1086828a 100644
--- a/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java
+++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingDstNsReorder.java
@@ -66,6 +66,15 @@ public void visitDstDesc(MappedElementKind targetKind, int namespace, String des
}
}
+ @Override
+ public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException {
+ if (namespace >= 0) namespace = nsMap[namespace];
+
+ if (namespace >= 0) {
+ super.visitElementMetadata(targetKind, key, namespace, value);
+ }
+ }
+
private final List newDstNs;
private int[] nsMap;
}
diff --git a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java
index de52a900..91da8920 100644
--- a/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java
+++ b/src/main/java/net/fabricmc/mappingio/adapter/MappingSourceNsSwitch.java
@@ -300,6 +300,17 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept
return relay;
}
+ @Override
+ public void visitElementMetadata(MappedElementKind targetKind, String key, int namespace, String value) throws IOException {
+ if (namespace == newSourceNs) {
+ namespace = -1;
+ } else if (namespace == -1) {
+ namespace = newSourceNs;
+ }
+
+ next.visitElementMetadata(targetKind, key, namespace, value);
+ }
+
private final String newSourceNsName;
private final boolean dropMissingNewSrcName;
diff --git a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java
index 2c6408e8..153b3dc1 100644
--- a/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java
+++ b/src/main/java/net/fabricmc/mappingio/adapter/RegularAsFlatMappingVisitor.java
@@ -89,6 +89,18 @@ private boolean visitClass(String srcName, String[] dstNames, String dstName) th
return relayLastClass;
}
+ @Override
+ public void visitClassMetadata(String srcName, String[] dstNames, String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitClass(srcName, dstNames, null)) return;
+ visitElementMetadata(MappedElementKind.CLASS, propertyKey, propertyValues);
+ }
+
+ @Override
+ public void visitClassMetadata(String srcName, String dstName, String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitClass(srcName, null, dstName)) return;
+ visitElementMetadata(MappedElementKind.CLASS, propertyKey, propertyValues);
+ }
+
@Override
public void visitClassComment(String srcName, String[] dstNames, String comment) throws IOException {
if (!visitClass(srcName, dstNames, null)) return;
@@ -128,6 +140,22 @@ private boolean visitField(String srcClsName, String srcName, String srcDesc,
return relayLastMember;
}
+ @Override
+ public void visitFieldMetadata(String srcClsName, String srcName, String srcDesc,
+ String[] dstClsNames, String[] dstNames, String[] dstDescs,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitField(srcClsName, srcName, srcDesc, dstClsNames, dstNames, dstDescs, null, null, null)) return;
+ visitElementMetadata(MappedElementKind.FIELD, propertyKey, propertyValues);
+ }
+
+ @Override
+ public void visitFieldMetadata(String srcClsName, String srcName, String srcDesc,
+ String dstClsName, String dstName, String dstDesc,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitField(srcClsName, srcName, srcDesc, null, null, null, dstClsName, dstName, dstDesc)) return;
+ visitElementMetadata(MappedElementKind.FIELD, propertyKey, propertyValues);
+ }
+
@Override
public void visitFieldComment(String srcClsName, String srcName, String srcDesc,
String[] dstClsNames, String[] dstNames, String[] dstDescs,
@@ -171,6 +199,22 @@ private boolean visitMethod(String srcClsName, String srcName, String srcDesc,
return relayLastMember;
}
+ @Override
+ public void visitMethodMetadata(String srcClsName, String srcName, String srcDesc,
+ String[] dstClsNames, String[] dstNames, String[] dstDescs,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitMethod(srcClsName, srcName, srcDesc, dstClsNames, dstNames, dstDescs, null, null, null)) return;
+ visitElementMetadata(MappedElementKind.METHOD, propertyKey, propertyValues);
+ }
+
+ @Override
+ public void visitMethodMetadata(String srcClsName, String srcName, String srcDesc,
+ String dstClsName, String dstName, String dstDesc,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitMethod(srcClsName, srcName, srcDesc, null, null, null, dstClsName, dstName, dstDesc)) return;
+ visitElementMetadata(MappedElementKind.METHOD, propertyKey, propertyValues);
+ }
+
@Override
public void visitMethodComment(String srcClsName, String srcName, String srcDesc,
String[] dstClsNames, String[] dstNames, String[] dstDescs,
@@ -219,6 +263,30 @@ private boolean visitMethodArg(String srcClsName, String srcMethodName, String s
return relayLastMethodSub;
}
+ @Override
+ public void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName,
+ String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitMethodArg(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName,
+ dstClsNames, dstMethodNames, dstMethodDescs, dstArgNames, null, null, null, null)) {
+ return;
+ }
+
+ visitElementMetadata(MappedElementKind.METHOD_ARG, propertyKey, propertyValues);
+ }
+
+ @Override
+ public void visitMethodArgMetadata(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition,
+ int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitMethodArg(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName,
+ null, null, null, null, dstClsName, dstMethodName, dstMethodDesc, dstArgName)) {
+ return;
+ }
+
+ visitElementMetadata(MappedElementKind.METHOD_ARG, propertyKey, propertyValues);
+ }
+
@Override
public void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName,
String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames,
@@ -233,8 +301,8 @@ public void visitMethodArgComment(String srcClsName, String srcMethodName, Strin
@Override
public void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition,
- int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc,
- String dstArgName, String comment) throws IOException {
+ int lvIndex, String srcArgName, String dstClsName, String dstMethodName, String dstMethodDesc, String dstArgName,
+ String comment) throws IOException {
if (!visitMethodArg(srcClsName, srcMethodName, srcMethodDesc, argPosition, lvIndex, srcArgName,
null, null, null, null, dstClsName, dstMethodName, dstMethodDesc, dstArgName)) {
return;
@@ -274,6 +342,32 @@ private boolean visitMethodVar(String srcClsName, String srcMethodName, String s
return relayLastMethodSub;
}
+ @Override
+ public void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
+ String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitMethodVar(srcClsName, srcMethodName, srcMethodDesc, lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName,
+ dstClsNames, dstMethodNames, dstMethodDescs, dstVarNames, null, null, null, null)) {
+ return;
+ }
+
+ visitElementMetadata(MappedElementKind.METHOD_VAR, propertyKey, propertyValues);
+ }
+
+ @Override
+ public void visitMethodVarMetadata(String srcClsName, String srcMethodName, String srcMethodDesc,
+ int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
+ String dstClsName, String dstMethodName, String dstMethodDesc, String dstVarName,
+ String propertyKey, String[] propertyValues) throws IOException {
+ if (!visitMethodVar(srcClsName, srcMethodName, srcMethodDesc, lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcVarName,
+ null, null, null, null, dstClsName, dstMethodName, dstMethodDesc, dstVarName)) {
+ return;
+ }
+
+ visitElementMetadata(MappedElementKind.METHOD_VAR, propertyKey, propertyValues);
+ }
+
@Override
public void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc,
int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcVarName,
@@ -344,6 +438,15 @@ private boolean visitDstNamesDescs(MappedElementKind targetKind, String[] dstNam
return next.visitElementContent(targetKind);
}
+ private void visitElementMetadata(MappedElementKind targetKind, String key, String[] values) throws IOException {
+ if (values != null) {
+ for (int i = -1; i < values.length; i++) {
+ String value = values[i];
+ if (value != null) next.visitElementMetadata(targetKind, key, i, value);
+ }
+ }
+ }
+
private final MappingVisitor next;
private boolean relayDstFieldDescs;
diff --git a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java
index ac7bfcf6..cb318c4c 100644
--- a/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java
+++ b/src/main/java/net/fabricmc/mappingio/format/MappingFormat.java
@@ -17,19 +17,21 @@
package net.fabricmc.mappingio.format;
public enum MappingFormat {
- TINY_FILE("Tiny file", "tiny", true, true, false, false, false),
- TINY_2_FILE("Tiny v2 file", "tiny", true, true, true, true, true),
- ENIGMA_FILE("Enigma file", "mappings", false, true, true, true, false),
- ENIGMA_DIR("Enigma directory", null, false, true, true, true, false),
- MCP_DIR("MCP directory", null, false, false, true, true, false),
- SRG_FILE("SRG file", "srg", false, false, false, false, false),
- TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false),
- TSRG_2_FILE("TSRG2 file", "tsrg", true, false, false, true, false),
- PROGUARD_FILE("ProGuard file", "map", false, true, false, false, false);
+ TINY_FILE("Tiny file", "tiny", true, true, false, false, false, MetadataSupport.ARBITRARY, MetadataSupport.NONE),
+ TINY_2_FILE("Tiny v2 file", "tiny", true, true, true, true, true, MetadataSupport.ARBITRARY, MetadataSupport.NONE),
+ ENIGMA_FILE("Enigma file", "mappings", false, true, true, true, false, MetadataSupport.NONE, MetadataSupport.HARDCODED),
+ ENIGMA_DIR("Enigma directory", null, false, true, true, true, false, MetadataSupport.NONE, MetadataSupport.HARDCODED),
+ MCP_DIR("MCP directory", null, false, false, true, true, false, MetadataSupport.NONE, MetadataSupport.NONE),
+ SRG_FILE("SRG file", "srg", false, false, false, false, false, MetadataSupport.NONE, MetadataSupport.NONE),
+ TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false, MetadataSupport.NONE, MetadataSupport.NONE),
+ TSRG_2_FILE("TSRG2 file", "tsrg", true, false, false, true, false, MetadataSupport.NONE, MetadataSupport.HARDCODED),
+ PROGUARD_FILE("ProGuard file", "map", false, true, false, false, false, MetadataSupport.NONE, MetadataSupport.HARDCODED),
+ MATCH_FILE("Match file", "match", false, true, false, true, true, MetadataSupport.HARDCODED, MetadataSupport.HARDCODED);
MappingFormat(String name, String fileExt,
boolean hasNamespaces, boolean hasFieldDescriptors,
- boolean supportsComments, boolean supportsArgs, boolean supportsLocals) {
+ boolean supportsComments, boolean supportsArgs, boolean supportsLocals,
+ MetadataSupport fileMetadataSupport, MetadataSupport elementMetadataSupport) {
this.name = name;
this.fileExt = fileExt;
this.hasNamespaces = hasNamespaces;
@@ -37,6 +39,8 @@ public enum MappingFormat {
this.supportsComments = supportsComments;
this.supportsArgs = supportsArgs;
this.supportsLocals = supportsLocals;
+ this.fileMetadataSupport = fileMetadataSupport;
+ this.elementMetadataSupport = elementMetadataSupport;
}
public boolean hasSingleFile() {
@@ -56,4 +60,17 @@ public String getGlobPattern() {
public final boolean supportsComments;
public final boolean supportsArgs;
public final boolean supportsLocals;
+ public final MetadataSupport fileMetadataSupport;
+ public final MetadataSupport elementMetadataSupport;
+
+ public enum MetadataSupport {
+ /** No metadata at all. */
+ NONE,
+
+ /** Only some select properties. */
+ HARDCODED,
+
+ /** Arbitrary metadata may be attached. */
+ ARBITRARY
+ }
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/MioTempProperties.java b/src/main/java/net/fabricmc/mappingio/format/MioTempProperties.java
new file mode 100644
index 00000000..24747d69
--- /dev/null
+++ b/src/main/java/net/fabricmc/mappingio/format/MioTempProperties.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * Internal properties which mapping readers attach while parsing.
+ * They are removed again when saving via a {@link net.fabricmc.mappingio.MappingWriter MappingWriter}.
+ */
+public final class MioTempProperties {
+ public static final String MIO_PREFIX = "mio:";
+
+ private static String register(String name) {
+ return MIO_PREFIX + name;
+ }
+}
diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java
new file mode 100644
index 00000000..1280a65e
--- /dev/null
+++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperties.java
@@ -0,0 +1,222 @@
+/*
+ * 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;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.jetbrains.annotations.ApiStatus;
+
+import net.fabricmc.mappingio.MappedElementKind;
+
+public final class StandardProperties {
+ private StandardProperties() {
+ }
+
+ public static Set values() {
+ return Collections.unmodifiableSet(values);
+ }
+
+ public static StandardProperty getByName(String name) {
+ return valuesByName.get(name);
+ }
+
+ @ApiStatus.Internal
+ public static StandardProperty getById(String id) {
+ return valuesById.get(id);
+ }
+
+ public static final StandardProperty NEXT_INTERMEDIARY_CLASS;
+ public static final StandardProperty NEXT_INTERMEDIARY_FIELD;
+ public static final StandardProperty NEXT_INTERMEDIARY_METHOD;
+ public static final StandardProperty NEXT_INTERMEDIARY_COMPONENT;
+ public static final StandardProperty MISSING_LVT_INDICES;
+ public static final StandardProperty ESCAPED_NAMES;
+ public static final StandardProperty MODIFIED_ACCESS;
+ public static final StandardProperty IS_STATIC;
+ public static final StandardProperty START_LINE_NUMBER;
+ public static final StandardProperty END_LINE_NUMBER;
+ public static final StandardProperty PARAM_DEST_POS;
+ private static final Set values = new HashSet<>();
+ private static final Map valuesByName = new HashMap<>();
+ private static final Map valuesById = new HashMap<>();
+
+ static {
+ NEXT_INTERMEDIARY_CLASS = register(
+ "next-intermediary-class",
+ new HashMap() {{
+ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER class");
+ put(MappingFormat.TINY_2_FILE, "next-intermediary-class");
+ }},
+ Collections.emptyMap());
+ NEXT_INTERMEDIARY_FIELD = register(
+ "next-intermediary-field",
+ new HashMap() {{
+ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER field");
+ put(MappingFormat.TINY_2_FILE, "next-intermediary-field");
+ }},
+ Collections.emptyMap());
+ NEXT_INTERMEDIARY_METHOD = register(
+ "next-intermediary-method",
+ new HashMap() {{
+ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER method");
+ put(MappingFormat.TINY_2_FILE, "next-intermediary-method");
+ }},
+ Collections.emptyMap());
+ NEXT_INTERMEDIARY_COMPONENT = register(
+ "next-intermediary-component",
+ new HashMap() {{
+ put(MappingFormat.TINY_FILE, "INTERMEDIARY_COUNTER component");
+ put(MappingFormat.TINY_2_FILE, "next-intermediary-component");
+ }},
+ Collections.emptyMap());
+ MISSING_LVT_INDICES = register(
+ "missing-lvt-indices",
+ new HashMap() {{
+ put(MappingFormat.TINY_2_FILE, "missing-lvt-indices");
+ }},
+ Collections.emptyMap());
+ ESCAPED_NAMES = register(
+ "escaped-names",
+ new HashMap() {{
+ put(MappingFormat.TINY_2_FILE, "escaped-names");
+ }},
+ Collections.emptyMap());
+ MODIFIED_ACCESS = register(
+ "modified-access",
+ Collections.emptyMap(),
+ new HashMap, String>() {{
+ put(new SimpleEntry<>(MappingFormat.ENIGMA_FILE, MappedElementKind.CLASS), "ACC:");
+ put(new SimpleEntry<>(MappingFormat.ENIGMA_FILE, MappedElementKind.FIELD), "ACC:");
+ put(new SimpleEntry<>(MappingFormat.ENIGMA_FILE, MappedElementKind.METHOD), "ACC:");
+ put(new SimpleEntry<>(MappingFormat.ENIGMA_DIR, MappedElementKind.CLASS), "ACC:");
+ put(new SimpleEntry<>(MappingFormat.ENIGMA_DIR, MappedElementKind.FIELD), "ACC:");
+ put(new SimpleEntry<>(MappingFormat.ENIGMA_DIR, MappedElementKind.METHOD), "ACC:");
+ }});
+ IS_STATIC = register(
+ "is-static",
+ Collections.emptyMap(),
+ new HashMap, String>() {{
+ put(new SimpleEntry<>(MappingFormat.TSRG_2_FILE, MappedElementKind.METHOD), "static");
+ }});
+ START_LINE_NUMBER = register(
+ "start-line-number",
+ Collections.emptyMap(),
+ new HashMap, String>() {{
+ put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null);
+ put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null);
+ }});
+ END_LINE_NUMBER = register(
+ "end-line-number",
+ Collections.emptyMap(),
+ new HashMap, String>() {{
+ put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null);
+ put(new SimpleEntry<>(MappingFormat.PROGUARD_FILE, MappedElementKind.FIELD), null);
+ }});
+ PARAM_DEST_POS = register(
+ "parameter-destination-position",
+ Collections.emptyMap(),
+ new HashMap, String>() {{
+ put(new SimpleEntry<>(MappingFormat.MATCH_FILE, MappedElementKind.METHOD_ARG), null);
+ }});
+ }
+
+ private static StandardProperty register(String id, Map filePropNameByFormat,
+ Map, String> elementPropNameByFormat) {
+ StandardProperty ret = new StandardPropertyImpl(id, filePropNameByFormat, elementPropNameByFormat);
+ values.add(ret);
+ valuesById.put(id, ret);
+
+ for (String name : filePropNameByFormat.values()) {
+ valuesByName.putIfAbsent(name, ret);
+ }
+
+ for (String name : elementPropNameByFormat.values()) {
+ valuesByName.putIfAbsent(name, ret);
+ }
+
+ return ret;
+ }
+
+ static class StandardPropertyImpl implements StandardProperty {
+ StandardPropertyImpl(String id, Map filePropNameByFormat,
+ Map, String> elementPropNameByFormat) {
+ this.id = id;
+ this.filePropNameByFormat = filePropNameByFormat;
+ this.elementPropNameByFormat = elementPropNameByFormat;
+ this.propElementKindByFormat = elementPropNameByFormat.entrySet().stream()
+ .map(entry -> entry.getKey())
+ .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+ }
+
+ @Override
+ public boolean isFileProperty() {
+ return !filePropNameByFormat.isEmpty();
+ }
+
+ @Override
+ public boolean isElementProperty() {
+ return !elementPropNameByFormat.isEmpty();
+ }
+
+ @Override
+ public Set getApplicableFormats() {
+ return filePropNameByFormat.keySet();
+ }
+
+ @Override
+ public Map getApplicableElementKinds() {
+ return propElementKindByFormat;
+ }
+
+ @Override
+ public boolean isApplicableTo(MappingFormat format) {
+ return filePropNameByFormat.containsKey(format);
+ }
+
+ @Override
+ public boolean isApplicableTo(MappingFormat format, MappedElementKind elementKind) {
+ return elementPropNameByFormat.containsKey(new SimpleEntry<>(format, elementKind));
+ }
+
+ @Override
+ public String getNameFor(MappingFormat format) {
+ return filePropNameByFormat.get(format);
+ }
+
+ @Override
+ public String getNameFor(MappingFormat format, MappedElementKind elementKind) {
+ return elementPropNameByFormat.get(new SimpleEntry<>(format, elementKind));
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ private final String id;
+ private final Map filePropNameByFormat;
+ private final Map, String> elementPropNameByFormat;
+ private final Map propElementKindByFormat;
+ }
+}
diff --git a/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java
new file mode 100644
index 00000000..84d5ea8e
--- /dev/null
+++ b/src/main/java/net/fabricmc/mappingio/format/StandardProperty.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.jetbrains.annotations.ApiStatus;
+
+import net.fabricmc.mappingio.MappedElementKind;
+
+public interface StandardProperty {
+ boolean isFileProperty();
+ boolean isElementProperty();
+
+ Set getApplicableFormats();
+ Map getApplicableElementKinds();
+
+ boolean isApplicableTo(MappingFormat format);
+ boolean isApplicableTo(MappingFormat format, MappedElementKind elementKind);
+
+ String getNameFor(MappingFormat format);
+ String getNameFor(MappingFormat format, MappedElementKind elementKind);
+
+ /**
+ * Used internally by MappingTrees, consistency between JVM sessions
+ * or library versions isn't guaranteed!
+ */
+ @ApiStatus.Internal
+ String getId();
+}
diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java
index 05ffce65..f8885567 100644
--- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java
+++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileReader.java
@@ -19,13 +19,17 @@
import java.io.IOException;
import java.io.Reader;
import java.util.Collections;
+import java.util.Locale;
import java.util.Set;
+import org.jetbrains.annotations.Nullable;
+
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.StandardProperties;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -61,7 +65,7 @@ public static void read(ColumnFileReader reader, String sourceNs, String targetN
final MappingVisitor finalVisitor = visitor;
do {
- if (reader.nextCol("CLASS")) { // class: CLASS []
+ if (reader.nextCol("CLASS")) { // class: CLASS [] []
readClass(reader, 0, null, null, commentSb, finalVisitor);
}
} while (reader.nextLine(0));
@@ -75,8 +79,11 @@ public static void read(ColumnFileReader reader, String sourceNs, String targetN
}
private static void readClass(ColumnFileReader reader, int indent, String outerSrcClass, String outerDstClass, StringBuilder commentSb, MappingVisitor visitor) throws IOException {
- String srcInnerName = reader.nextCol();
- if (srcInnerName == null || srcInnerName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber());
+ String line = reader.nextCols(false);
+ String[] parts = line.split(" ");
+
+ if (parts.length == 0 || parts[0].isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber());
+ String srcInnerName = parts[0];
String srcName = srcInnerName;
@@ -84,7 +91,22 @@ private static void readClass(ColumnFileReader reader, int indent, String outerS
srcName = String.format("%s$%s", outerSrcClass, srcInnerName);
}
- String dstInnerName = reader.nextCol();
+ String dstInnerName = null;
+ String accessModifier = null;
+
+ if (parts.length == 2) { // |
+ String parsedModifier = parseModifier(parts[1]);
+
+ if (parsedModifier == null) {
+ dstInnerName = parts[1];
+ } else {
+ accessModifier = parsedModifier;
+ }
+ } else {
+ dstInnerName = parts[1];
+ accessModifier = parts[2];
+ }
+
String dstName = dstInnerName;
// merge with outer name if available
@@ -96,19 +118,20 @@ private static void readClass(ColumnFileReader reader, int indent, String outerS
dstName = String.format("%s$%s", outerDstClass, dstInnerName);
}
- readClassBody(reader, indent, srcName, dstName, commentSb, visitor);
+ readClassBody(reader, indent, srcName, dstName, accessModifier, commentSb, visitor);
}
- private static void readClassBody(ColumnFileReader reader, int indent, String srcClass, String dstClass, StringBuilder commentSb, MappingVisitor visitor) throws IOException {
+ private static void readClassBody(ColumnFileReader reader, int indent, String srcClass, String dstClass,
+ String classAccess, StringBuilder commentSb, MappingVisitor visitor) throws IOException {
boolean visited = false;
int state = 0; // 0=invalid 1=visit -1=skip
while (reader.nextLine(indent + 1)) {
boolean isMethod;
- if (reader.nextCol("CLASS")) { // nested class: CLASS []
+ if (reader.nextCol("CLASS")) { // nested class: CLASS [] []
if (!visited || commentSb.length() > 0) {
- visitClass(srcClass, dstClass, state, commentSb, visitor);
+ visitClass(srcClass, dstClass, state, classAccess, commentSb, visitor);
visited = true;
}
@@ -116,46 +139,64 @@ private static void readClassBody(ColumnFileReader reader, int indent, String sr
state = 0;
} else if (reader.nextCol("COMMENT")) { // comment: COMMENT
readComment(reader, commentSb);
- } else if ((isMethod = reader.nextCol("METHOD")) || reader.nextCol("FIELD")) { // method: METHOD [] or field: FIELD []
- state = visitClass(srcClass, dstClass, state, commentSb, visitor);
+ } else if ((isMethod = reader.nextCol("METHOD")) || reader.nextCol("FIELD")) { // METHOD|FIELD [] []
+ state = visitClass(srcClass, dstClass, state, classAccess, commentSb, visitor);
visited = true;
if (state < 0) continue;
- String srcName = reader.nextCol();
- if (srcName == null || srcName.isEmpty()) throw new IOException("missing field-name-a in line "+reader.getLineNumber());
+ String line = reader.nextCols(false);
+ String[] parts = line.split(" ");
+
+ if (parts.length == 0 || parts[0].isEmpty()) throw new IOException("missing member-name-a in line "+reader.getLineNumber());
+ if (parts.length == 1 || parts[1].isEmpty()) throw new IOException("missing member-desc-a in line "+reader.getLineNumber());
+ String srcName = parts[0];
+ String dstName = null;
+ String modifier = null;
+ String srcDesc;
+
+ if (parts.length == 2) { //
+ srcDesc = parts[1];
+ } else if (parts.length == 3) { // |
+ String parsedModifier = parseModifier(parts[2]);
+
+ if (parsedModifier == null) {
+ dstName = parts[1];
+ srcDesc = parts[2];
+ } else {
+ srcDesc = parts[1];
+ modifier = parsedModifier;
+ }
+ } else { //
+ dstName = parts[1];
+ srcDesc = parts[2];
+ modifier = parts[3];
+ }
- String dstNameOrSrcDesc = reader.nextCol();
- if (dstNameOrSrcDesc == null || dstNameOrSrcDesc.isEmpty()) throw new IOException("missing field-desc-b in line "+reader.getLineNumber());
+ MappedElementKind targetKind = isMethod && visitor.visitMethod(srcName, srcDesc) ? MappedElementKind.METHOD
+ : !isMethod && visitor.visitField(srcName, srcDesc) ? MappedElementKind.FIELD : null;
- String srcDesc = reader.nextCol();
- String dstName;
+ if (targetKind != null) {
+ if (dstName != null && !dstName.isEmpty()) visitor.visitDstName(targetKind, 0, dstName);
+ if (modifier != null) visitAccessModifier(targetKind, modifier, visitor);
- if (srcDesc == null) {
- dstName = null;
- srcDesc = dstNameOrSrcDesc;
- } else {
- dstName = dstNameOrSrcDesc;
- }
-
- if (isMethod && visitor.visitMethod(srcName, srcDesc)) {
- if (dstName != null && !dstName.isEmpty()) visitor.visitDstName(MappedElementKind.METHOD, 0, dstName);
- readMethod(reader, indent, commentSb, visitor);
- } else if (!isMethod && visitor.visitField(srcName, srcDesc)) {
- if (dstName != null && !dstName.isEmpty()) visitor.visitDstName(MappedElementKind.FIELD, 0, dstName);
- readElement(reader, MappedElementKind.FIELD, indent, commentSb, visitor);
+ if (targetKind == MappedElementKind.METHOD) {
+ readMethod(reader, indent, commentSb, visitor);
+ } else {
+ readElement(reader, targetKind, indent, commentSb, visitor);
+ }
}
}
}
if (!visited || commentSb.length() > 0) {
- visitClass(srcClass, dstClass, state, commentSb, visitor);
+ visitClass(srcClass, dstClass, state, classAccess, commentSb, visitor);
}
}
/**
* Re-visit a class if necessary and visit its comment if available.
*/
- private static int visitClass(String srcClass, String dstClass, int state, StringBuilder commentSb, MappingVisitor visitor) throws IOException {
+ private static int visitClass(String srcClass, String dstClass, int state, String accessModifier, StringBuilder commentSb, MappingVisitor visitor) throws IOException {
// state: 0=invalid 1=visit -1=skip
if (state == 0) {
@@ -168,6 +209,10 @@ private static int visitClass(String srcClass, String dstClass, int state, Strin
state = visitContent ? 1 : -1;
+ if (accessModifier != null) {
+ visitAccessModifier(MappedElementKind.CLASS, accessModifier, visitor);
+ }
+
if (commentSb.length() > 0) {
if (state > 0) visitor.visitComment(MappedElementKind.CLASS, commentSb.toString());
@@ -178,6 +223,10 @@ private static int visitClass(String srcClass, String dstClass, int state, Strin
return state;
}
+ private static void visitAccessModifier(MappedElementKind targetKind, String modifier, MappingVisitor visitor) throws IOException {
+ visitor.visitElementMetadata(targetKind, StandardProperties.MODIFIED_ACCESS.getId(), 0, modifier);
+ }
+
private static void readMethod(ColumnFileReader reader, int indent, StringBuilder commentSb, MappingVisitor visitor) throws IOException {
if (!visitor.visitElementContent(MappedElementKind.METHOD)) return;
@@ -233,4 +282,13 @@ private static void submitComment(MappedElementKind kind, StringBuilder commentS
visitor.visitComment(kind, commentSb.toString());
commentSb.setLength(0);
}
+
+ @Nullable
+ private static String parseModifier(String token) {
+ if (!token.startsWith("ACC:")) {
+ return null;
+ }
+
+ return token.substring(4).toLowerCase(Locale.ROOT);
+ }
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java
index 4c285707..c568e349 100644
--- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java
+++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaFileWriter.java
@@ -33,9 +33,6 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept
} else if (targetKind == MappedElementKind.FIELD || targetKind == MappedElementKind.METHOD) {
writer.write(' ');
writer.write(desc);
- writer.write('\n');
- } else {
- writer.write('\n');
}
return true;
diff --git a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java
index 11277530..9490e5c9 100644
--- a/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java
+++ b/src/main/java/net/fabricmc/mappingio/format/enigma/EnigmaWriterBase.java
@@ -19,12 +19,16 @@
import java.io.IOException;
import java.io.Writer;
import java.util.EnumSet;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import net.fabricmc.mappingio.MappedElementKind;
import net.fabricmc.mappingio.MappingFlag;
import net.fabricmc.mappingio.MappingWriter;
+import net.fabricmc.mappingio.format.StandardProperties;
abstract class EnigmaWriterBase implements MappingWriter {
EnigmaWriterBase(Writer writer) throws IOException {
@@ -46,12 +50,14 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) { }
@Override
public boolean visitClass(String srcName) throws IOException {
+ writePendingElementMetadata();
srcClassName = srcName;
return true;
}
@Override
public boolean visitField(String srcName, String srcDesc) throws IOException {
+ writePendingElementMetadata();
writeIndent(0);
writer.write("FIELD ");
writer.write(srcName);
@@ -63,6 +69,7 @@ public boolean visitField(String srcName, String srcDesc) throws IOException {
@Override
public boolean visitMethod(String srcName, String srcDesc) throws IOException {
+ writePendingElementMetadata();
writeIndent(0);
writer.write("METHOD ");
writer.write(srcName);
@@ -74,6 +81,7 @@ public boolean visitMethod(String srcName, String srcDesc) throws IOException {
@Override
public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) throws IOException {
+ writePendingElementMetadata();
writeIndent(1);
writer.write("ARG ");
writer.write(Integer.toString(lvIndex));
@@ -82,12 +90,14 @@ public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) thro
}
@Override
- public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) {
+ public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcName) throws IOException {
+ writePendingElementMetadata();
return false;
}
@Override
public boolean visitEnd() throws IOException {
+ writePendingElementMetadata();
close();
return true;
@@ -108,6 +118,11 @@ public void visitDstName(MappedElementKind targetKind, int namespace, String nam
@Override
public abstract boolean visitElementContent(MappedElementKind targetKind) throws IOException;
+ @Override
+ public void visitElementMetadata(MappedElementKind target, String key, int namespace, String value) {
+ if (namespace == 0) elementMetadata.put(key, value);
+ }
+
protected static int getNextOuterEnd(String name, int startPos) {
int pos;
@@ -121,6 +136,7 @@ protected static int getNextOuterEnd(String name, int startPos) {
@Override
public void visitComment(MappedElementKind targetKind, String comment) throws IOException {
+ writePendingElementMetadata();
int start = 0;
int pos;
@@ -203,15 +219,38 @@ protected void writeMismatchedOrMissingClasses() throws IOException {
dstName = null;
}
+ protected void writePendingElementMetadata() throws IOException {
+ if (!elementMetadata.isEmpty()) {
+ for (Map.Entry entry : elementMetadata.entrySet()) {
+ String key = entry.getKey();
+ if (StandardProperties.getById(key) != StandardProperties.MODIFIED_ACCESS) continue;
+
+ writer.write(key);
+ writer.write(" ACC:");
+ writer.write(entry.getValue().toUpperCase(Locale.ROOT));
+ break;
+ }
+
+ elementMetadata.clear();
+ }
+
+ writer.write('\n');
+ }
+
protected void writeIndent(int extra) throws IOException {
for (int i = 0; i < indent + extra; i++) {
writer.write('\t');
}
}
- protected static final Set flags = EnumSet.of(MappingFlag.NEEDS_UNIQUENESS, MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC);
+ protected static final Set flags = EnumSet.of(
+ MappingFlag.NEEDS_HEADER_METADATA,
+ MappingFlag.NEEDS_UNIQUENESS,
+ MappingFlag.NEEDS_SRC_FIELD_DESC,
+ MappingFlag.NEEDS_SRC_METHOD_DESC);
protected static final String toEscape = "\\\n\r\0\t";
protected static final String escaped = "\\nr0t";
+ protected static final LinkedHashMap elementMetadata = new LinkedHashMap<>();
protected Writer writer;
protected int indent;
@@ -220,7 +259,6 @@ protected void writeIndent(int extra) throws IOException {
protected String currentClass;
protected String lastWrittenClass = "";
protected String dstName;
- protected String[] dstNames;
protected String desc;
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java b/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java
new file mode 100644
index 00000000..726e134d
--- /dev/null
+++ b/src/main/java/net/fabricmc/mappingio/format/match/MatchFileReader.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2021 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.match;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Arrays;
+
+import net.fabricmc.mappingio.MappedElementKind;
+import net.fabricmc.mappingio.MappingFlag;
+import net.fabricmc.mappingio.MappingVisitor;
+import net.fabricmc.mappingio.format.ColumnFileReader;
+import net.fabricmc.mappingio.format.StandardProperties;
+
+public class MatchFileReader {
+ public static void read(Reader reader, MappingVisitor visitor) throws IOException {
+ read(new ColumnFileReader(reader, '\t'), visitor);
+ }
+
+ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws IOException {
+ if (!reader.nextCol().startsWith("Matches saved")) {
+ throw new IOException("invalid/unsupported match file: incorrect header");
+ }
+
+ if (visitor.getFlags().contains(MappingFlag.NEEDS_MULTIPLE_PASSES)) {
+ reader.mark();
+ }
+
+ boolean escapeNames = false;
+
+ for (;;) {
+ boolean visitHeader = visitor.visitHeader();
+
+ if (visitHeader) {
+ visitor.visitNamespaces("a", Arrays.asList("b"));
+ }
+
+ if (visitor.visitContent()) {
+ while (reader.nextLine(0)) {
+ if (reader.nextCol("c")) { // class: c
+ String srcName = reader.nextCol(escapeNames);
+ if (srcName == null || srcName.isEmpty()) throw new IOException("missing class-name-a in line "+reader.getLineNumber());
+
+ if (visitor.visitClass(srcName)) {
+ readClass(reader, escapeNames, visitor);
+ }
+ }
+ }
+ }
+
+ if (visitor.visitEnd()) break;
+
+ reader.reset();
+ }
+ }
+
+ private static void readClass(ColumnFileReader reader, boolean escapeNames, MappingVisitor visitor) throws IOException {
+ visitor.visitDstName(MappedElementKind.CLASS, 0, reader.nextCol(escapeNames));
+ if (!visitor.visitElementContent(MappedElementKind.CLASS)) return;
+
+ while (reader.nextLine(1)) {
+ boolean field = false;
+ boolean method = false;
+
+ if ((field = reader.nextCol("f")) || (method = reader.nextCol("m"))) {
+ // field: f
+ // method: m (but no spaces between name and desc)
+
+ String[] from;
+ String[] to;
+
+ if (field) {
+ from = reader.nextCol(escapeNames).split(";;");
+ to = reader.nextCol(escapeNames).split(";;");
+ } else {
+ from = toMethodArray(reader.nextCol(escapeNames));
+ to = toMethodArray(reader.nextCol(escapeNames));
+ }
+
+ if (from.length != 2 || to.length != 2) throw new IOException("invalid member mapping in line "+reader.getLineNumber());
+
+ String srcName = from[0];
+ String srcDesc = from[1];
+ String dstName = to[0];
+ String dstDesc = to[1];
+
+ if (field && visitor.visitField(srcName, srcDesc)) {
+ visitor.visitDstName(MappedElementKind.FIELD, 0, dstName);
+ visitor.visitDstDesc(MappedElementKind.FIELD, 0, dstDesc);
+ } else if (method && visitor.visitMethod(srcName, srcDesc)) {
+ visitor.visitDstName(MappedElementKind.METHOD, 0, dstName);
+ visitor.visitDstDesc(MappedElementKind.METHOD, 0, dstDesc);
+ readMethodContent(reader, escapeNames, visitor);
+ }
+ } else if (reader.nextCol("c")) { // comment: c
+ readComment(reader, MappedElementKind.CLASS, visitor);
+ }
+ }
+ }
+
+ private static String[] toMethodArray(String nameWithDescriptor) {
+ int parenPos = nameWithDescriptor.indexOf('(');
+ return new String[] {
+ nameWithDescriptor.substring(0, parenPos),
+ nameWithDescriptor.substring(parenPos)
+ };
+ }
+
+ private static void readMethodContent(ColumnFileReader reader, boolean escapeNames, MappingVisitor visitor) throws IOException {
+ if (!visitor.visitElementContent(MappedElementKind.METHOD)) return;
+
+ while (reader.nextLine(2)) {
+ if (reader.nextCol("ma")) {
+ // method arg: ma
+
+ int srcArgPos = reader.nextIntCol();
+ int dstArgPos = reader.nextIntCol();
+ if (srcArgPos < 0 || dstArgPos < 0) throw new IOException("missing/invalid method arg position in line "+reader.getLineNumber());
+
+ if (visitor.visitMethodArg(srcArgPos, -1, null)) {
+ visitor.visitElementMetadata(MappedElementKind.METHOD_ARG, StandardProperties.PARAM_DEST_POS.getId(), 0, String.valueOf(dstArgPos));
+ }
+ } else if (reader.nextCol("c")) { // comment: c
+ readComment(reader, MappedElementKind.METHOD, visitor);
+ }
+ }
+ }
+
+ private static void readComment(ColumnFileReader reader, MappedElementKind subjectKind, MappingVisitor visitor) throws IOException {
+ String comment = reader.nextEscapedCol();
+ if (comment == null) throw new IOException("missing comment in line "+reader.getLineNumber());
+
+ visitor.visitComment(subjectKind, comment);
+ }
+}
diff --git a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java
index d1670b7d..9193e79a 100644
--- a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java
+++ b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileReader.java
@@ -27,6 +27,7 @@
import net.fabricmc.mappingio.MappingFlag;
import net.fabricmc.mappingio.MappingUtil;
import net.fabricmc.mappingio.MappingVisitor;
+import net.fabricmc.mappingio.format.StandardProperties;
public final class ProGuardFileReader {
private ProGuardFileReader() {
@@ -115,6 +116,8 @@ private static void read(BufferedReader reader, String sourceNs, String targetNs
// lineStart, lineEndIncl, rtype
String part0 = parts[0];
int pos = part0.indexOf(':');
+ String lineStart = null;
+ String lineEnd = null;
String retType;
@@ -124,6 +127,8 @@ private static void read(BufferedReader reader, String sourceNs, String targetNs
int pos2 = part0.indexOf(':', pos + 1);
assert pos2 != -1;
+ lineStart = part0.substring(0, pos);
+ lineEnd = part0.substring(pos + 1, pos2);
retType = part0.substring(pos2 + 1);
}
@@ -141,7 +146,11 @@ private static void read(BufferedReader reader, String sourceNs, String targetNs
if (visitor.visitMethod(name, desc)) {
String mappedName = parts[3];
visitor.visitDstName(MappedElementKind.METHOD, 0, mappedName);
- visitor.visitElementContent(MappedElementKind.METHOD);
+
+ if (visitor.visitElementContent(MappedElementKind.METHOD) && lineStart != null) {
+ visitor.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.START_LINE_NUMBER.getId(), 0, lineStart);
+ visitor.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.END_LINE_NUMBER.getId(), 0, lineEnd);
+ }
}
}
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java
index f41d4450..b53c144b 100644
--- a/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java
+++ b/src/main/java/net/fabricmc/mappingio/format/proguard/ProGuardFileWriter.java
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.io.Writer;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -25,6 +26,8 @@
import net.fabricmc.mappingio.MappedElementKind;
import net.fabricmc.mappingio.MappingWriter;
+import net.fabricmc.mappingio.format.StandardProperties;
+import net.fabricmc.mappingio.format.StandardProperty;
/**
* A mapping writer for the ProGuard mapping format.
@@ -36,8 +39,11 @@
*/
public final class ProGuardFileWriter implements MappingWriter {
private final Writer writer;
- private int dstNamespace = -1;
private final String dstNamespaceString;
+ private int dstNamespace = -1;
+ private MappedElementKind pendingMemberType;
+ /** srcName, srcDesc, dstName, [lineStart, lineEnd]. */
+ private String[] pendingMemberData = new String[5];
/**
* Constructs a ProGuard mapping writer that uses
@@ -103,6 +109,8 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr
@Override
public boolean visitClass(String srcName) throws IOException {
+ writePendingMember();
+
writer.write(toJavaClassName(srcName));
writeArrow();
return true;
@@ -110,34 +118,21 @@ public boolean visitClass(String srcName) throws IOException {
@Override
public boolean visitField(String srcName, String srcDesc) throws IOException {
- writeIndent();
- writer.write(toJavaType(srcDesc));
- writer.write(' ');
- writer.write(srcName);
- writeArrow();
+ writePendingMember();
+
+ pendingMemberType = MappedElementKind.FIELD;
+ pendingMemberData[0] = srcName;
+ pendingMemberData[1] = srcDesc;
return true;
}
@Override
public boolean visitMethod(String srcName, String srcDesc) throws IOException {
- Type type = Type.getMethodType(srcDesc);
- writeIndent();
- writer.write(toJavaType(type.getReturnType().getDescriptor()));
- writer.write(' ');
- writer.write(srcName);
- writer.write('(');
- Type[] args = type.getArgumentTypes();
-
- for (int i = 0; i < args.length; i++) {
- if (i > 0) {
- writer.write(',');
- }
-
- writer.write(toJavaType(args[i].getDescriptor()));
- }
+ writePendingMember();
- writer.write(')');
- writeArrow();
+ pendingMemberType = MappedElementKind.METHOD;
+ pendingMemberData[0] = srcName;
+ pendingMemberData[1] = srcDesc;
return true;
}
@@ -162,11 +157,22 @@ public void visitDstName(MappedElementKind targetKind, int namespace, String nam
if (targetKind == MappedElementKind.CLASS) {
writer.write(toJavaClassName(name));
writer.write(':');
+ writer.write('\n');
} else {
- writer.write(name);
+ pendingMemberData[2] = name;
}
+ }
- writer.write('\n');
+ @Override
+ public void visitElementMetadata(MappedElementKind target, String key, int namespace, String value) {
+ assert target == pendingMemberType;
+ StandardProperty property = StandardProperties.getById(key);
+
+ if (property == StandardProperties.START_LINE_NUMBER) {
+ pendingMemberData[3] = value;
+ } else if (property == StandardProperties.END_LINE_NUMBER) {
+ pendingMemberData[4] = value;
+ }
}
@Override
@@ -174,6 +180,62 @@ public void visitComment(MappedElementKind targetKind, String comment) throws IO
// ignored
}
+ @Override
+ public boolean visitEnd() throws IOException {
+ writePendingMember();
+ return true;
+ }
+
+ private void writePendingMember() throws IOException {
+ if (pendingMemberType == null) return;
+ String srcName = pendingMemberData[0];
+ String srcDesc = pendingMemberData[1];
+ String startLine = pendingMemberData[2];
+ String endLine = pendingMemberData[3];
+
+ writeIndent();
+
+ if (startLine != null) {
+ writer.write(startLine);
+ writer.write(':');
+ writer.write(endLine);
+ writer.write(':');
+ }
+
+ if (pendingMemberType == MappedElementKind.FIELD) {
+ writer.write(toJavaType(srcDesc));
+ writer.write(' ');
+ writer.write(srcName);
+ writeArrow();
+ } else {
+ Type type = Type.getMethodType(srcDesc);
+ writer.write(toJavaType(type.getReturnType().getDescriptor()));
+ writer.write(' ');
+ writer.write(srcName);
+ writer.write('(');
+ Type[] args = type.getArgumentTypes();
+
+ for (int i = 0; i < args.length; i++) {
+ if (i > 0) {
+ writer.write(',');
+ }
+
+ writer.write(toJavaType(args[i].getDescriptor()));
+ }
+
+ writer.write(')');
+ writeArrow();
+ }
+
+ if (pendingMemberData[2] != null) {
+ writer.write(pendingMemberData[2]);
+ writer.write('\n');
+ }
+
+ Arrays.fill(pendingMemberData, null);
+ pendingMemberType = null;
+ }
+
private void writeArrow() throws IOException {
writer.write(" -> ");
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java
index 56e2517c..9d807b6d 100644
--- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java
+++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileReader.java
@@ -26,6 +26,9 @@
import net.fabricmc.mappingio.MappingFlag;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.format.ColumnFileReader;
+import net.fabricmc.mappingio.format.MappingFormat;
+import net.fabricmc.mappingio.format.StandardProperties;
+import net.fabricmc.mappingio.format.StandardProperty;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -134,28 +137,27 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws
}
} else {
String line = reader.nextCol();
- final String prefix = "# INTERMEDIARY-COUNTER ";
- String[] parts;
-
- if (line.startsWith(prefix)
- && (parts = line.substring(prefix.length()).split(" ")).length == 2) {
- String property = null;
-
- switch (parts[0]) {
- case "class":
- property = nextIntermediaryClassProperty;
- break;
- case "field":
- property = nextIntermediaryFieldProperty;
- break;
- case "method":
- property = nextIntermediaryMethodProperty;
- break;
+
+ if (line.startsWith("# ") && line.length() >= 3 && line.charAt(3) != ' ') { // Metadata
+ line = line.substring(2);
+ String[] parts = line.split(" ");
+ String value = parts[parts.length - 1];
+ String key = line.substring(0, line.lastIndexOf(value));
+
+ if (key.isEmpty()) {
+ String oldValue = value;
+ value = key;
+ key = oldValue;
}
+ StandardProperty property = StandardProperties.getByName(key);
+
if (property != null) {
- visitor.visitMetadata(property, parts[1]);
+ if (!property.isApplicableTo(format)) continue; // How did it get there?
+ key = property.getId();
}
+
+ visitor.visitMetadata(key, value);
}
}
}
@@ -180,7 +182,5 @@ private static void readDstNames(ColumnFileReader reader, MappedElementKind subj
}
}
- static final String nextIntermediaryClassProperty = "next-intermediary-class";
- static final String nextIntermediaryFieldProperty = "next-intermediary-field";
- static final String nextIntermediaryMethodProperty = "next-intermediary-method";
+ private static final MappingFormat format = MappingFormat.TINY_FILE;
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java
index bcdf2406..c249d4e8 100644
--- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java
+++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny1FileWriter.java
@@ -26,6 +26,9 @@
import net.fabricmc.mappingio.MappedElementKind;
import net.fabricmc.mappingio.MappingFlag;
import net.fabricmc.mappingio.MappingWriter;
+import net.fabricmc.mappingio.format.MappingFormat;
+import net.fabricmc.mappingio.format.StandardProperties;
+import net.fabricmc.mappingio.format.StandardProperty;
public final class Tiny1FileWriter implements MappingWriter {
public Tiny1FileWriter(Writer writer) {
@@ -59,30 +62,18 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr
@Override
public void visitMetadata(String key, String value) throws IOException {
- switch (key) {
- case Tiny1FileReader.nextIntermediaryClassProperty:
- case Tiny1FileReader.nextIntermediaryFieldProperty:
- case Tiny1FileReader.nextIntermediaryMethodProperty:
- write("# INTERMEDIARY-COUNTER ");
-
- switch (key) {
- case Tiny1FileReader.nextIntermediaryClassProperty:
- write("class");
- break;
- case Tiny1FileReader.nextIntermediaryFieldProperty:
- write("field");
- break;
- case Tiny1FileReader.nextIntermediaryMethodProperty:
- write("method");
- break;
- default:
- throw new IllegalStateException();
- }
+ StandardProperty property = StandardProperties.getById(key);
- write(" ");
- write(value);
- writeLn();
+ if (property != null) {
+ if (!property.isApplicableTo(format)) return;
+ key = property.getNameFor(format);
}
+
+ write("# ");
+ write(key);
+ write(" ");
+ write(value);
+ writeLn();
}
@Override
@@ -191,6 +182,7 @@ private void writeTab() throws IOException {
}
private static final Set flags = EnumSet.of(MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC);
+ private static final MappingFormat format = MappingFormat.TINY_FILE;
private final Writer writer;
private String classSrcName;
diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java
index 6381d80f..7c174ea1 100644
--- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java
+++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileReader.java
@@ -25,6 +25,9 @@
import net.fabricmc.mappingio.MappingFlag;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.format.ColumnFileReader;
+import net.fabricmc.mappingio.format.MappingFormat;
+import net.fabricmc.mappingio.format.StandardProperties;
+import net.fabricmc.mappingio.format.StandardProperty;
public final class Tiny2FileReader {
private Tiny2FileReader() {
@@ -89,16 +92,22 @@ private static void read(ColumnFileReader reader, MappingVisitor visitor) throws
if (visitHeader || firstIteration) {
while (reader.nextLine(1)) {
if (!visitHeader) {
- if (!escapeNames && reader.nextCol(Tiny2Util.escapedNamesProperty)) {
+ if (!escapeNames && reader.nextCol(StandardProperties.ESCAPED_NAMES.getNameFor(format))) {
escapeNames = true;
}
} else {
String key = reader.nextCol();
if (key == null) throw new IOException("missing property key in line "+reader.getLineNumber());
String value = reader.nextEscapedCol(); // may be missing -> null
+ StandardProperty property = StandardProperties.getByName(key);
- if (key.equals(Tiny2Util.escapedNamesProperty)) {
- escapeNames = true;
+ if (property != null) {
+ if (!property.isApplicableTo(format)) continue; // How did it get there?
+ key = property.getId();
+
+ if (property == StandardProperties.ESCAPED_NAMES) {
+ escapeNames = true;
+ }
}
visitor.visitMetadata(key, value);
@@ -215,4 +224,6 @@ private static void readDstNames(ColumnFileReader reader, MappedElementKind subj
if (!name.isEmpty()) visitor.visitDstName(subjectKind, dstNs, name);
}
}
+
+ private static final MappingFormat format = MappingFormat.TINY_2_FILE;
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java
index aee1bdc0..2a37e263 100644
--- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java
+++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2FileWriter.java
@@ -26,6 +26,9 @@
import net.fabricmc.mappingio.MappedElementKind;
import net.fabricmc.mappingio.MappingFlag;
import net.fabricmc.mappingio.MappingWriter;
+import net.fabricmc.mappingio.format.MappingFormat;
+import net.fabricmc.mappingio.format.StandardProperties;
+import net.fabricmc.mappingio.format.StandardProperty;
public final class Tiny2FileWriter implements MappingWriter {
public Tiny2FileWriter(Writer writer, boolean escapeNames) {
@@ -60,9 +63,16 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) thr
@Override
public void visitMetadata(String key, String value) throws IOException {
- if (key.equals(Tiny2Util.escapedNamesProperty)) {
- escapeNames = true;
- wroteEscapedNamesProperty = true;
+ StandardProperty property = StandardProperties.getById(key);
+
+ if (property != null) {
+ if (!property.isApplicableTo(format)) return;
+ key = property.getNameFor(format);
+
+ if (property == StandardProperties.ESCAPED_NAMES) {
+ escapeNames = true;
+ wroteEscapedNamesProperty = true;
+ }
}
writeTab();
@@ -80,7 +90,7 @@ public void visitMetadata(String key, String value) throws IOException {
public boolean visitContent() throws IOException {
if (escapeNames && !wroteEscapedNamesProperty) {
write("\t");
- write(Tiny2Util.escapedNamesProperty);
+ write(StandardProperties.ESCAPED_NAMES.getNameFor(format));
writeLn();
}
@@ -201,6 +211,7 @@ private void writeTabs(int count) throws IOException {
}
private static final Set flags = EnumSet.of(MappingFlag.NEEDS_HEADER_METADATA, MappingFlag.NEEDS_UNIQUENESS, MappingFlag.NEEDS_SRC_FIELD_DESC, MappingFlag.NEEDS_SRC_METHOD_DESC);
+ private static final MappingFormat format = MappingFormat.TINY_2_FILE;
private final Writer writer;
private boolean escapeNames;
diff --git a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java
index 68bee840..341d297d 100644
--- a/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java
+++ b/src/main/java/net/fabricmc/mappingio/format/tiny/Tiny2Util.java
@@ -84,6 +84,4 @@ public static String unescape(String str) {
private static final String toEscape = "\\\n\r\0\t";
private static final String escaped = "\\nr0t";
-
- static final String escapedNamesProperty = "escaped-names";
}
diff --git a/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java b/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java
index 8ef79883..9eb1def0 100644
--- a/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java
+++ b/src/main/java/net/fabricmc/mappingio/format/tsrg/TsrgFileReader.java
@@ -28,6 +28,8 @@
import net.fabricmc.mappingio.MappingUtil;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.format.ColumnFileReader;
+import net.fabricmc.mappingio.format.StandardProperties;
+import net.fabricmc.mappingio.tree.MappingTree;
public final class TsrgFileReader {
private TsrgFileReader() {
@@ -185,8 +187,8 @@ private static void readMethod(ColumnFileReader reader, int dstNsCount, MappingV
while (reader.nextLine(2)) {
if (reader.hasExtraIndents()) continue;
- if (reader.nextCol("static")) {
- // method is static
+ if (reader.nextCol("static")) { // method is static
+ visitor.visitElementMetadata(MappedElementKind.METHOD, StandardProperties.IS_STATIC.getId(), MappingTree.SRC_NAMESPACE_ID, "true");
} else {
int lvIndex = reader.nextIntCol();
if (lvIndex < 0) throw new IOException("missing/invalid parameter lv-index in line "+reader.getLineNumber());
diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java
index b99d749b..e26aa085 100644
--- a/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java
+++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTree.java
@@ -64,6 +64,9 @@ interface ElementMapping extends ElementMappingView {
MappingTree getTree();
void setDstName(String name, int namespace);
+
+ void addMetadata(String key, int namespace, String value);
+ String[] removeMetadata(String key);
void setComment(String comment);
}
diff --git a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java
index 3de70989..77f4895e 100644
--- a/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java
+++ b/src/main/java/net/fabricmc/mappingio/tree/MappingTreeView.java
@@ -206,6 +206,9 @@ default String getName(String namespace) {
}
}
+ Collection> getMetadata();
+ String[] getMetadata(String key);
+ String getMetadata(String key, int namespace);
String getComment();
}
diff --git a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java
index 9956cce0..be3dab61 100644
--- a/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java
+++ b/src/main/java/net/fabricmc/mappingio/tree/MemoryMappingTree.java
@@ -17,14 +17,12 @@
package net.fabricmc.mappingio.tree;
import java.io.IOException;
-import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
-import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -206,36 +204,22 @@ private void updateDstNames(int[] nameMap) {
@Override
public Collection> getMetadata() {
- return metadata;
+ return Collections.unmodifiableSet(metadata.entrySet());
}
@Override
public String getMetadata(String key) {
- for (Map.Entry entry : metadata) {
- if (entry.getKey().equals(key)) return entry.getValue();
- }
-
- return null;
+ return metadata.get(key);
}
@Override
public void addMetadata(String key, String value) {
- metadata.add(new AbstractMap.SimpleEntry<>(key, value));
+ metadata.put(key, value);
}
@Override
public String removeMetadata(String key) {
- for (Iterator> it = metadata.iterator(); it.hasNext(); ) {
- Map.Entry entry = it.next();
-
- if (entry.getKey().equals(key)) {
- it.remove();
-
- return entry.getValue();
- }
- }
-
- return null;
+ return metadata.remove(key);
}
@Override
@@ -304,7 +288,7 @@ public void accept(MappingVisitor visitor, VisitOrder order) throws IOException
if (visitor.visitHeader()) {
visitor.visitNamespaces(srcNamespace, dstNamespaces);
- for (Map.Entry entry : metadata) {
+ for (Map.Entry entry : metadata.entrySet()) {
visitor.visitMetadata(entry.getKey(), entry.getValue());
}
}
@@ -391,7 +375,7 @@ public void visitNamespaces(String srcNamespace, List dstNamespaces) {
@Override
public void visitMetadata(String key, String value) {
- this.metadata.add(new AbstractMap.SimpleEntry<>(key, value));
+ addMetadata(key, value);
}
@Override
@@ -670,8 +654,17 @@ public boolean visitElementContent(MappedElementKind targetKind) throws IOExcept
return targetKind != MappedElementKind.CLASS || currentClass.getSrcName() != null; // reject classes that never received a src name
}
+ @Override
+ public void visitElementMetadata(MappedElementKind targetKind, String propertyKey, int namespace, String propertyValue) {
+ getCurrentEntry(targetKind).addMetadata(propertyKey, namespace, propertyValue);
+ }
+
@Override
public void visitComment(MappedElementKind targetKind, String comment) {
+ getCurrentEntry(targetKind).setComment(comment);
+ }
+
+ private Entry> getCurrentEntry(MappedElementKind targetKind) {
Entry> entry;
switch (targetKind) {
@@ -686,7 +679,7 @@ public void visitComment(MappedElementKind targetKind, String comment) {
}
if (entry == null) throw new UnsupportedOperationException("Tried to visit comment before owning target");
- entry.setComment(comment);
+ return entry;
}
abstract static class Entry> implements ElementMapping {
@@ -744,6 +737,33 @@ void updateDstNames(int[] map) {
dstNames = newDstNames;
}
+ @Override
+ public Collection> getMetadata() {
+ return Collections.unmodifiableSet(metadata.entrySet());
+ }
+
+ @Override
+ public String[] getMetadata(String key) {
+ return metadata.get(key);
+ }
+
+ @Override
+ public String getMetadata(String key, int namespace) {
+ return metadata.get(key)[namespace];
+ }
+
+ @Override
+ public void addMetadata(String key, int namespace, String value) {
+ String[] values = metadata.getOrDefault(key, new String[dstNames.length + 1]);
+ values[namespace] = value;
+ metadata.put(key, values);
+ }
+
+ @Override
+ public String[] removeMetadata(String key) {
+ return metadata.remove(key);
+ }
+
@Override
public final String getComment() {
return comment;
@@ -794,6 +814,7 @@ protected void copyFrom(T o, boolean replace) {
// TODO: copy args+vars
}
+ private final Map metadata = new HashMap<>();
protected String srcName;
protected String[] dstNames;
protected String comment;
@@ -1739,7 +1760,7 @@ public String toString() {
private boolean indexByDstNames;
private String srcNamespace;
private List dstNamespaces = Collections.emptyList();
- private final List> metadata = new ArrayList<>();
+ private final Map metadata = new HashMap<>();
private final Map classesBySrcName = new LinkedHashMap<>();
private Map[] classesByDstNames;