Skip to content

Commit

Permalink
Merge upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
NebelNidas committed Aug 26, 2024
2 parents 8a71873 + d84108e commit 606f97e
Show file tree
Hide file tree
Showing 31 changed files with 1,838 additions and 183 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Added IntelliJ IDEA migration map reader and writer
- Added `MappingFormat#features()` to allow for more fine-grained programmatic querying of format capabilities
- Overhauled the internal `ColumnFileReader` to behave more consistently
- Made handling of the `NEEDS_MULTIPLE_PASSES` flag more consistent, reducing memory usage in a few cases
- Made some internal methods in Enigma and TSRG readers actually private
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/net/fabricmc/mappingio/MappingReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,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.intellij.MigrationMapFileReader;
import net.fabricmc.mappingio.format.jobf.JobfFileReader;
import net.fabricmc.mappingio.format.proguard.ProGuardFileReader;
import net.fabricmc.mappingio.format.simple.RecafSimpleFileReader;
Expand Down Expand Up @@ -105,7 +106,9 @@ private static MappingFormat detectFormat(Reader reader, @Nullable String fileEx

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

if ((headerStr.startsWith("p ")
if (headerStr.contains("<migrationMap>")) {
return MappingFormat.INTELLIJ_MIGRATION_MAP_FILE;
} else if ((headerStr.startsWith("p ")
|| headerStr.startsWith("c ")
|| headerStr.startsWith("f ")
|| headerStr.startsWith("m "))
Expand Down Expand Up @@ -161,7 +164,7 @@ public static List<String> getNamespaces(Path file, MappingFormat format) throws
if (format == null) throw new IOException("invalid/unsupported mapping format");
}

if (format.hasNamespaces) {
if (format.features().hasNamespaces()) {
try (Reader reader = Files.newBufferedReader(file)) {
return getNamespaces(reader, format);
}
Expand All @@ -183,7 +186,7 @@ public static List<String> getNamespaces(Reader reader, MappingFormat format) th
if (format == null) throw new IOException("invalid/unsupported mapping format");
}

if (format.hasNamespaces) {
if (format.features().hasNamespaces()) {
checkReaderCompatible(format);

switch (format) {
Expand Down Expand Up @@ -296,6 +299,9 @@ public static void read(Reader reader, MappingFormat format, MappingVisitor visi
case PROGUARD_FILE:
ProGuardFileReader.read(reader, visitor);
break;
case INTELLIJ_MIGRATION_MAP_FILE:
MigrationMapFileReader.read(reader, visitor);
break;
case RECAF_SIMPLE_FILE:
RecafSimpleFileReader.read(reader, visitor);
break;
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 @@ -27,6 +27,7 @@
import net.fabricmc.mappingio.format.MappingFormat;
import net.fabricmc.mappingio.format.enigma.EnigmaDirWriter;
import net.fabricmc.mappingio.format.enigma.EnigmaFileWriter;
import net.fabricmc.mappingio.format.intellij.MigrationMapFileWriter;
import net.fabricmc.mappingio.format.jobf.JobfFileWriter;
import net.fabricmc.mappingio.format.proguard.ProGuardFileWriter;
import net.fabricmc.mappingio.format.simple.RecafSimpleFileWriter;
Expand Down Expand Up @@ -65,6 +66,7 @@ static MappingWriter create(Writer writer, MappingFormat format) throws IOExcept
case TSRG_FILE: return new TsrgFileWriter(writer, false);
case TSRG_2_FILE: return new TsrgFileWriter(writer, true);
case PROGUARD_FILE: return new ProGuardFileWriter(writer);
case INTELLIJ_MIGRATION_MAP_FILE: return new MigrationMapFileWriter(writer);
case RECAF_SIMPLE_FILE: return new RecafSimpleFileWriter(writer);
case JOBF_FILE: return new JobfFileWriter(writer);
default: return null;
Expand Down
67 changes: 41 additions & 26 deletions src/main/java/net/fabricmc/mappingio/format/ColumnFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
@ApiStatus.Internal
public final class ColumnFileReader implements Closeable {
public ColumnFileReader(Reader reader, char indentationChar, char columnSeparator) {
assert indentationChar != '\r';
assert indentationChar != '\n';
assert columnSeparator != '\r';
assert columnSeparator != '\n';

this.reader = reader;
this.indentationChar = indentationChar;
this.columnSeparator = columnSeparator;
Expand All @@ -51,7 +56,7 @@ public void close() throws IOException {
* @return {@code true} if the column was read and had the expected content, {@code false} otherwise.
*/
public boolean nextCol(String expected) throws IOException {
return read(false, false, true, expected) != noMatch;
return read(false, false, true, expected) != NO_MATCH;
}

/**
Expand Down Expand Up @@ -89,52 +94,45 @@ public String peekCol(boolean unescape) throws IOException {
* @param unescape Whether to unescape the read string.
* @param consume Whether to advance the bufferPos.
* @param stopAtNextCol Whether to only read one column.
* @param expected If not {@code null}, the read string must match this exactly, otherwise we early-exit with {@link #noMatch}. Always consumes if matched.
* @param expected If not {@code null}, the read string must match this exactly, otherwise we early-exit with {@link #NO_MATCH}. Always consumes if matched.
*
* @return {@code null} if nothing has been read (first char was EOL), otherwise the read string (may be empty).
* If {@code expected} is not {@code null}, it will be returned if matched, otherwise {@link #noMatch}.
* If {@code expected} is not {@code null}, it will be returned if matched, otherwise {@link #NO_MATCH}.
*/
@Nullable
private String read(boolean unescape, boolean consume, boolean stopAtNextCol, @Nullable String expected) throws IOException {
if (eol) return expected == null ? null : noMatch;
if (eol) return expected == null ? null : NO_MATCH;

int expectedLength = expected != null ? expected.length() : -1;

// Check if the buffer needs to be filled and if we hit EOF while doing so
if (expectedLength > 0 && bufferPos + expectedLength >= bufferLimit) {
if (!fillBuffer(expectedLength, !consume, false)) return noMatch;
if (!fillBuffer(expectedLength, !consume, false)) return NO_MATCH;
}

int start;
int end = this.bufferPos;
int firstEscaped = -1;
int contentCharsRead = 0;
int modifiedBufferPos = -1;
int startOffset = 0;
boolean readAnything = false;
boolean filled = true;
boolean isColumnSeparator = false;

readLoop: for (;;) {
while (end < bufferLimit) {
char c = buffer[end];
boolean isColumnSeparator = (c == columnSeparator);

// skip leading column separator
if (isColumnSeparator && !readAnything) {
startOffset = 1;
contentCharsRead = -1;
}

isColumnSeparator = (c == columnSeparator);
readAnything = true;

if (expected != null && contentCharsRead > -1) {
if (expected != null) {
if ((contentCharsRead < expectedLength && c != expected.charAt(contentCharsRead))
|| contentCharsRead > expectedLength) {
return noMatch;
return NO_MATCH;
}
}

if (c == '\n' || c == '\r' || (isColumnSeparator && stopAtNextCol && contentCharsRead > -1)) { // stop reading
if (c == '\n' || c == '\r' || (isColumnSeparator && stopAtNextCol)) { // stop reading
start = bufferPos;
modifiedBufferPos = end;

Expand Down Expand Up @@ -166,28 +164,36 @@ private String read(boolean unescape, boolean consume, boolean stopAtNextCol, @N
}
}

start += startOffset;
String ret;

if (expected != null) {
consume = true;
ret = expected;
} else {
int len = end - start;
int contentLength = end - start;

if (len == 0) {
if (contentLength == 0) {
ret = readAnything ? "" : null;
} else if (firstEscaped >= 0) {
ret = Tiny2Util.unescape(String.valueOf(buffer, start, len));
ret = Tiny2Util.unescape(String.valueOf(buffer, start, contentLength));
} else {
ret = String.valueOf(buffer, start, len);
ret = String.valueOf(buffer, start, contentLength);
}
}

if (consume) {
if (readAnything) bof = false;

if (modifiedBufferPos != -1) {
bufferPos = modifiedBufferPos;

// consume trailing column separator if present
if (isColumnSeparator && filled && fillBuffer(1, false, false)) {
bufferPos++;
}
}

if (!filled) eof = eol = true;
if (modifiedBufferPos != -1) bufferPos = modifiedBufferPos;

if (eol && !eof) { // manually check for EOF
int charsToRead = buffer[bufferPos] == '\r' ? 2 : 1; // 2 for \r\n, 1 for just \n
Expand Down Expand Up @@ -237,6 +243,15 @@ public int nextIntCol() throws IOException {
}
}

/**
* Read and consume until the the start of the next line is reached, and return whether the
* following {@code indent} characters match {@link #indentationChar}.
*
* <p>Empty lines are skipped if {@code indent} is 0.
*
* @param indent The number of characters to check for indentation.
* @return {@code true} if the next line has the specified indentation or higher, {@code false} otherwise.
*/
public boolean nextLine(int indent) throws IOException {
fillLoop: do {
while (bufferPos < bufferLimit) {
Expand All @@ -246,9 +261,9 @@ public boolean nextLine(int indent) throws IOException {
if (indent == 0) { // skip empty lines if indent is 0
if (!fillBuffer(2, false, true)) break fillLoop;

c = buffer[bufferPos + 1];
char next = buffer[bufferPos + 1];

if (c == '\n' || c == '\r') { // 2+ consecutive new lines, consume first nl and retry
if (next == '\n' || next == '\r') { // 2+ consecutive new lines, consume first nl and retry
bufferPos++;
lineNumber++;
bof = false;
Expand Down Expand Up @@ -428,7 +443,7 @@ private boolean fillBuffer(int count, boolean preventCompaction, boolean markEof
return true;
}

private static final String noMatch = new String();
private static final String NO_MATCH = new String();
private final Reader reader;
private final char indentationChar;
private final char columnSeparator;
Expand Down
101 changes: 101 additions & 0 deletions src/main/java/net/fabricmc/mappingio/format/FeatureSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2024 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;

public interface FeatureSet {
boolean hasNamespaces();
MetadataSupport fileMetadata();
MetadataSupport elementMetadata();
NameSupport packages();
NameSupport classes();
MemberSupport fields();
MemberSupport methods();
LocalSupport args();
LocalSupport vars();
ElementCommentSupport elementComments();
boolean hasFileComments();

default boolean supportsPackages() {
return packages().srcNames() != FeaturePresence.ABSENT
|| packages().dstNames() != FeaturePresence.ABSENT;
}

default boolean supportsClasses() {
return classes().srcNames() != FeaturePresence.ABSENT
|| classes().dstNames() != FeaturePresence.ABSENT;
}

default boolean supportsFields() {
return FeatureSetHelper.isSupported(fields());
}

default boolean supportsMethods() {
return FeatureSetHelper.isSupported(methods());
}

default boolean supportsArgs() {
return FeatureSetHelper.isSupported(args());
}

default boolean supportsVars() {
return FeatureSetHelper.isSupported(vars());
}

enum MetadataSupport {
/** No metadata at all. */
NONE,

/** Only some select properties. */
FIXED,

/** Arbitrary metadata may be attached. */
ARBITRARY
}

enum FeaturePresence {
REQUIRED,
OPTIONAL,
ABSENT
}

interface NameSupport {
FeaturePresence srcNames();
FeaturePresence dstNames();
}

interface DescSupport {
FeaturePresence srcDescs();
FeaturePresence dstDescs();
}

interface MemberSupport extends NameSupport, DescSupport {
}

interface LocalSupport extends NameSupport, DescSupport {
FeaturePresence positions();
FeaturePresence lvIndices();
FeaturePresence lvtRowIndices();
FeaturePresence startOpIndices();
FeaturePresence endOpIndices();
}

enum ElementCommentSupport {
NAMESPACED,
SHARED,
NONE
}
}
Loading

0 comments on commit 606f97e

Please sign in to comment.