diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 8b2c9ea0a..008296008 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { api(libs.fastutil) api(libs.flare) api(libs.flareFastutil) - api(libs.openNBT) + api(libs.nbt) api(libs.gson) compileOnlyApi(libs.snakeYaml) diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/BinaryTagIO.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/BinaryTagIO.java deleted file mode 100644 index 390518dee..000000000 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/BinaryTagIO.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * This file is part of adventure, licensed under the MIT License. - * - * Copyright (c) 2017-2020 KyoriPowered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.viaversion.viaversion.api.minecraft.nbt; - -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import java.io.BufferedInputStream; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; -import org.checkerframework.checker.nullness.qual.NonNull; - -// Specific Via changes: -// - Use OpenNBT tags -// - Added readString/writeString methods from TagStringIO -// - Has not been updated for the sake of keeping the class simple - -/** - * Serialization operations for binary tags. - */ -public final class BinaryTagIO { - private BinaryTagIO() { - } - - /** - * Reads a compound tag from {@code path}. - * - * @param path the path - * @return the compound tag - * @throws IOException if an exception was encountered while reading a compound tag - */ - public static @NonNull CompoundTag readPath(final @NonNull Path path) throws IOException { - return readInputStream(Files.newInputStream(path)); - } - - /** - * Reads a compound tag from an input stream. - * - * @param input the input stream - * @return the compound tag - * @throws IOException if an exception was encountered while reading a compound tag - */ - public static @NonNull CompoundTag readInputStream(final @NonNull InputStream input) throws IOException { - try (final DataInputStream dis = new DataInputStream(input)) { - return readDataInput(dis); - } - } - - /** - * Reads a compound tag from {@code path} using GZIP decompression. - * - * @param path the path - * @return the compound tag - * @throws IOException if an exception was encountered while reading a compound tag - */ - public static @NonNull CompoundTag readCompressedPath(final @NonNull Path path) throws IOException { - return readCompressedInputStream(Files.newInputStream(path)); - } - - /** - * Reads a compound tag from an input stream using GZIP decompression. - * - * @param input the input stream - * @return the compound tag - * @throws IOException if an exception was encountered while reading a compound tag - */ - public static @NonNull CompoundTag readCompressedInputStream(final @NonNull InputStream input) throws IOException { - try (final DataInputStream dis = new DataInputStream(new BufferedInputStream(new GZIPInputStream(input)))) { - return readDataInput(dis); - } - } - - /** - * Reads a compound tag from {@code input}. - * - * @param input the input - * @return the compound tag - * @throws IOException if an exception was encountered while reading a compound tag - */ - public static @NonNull CompoundTag readDataInput(final @NonNull DataInput input) throws IOException { - byte type = input.readByte(); - if (type != CompoundTag.ID) { - throw new IOException(String.format("Expected root tag to be a CompoundTag, was %s", type)); - } - input.skipBytes(input.readUnsignedShort()); // read empty name - - final CompoundTag compoundTag = new CompoundTag(); - compoundTag.read(input); - return compoundTag; - } - - /** - * Writes a compound tag to {@code path}. - * - * @param tag the compound tag - * @param path the path - * @throws IOException if an exception was encountered while writing the compound tag - */ - public static void writePath(final @NonNull CompoundTag tag, final @NonNull Path path) throws IOException { - writeOutputStream(tag, Files.newOutputStream(path)); - } - - /** - * Writes a compound tag to an output stream. - * - * @param tag the compound tag - * @param output the output stream - * @throws IOException if an exception was encountered while writing the compound tag - */ - public static void writeOutputStream(final @NonNull CompoundTag tag, final @NonNull OutputStream output) throws IOException { - try (final DataOutputStream dos = new DataOutputStream(output)) { - writeDataOutput(tag, dos); - } - } - - /** - * Writes a compound tag to {@code path} using GZIP compression. - * - * @param tag the compound tag - * @param path the path - * @throws IOException if an exception was encountered while writing the compound tag - */ - public static void writeCompressedPath(final @NonNull CompoundTag tag, final @NonNull Path path) throws IOException { - writeCompressedOutputStream(tag, Files.newOutputStream(path)); - } - - /** - * Writes a compound tag to an output stream using GZIP compression. - * - * @param tag the compound tag - * @param output the output stream - * @throws IOException if an exception was encountered while writing the compound tag - */ - public static void writeCompressedOutputStream(final @NonNull CompoundTag tag, final @NonNull OutputStream output) throws IOException { - try (final DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(output))) { - writeDataOutput(tag, dos); - } - } - - /** - * Writes a compound tag to {@code output}. - * - * @param tag the compound tag - * @param output the output - * @throws IOException if an exception was encountered while writing the compound tag - */ - public static void writeDataOutput(final @NonNull CompoundTag tag, final @NonNull DataOutput output) throws IOException { - output.writeByte(CompoundTag.ID); - output.writeUTF(""); // write empty name - tag.write(output); - } - - /** - * Reads a compound tag from a {@link String}. - * - * @param input the string - * @return the compound tag - * @throws IOException if an exception was encountered while reading a compound tag - */ - public static @NonNull CompoundTag readString(final @NonNull String input) throws IOException { - try { - final CharBuffer buffer = new CharBuffer(input); - final TagStringReader parser = new TagStringReader(buffer); - final CompoundTag tag = parser.compound(); - if (buffer.skipWhitespace().hasMore()) { - throw new IOException("Document had trailing content after first CompoundTag"); - } - return tag; - } catch (final StringTagParseException ex) { - throw new IOException(ex); - } - } - - /** - * Writes a compound tag to a {@link String}. - * - * @param tag the compound tag - * @return the string - * @throws IOException if an exception was encountered while writing the compound tag - */ - public static @NonNull String writeString(final @NonNull CompoundTag tag) throws IOException { - final StringBuilder sb = new StringBuilder(); - try (final TagStringWriter emit = new TagStringWriter(sb)) { - emit.writeTag(tag); - } - return sb.toString(); - } -} \ No newline at end of file diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/CharBuffer.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/CharBuffer.java deleted file mode 100644 index 83bf69a07..000000000 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/CharBuffer.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of adventure, licensed under the MIT License. - * - * Copyright (c) 2017-2021 KyoriPowered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.viaversion.viaversion.api.minecraft.nbt; - -/** - * A character buffer designed to be inspected by a parser. - */ -final class CharBuffer { - private final CharSequence sequence; - private int index; - - CharBuffer(final CharSequence sequence) { - this.sequence = sequence; - } - - /** - * Get the character at the current position. - * - * @return The current character - */ - public char peek() { - return this.sequence.charAt(this.index); - } - - public char peek(final int offset) { - return this.sequence.charAt(this.index + offset); - } - - /** - * Get the current character and advance. - * - * @return current character - */ - public char take() { - return this.sequence.charAt(this.index++); - } - - public boolean advance() { - this.index++; - return this.hasMore(); - } - - public boolean hasMore() { - return this.index < this.sequence.length(); - } - - public boolean hasMore(final int offset) { - return this.index + offset < this.sequence.length(); - } - - /** - * Search for the provided token, and advance the reader index past the {@code until} character. - * - * @param until Case-insensitive token - * @return the string starting at the current position (inclusive) and going until the location of {@code until}, exclusive - */ - public CharSequence takeUntil(char until) throws StringTagParseException { - until = Character.toLowerCase(until); - int endIdx = -1; - for (int idx = this.index; idx < this.sequence.length(); ++idx) { - if (this.sequence.charAt(idx) == Tokens.ESCAPE_MARKER) { - idx++; - } else if (Character.toLowerCase(this.sequence.charAt(idx)) == until) { - endIdx = idx; - break; - } - } - if (endIdx == -1) { - throw this.makeError("No occurrence of " + until + " was found"); - } - - final CharSequence result = this.sequence.subSequence(this.index, endIdx); - this.index = endIdx + 1; - return result; - } - - /** - * Assert that the next non-whitespace character is the provided parameter. - * - *
If the assertion is successful, the token will be consumed.
- * - * @param expectedChar expected character - * @return this - * @throws StringTagParseException if EOF or non-matching value is found - */ - public CharBuffer expect(final char expectedChar) throws StringTagParseException { - this.skipWhitespace(); - if (!this.hasMore()) { - throw this.makeError("Expected character '" + expectedChar + "' but got EOF"); - } - if (this.peek() != expectedChar) { - throw this.makeError("Expected character '" + expectedChar + "' but got '" + this.peek() + "'"); - } - this.take(); - return this; - } - - /** - * If the next non-whitespace character is {@code token}, advance past it. - * - *This method always consumes whitespace.
- * - * @param token next non-whitespace character to query - * @return if the next non-whitespace character is {@code token} - */ - public boolean takeIf(final char token) { - this.skipWhitespace(); - if (this.hasMore() && this.peek() == token) { - this.advance(); - return true; - } - return false; - } - - public CharBuffer skipWhitespace() { - while (this.hasMore() && Character.isWhitespace(this.peek())) this.advance(); - return this; - } - - public StringTagParseException makeError(final String message) { - return new StringTagParseException(message, this.sequence, this.index); - } -} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/StringTagParseException.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/StringTagParseException.java deleted file mode 100644 index 198086342..000000000 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/StringTagParseException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of adventure, licensed under the MIT License. - * - * Copyright (c) 2017-2020 KyoriPowered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.viaversion.viaversion.api.minecraft.nbt; - -import java.io.IOException; - -/** - * An exception thrown when parsing a string tag. - */ -class StringTagParseException extends IOException { - private static final long serialVersionUID = -3001637554903912905L; - private final CharSequence buffer; - private final int position; - - public StringTagParseException(final String message, final CharSequence buffer, final int position) { - super(message); - this.buffer = buffer; - this.position = position; - } - - @Override - public String getMessage() { - return super.getMessage() + "(at position " + this.position + ")"; - } -} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/TagStringReader.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/TagStringReader.java deleted file mode 100644 index 492a8ab92..000000000 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/TagStringReader.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * This file is part of adventure, licensed under the MIT License. - * - * Copyright (c) 2017-2021 KyoriPowered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.viaversion.viaversion.api.minecraft.nbt; - -import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.DoubleTag; -import com.github.steveice10.opennbt.tag.builtin.FloatTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; -import com.github.steveice10.opennbt.tag.builtin.NumberTag; -import com.github.steveice10.opennbt.tag.builtin.ShortTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import java.util.stream.IntStream; -import java.util.stream.LongStream; - -// Specific Via changes: -// - Use OpenNBT tags -// - Small byteArray() optimization -// - acceptLegacy = true by default -final class TagStringReader { - private static final int MAX_DEPTH = 512; - private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - private static final int[] EMPTY_INT_ARRAY = new int[0]; - private static final long[] EMPTY_LONG_ARRAY = new long[0]; - - private final CharBuffer buffer; - private boolean acceptLegacy = true; // Via - always true - private int depth; - - TagStringReader(final CharBuffer buffer) { - this.buffer = buffer; - } - - public CompoundTag compound() throws StringTagParseException { - this.buffer.expect(Tokens.COMPOUND_BEGIN); - final CompoundTag compoundTag = new CompoundTag(); - if (this.buffer.takeIf(Tokens.COMPOUND_END)) { - return compoundTag; - } - - while (this.buffer.hasMore()) { - compoundTag.put(this.key(), this.tag()); - if (this.separatorOrCompleteWith(Tokens.COMPOUND_END)) { - return compoundTag; - } - } - throw this.buffer.makeError("Unterminated compound tag!"); - } - - public ListTag list() throws StringTagParseException { - final ListTag listTag = new ListTag(); - this.buffer.expect(Tokens.ARRAY_BEGIN); - final boolean prefixedIndex = this.acceptLegacy && this.buffer.peek() == '0' && this.buffer.peek(1) == ':'; - if (!prefixedIndex && this.buffer.takeIf(Tokens.ARRAY_END)) { - return listTag; - } - while (this.buffer.hasMore()) { - if (prefixedIndex) { - this.buffer.takeUntil(':'); - } - - final Tag next = this.tag(); - listTag.add(next); - if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) { - return listTag; - } - } - throw this.buffer.makeError("Reached end of file without end of list tag!"); - } - - /** - * Similar to a list tag in syntax, but returning a single array tag rather than a list of tags. - * - * @return array-typed tag - */ - public Tag array(char elementType) throws StringTagParseException { - this.buffer.expect(Tokens.ARRAY_BEGIN) - .expect(elementType) - .expect(Tokens.ARRAY_SIGNATURE_SEPARATOR); - - elementType = Character.toLowerCase(elementType); - if (elementType == Tokens.TYPE_BYTE) { - return new ByteArrayTag(this.byteArray()); - } else if (elementType == Tokens.TYPE_INT) { - return new IntArrayTag(this.intArray()); - } else if (elementType == Tokens.TYPE_LONG) { - return new LongArrayTag(this.longArray()); - } else { - throw this.buffer.makeError("Type " + elementType + " is not a valid element type in an array!"); - } - } - - private byte[] byteArray() throws StringTagParseException { - if (this.buffer.takeIf(Tokens.ARRAY_END)) { - return EMPTY_BYTE_ARRAY; - } - - final IntList bytes = new IntArrayList(); // Via - no boxing - while (this.buffer.hasMore()) { - final CharSequence value = this.buffer.skipWhitespace().takeUntil(Tokens.TYPE_BYTE); - try { - bytes.add(Byte.parseByte(value.toString())); // Via - } catch (final NumberFormatException ex) { - throw this.buffer.makeError("All elements of a byte array must be bytes!"); - } - - if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) { - final byte[] result = new byte[bytes.size()]; - for (int i = 0; i < bytes.size(); ++i) { - result[i] = (byte) bytes.getInt(i); // Via - } - return result; - } - } - throw this.buffer.makeError("Reached end of document without array close"); - } - - private int[] intArray() throws StringTagParseException { - if (this.buffer.takeIf(Tokens.ARRAY_END)) { - return EMPTY_INT_ARRAY; - } - - final IntStream.Builder builder = IntStream.builder(); - while (this.buffer.hasMore()) { - final Tag value = this.tag(); - if (!(value instanceof IntTag)) { - throw this.buffer.makeError("All elements of an int array must be ints!"); - } - builder.add(((NumberTag) value).asInt()); - if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) { - return builder.build().toArray(); - } - } - throw this.buffer.makeError("Reached end of document without array close"); - } - - private long[] longArray() throws StringTagParseException { - if (this.buffer.takeIf(Tokens.ARRAY_END)) { - return EMPTY_LONG_ARRAY; - } - - final LongStream.Builder longs = LongStream.builder(); - while (this.buffer.hasMore()) { - final CharSequence value = this.buffer.skipWhitespace().takeUntil(Tokens.TYPE_LONG); - try { - longs.add(Long.parseLong(value.toString())); - } catch (final NumberFormatException ex) { - throw this.buffer.makeError("All elements of a long array must be longs!"); - } - - if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) { - return longs.build().toArray(); - } - } - throw this.buffer.makeError("Reached end of document without array close"); - } - - public String key() throws StringTagParseException { - this.buffer.skipWhitespace(); - final char starChar = this.buffer.peek(); - try { - if (starChar == Tokens.SINGLE_QUOTE || starChar == Tokens.DOUBLE_QUOTE) { - return unescape(this.buffer.takeUntil(this.buffer.take()).toString()); - } - - final StringBuilder builder = new StringBuilder(); - while (this.buffer.hasMore()) { - final char peek = this.buffer.peek(); - if (!Tokens.id(peek)) { - if (this.acceptLegacy) { - // In legacy format, a key is any non-colon character, with escapes allowed - if (peek == Tokens.ESCAPE_MARKER) { - this.buffer.take(); // skip - continue; - } else if (peek != Tokens.COMPOUND_KEY_TERMINATOR) { - builder.append(this.buffer.take()); - continue; - } - } - break; - } - builder.append(this.buffer.take()); - } - return builder.toString(); - } finally { - this.buffer.expect(Tokens.COMPOUND_KEY_TERMINATOR); - } - } - - public Tag tag() throws StringTagParseException { - if (this.depth++ > MAX_DEPTH) { - throw this.buffer.makeError("Exceeded maximum allowed depth of " + MAX_DEPTH + " when reading tag"); - } - try { - final char startToken = this.buffer.skipWhitespace().peek(); - switch (startToken) { - case Tokens.COMPOUND_BEGIN: - return this.compound(); - case Tokens.ARRAY_BEGIN: - // Maybe add in a legacy-only mode to read those? - if (this.buffer.hasMore(2) && this.buffer.peek(2) == ';') { // we know we're an array tag - return this.array(this.buffer.peek(1)); - } else { - return this.list(); - } - case Tokens.SINGLE_QUOTE: - case Tokens.DOUBLE_QUOTE: - // definitely a string tag - this.buffer.advance(); - return new StringTag(unescape(this.buffer.takeUntil(startToken).toString())); - default: // scalar - return this.scalar(); - } - } finally { - this.depth--; - } - } - - /** - * A tag that is definitely some sort of scalar. - * - *Does not detect quoted strings, so those should have been parsed already.
- * - * @return a parsed tag - */ - private Tag scalar() { - final StringBuilder builder = new StringBuilder(); - int noLongerNumericAt = -1; - while (this.buffer.hasMore()) { - char current = this.buffer.peek(); - if (current == '\\') { // escape -- we are significantly more lenient than original format at the moment - this.buffer.advance(); - current = this.buffer.take(); - } else if (Tokens.id(current)) { - this.buffer.advance(); - } else { // end of value - break; - } - builder.append(current); - if (noLongerNumericAt == -1 && !Tokens.numeric(current)) { - noLongerNumericAt = builder.length(); - } - } - - final int length = builder.length(); - final String built = builder.toString(); - if (noLongerNumericAt == length) { - final char last = built.charAt(length - 1); - try { - switch (Character.toLowerCase(last)) { // try to read and return as a number - case Tokens.TYPE_BYTE: - return new ByteTag(Byte.parseByte(built.substring(0, length - 1))); - case Tokens.TYPE_SHORT: - return new ShortTag(Short.parseShort(built.substring(0, length - 1))); - case Tokens.TYPE_INT: - return new IntTag(Integer.parseInt(built.substring(0, length - 1))); - case Tokens.TYPE_LONG: - return new LongTag(Long.parseLong(built.substring(0, length - 1))); - case Tokens.TYPE_FLOAT: - final float floatValue = Float.parseFloat(built.substring(0, length - 1)); - if (Float.isFinite(floatValue)) { // don't accept NaN and Infinity - return new FloatTag(floatValue); - } - break; - case Tokens.TYPE_DOUBLE: - final double doubleValue = Double.parseDouble(built.substring(0, length - 1)); - if (Double.isFinite(doubleValue)) { // don't accept NaN and Infinity - return new DoubleTag(doubleValue); - } - break; - } - } catch (final NumberFormatException ignored) { - } - } else if (noLongerNumericAt == -1) { // if we run out of content without an explicit value separator, then we're either an integer or string tag -- all others have a character at the end - try { - return new IntTag(Integer.parseInt(built)); - } catch (final NumberFormatException ex) { - if (built.indexOf('.') != -1) { - try { - return new DoubleTag(Double.parseDouble(built)); - } catch (final NumberFormatException ex2) { - // ignore - } - } - } - } - - if (built.equalsIgnoreCase(Tokens.LITERAL_TRUE)) { - return new ByteTag((byte) 1); - } else if (built.equalsIgnoreCase(Tokens.LITERAL_FALSE)) { - return new ByteTag((byte) 0); - } - return new StringTag(built); - - } - - private boolean separatorOrCompleteWith(final char endCharacter) throws StringTagParseException { - if (this.buffer.takeIf(endCharacter)) { - return true; - } - this.buffer.expect(Tokens.VALUE_SEPARATOR); - return this.buffer.takeIf(endCharacter); - } - - /** - * Remove simple escape sequences from a string. - * - * @param withEscapes input string with escapes - * @return string with escapes processed - */ - private static String unescape(final String withEscapes) { - int escapeIdx = withEscapes.indexOf(Tokens.ESCAPE_MARKER); - if (escapeIdx == -1) { // nothing to unescape - return withEscapes; - } - int lastEscape = 0; - final StringBuilder output = new StringBuilder(withEscapes.length()); - do { - output.append(withEscapes, lastEscape, escapeIdx); - lastEscape = escapeIdx + 1; - } while ((escapeIdx = withEscapes.indexOf(Tokens.ESCAPE_MARKER, lastEscape + 1)) != -1); // add one extra character to make sure we don't include escaped backslashes - output.append(withEscapes.substring(lastEscape)); - return output.toString(); - } - - public void legacy(final boolean acceptLegacy) { - this.acceptLegacy = acceptLegacy; - } -} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/TagStringWriter.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/TagStringWriter.java deleted file mode 100644 index 889ce63c2..000000000 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/nbt/TagStringWriter.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * This file is part of adventure, licensed under the MIT License. - * - * Copyright (c) 2017-2020 KyoriPowered - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.viaversion.viaversion.api.minecraft.nbt; - -import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; -import com.github.steveice10.opennbt.tag.builtin.ByteTag; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.DoubleTag; -import com.github.steveice10.opennbt.tag.builtin.FloatTag; -import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; -import com.github.steveice10.opennbt.tag.builtin.LongTag; -import com.github.steveice10.opennbt.tag.builtin.NumberTag; -import com.github.steveice10.opennbt.tag.builtin.ShortTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import java.io.IOException; -import java.io.Writer; -import java.util.Map; - -// Specific Via changes: -// - Use OpenNBT tags -// - Has not been updated to support pretty printing and legacy writing since that is not needed - -/** - * An emitter for the SNBT format. - * - *Details on the format are described in the package documentation.
- */ -final class TagStringWriter implements AutoCloseable { - private final Appendable out; - private int level; - /** - * Whether a {@link Tokens#VALUE_SEPARATOR} needs to be printed before the beginning of the next object. - */ - private boolean needsSeparator; - - public TagStringWriter(final Appendable out) { - this.out = out; - } - - // NBT-specific - - public TagStringWriter writeTag(final Tag tag) throws IOException { - if (tag instanceof CompoundTag) { - return this.writeCompound((CompoundTag) tag); - } else if (tag instanceof ListTag) { - return this.writeList((ListTag) tag); - } else if (tag instanceof ByteArrayTag) { - return this.writeByteArray((ByteArrayTag) tag); - } else if (tag instanceof IntArrayTag) { - return this.writeIntArray((IntArrayTag) tag); - } else if (tag instanceof LongArrayTag) { - return this.writeLongArray((LongArrayTag) tag); - } else if (tag instanceof StringTag) { - return this.value(((StringTag) tag).getValue(), Tokens.EOF); - } else if (tag instanceof ByteTag) { - return this.value(Byte.toString(((NumberTag) tag).asByte()), Tokens.TYPE_BYTE); - } else if (tag instanceof ShortTag) { - return this.value(Short.toString(((NumberTag) tag).asShort()), Tokens.TYPE_SHORT); - } else if (tag instanceof IntTag) { - return this.value(Integer.toString(((NumberTag) tag).asInt()), Tokens.TYPE_INT); - } else if (tag instanceof LongTag) { - return this.value(Long.toString(((NumberTag) tag).asLong()), Character.toUpperCase(Tokens.TYPE_LONG)); // special case - } else if (tag instanceof FloatTag) { - return this.value(Float.toString(((NumberTag) tag).asFloat()), Tokens.TYPE_FLOAT); - } else if (tag instanceof DoubleTag) { - return this.value(Double.toString(((NumberTag) tag).asDouble()), Tokens.TYPE_DOUBLE); - } else { - throw new IOException("Unknown tag type: " + tag.getClass().getSimpleName()); - // unknown! - } - } - - private TagStringWriter writeCompound(final CompoundTag tag) throws IOException { - this.beginCompound(); - for (final Map.EntryAn identifier character must match the expression {@code [a-zA-Z0-9_+.-]}
- * - * @param c the character - * @return identifier - */ - static boolean id(final char c) { - return (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || c == '-' || c == '_' - || c == '.' || c == '+'; - } - - /** - * Return whether a character could be at some position in a number. - * - *A string passing this check does not necessarily mean it is syntactically valid.
- * - * @param c character to check - * @return if possibly part of a number - */ - static boolean numeric(final char c) { - return (c >= '0' && c <= '9') // digit - || c == '+' || c == '-' // positive or negative - || c == 'e' || c == 'E' // exponent - || c == '.'; // decimal - } -} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/data/ComponentRewriter1_13.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/data/ComponentRewriter1_13.java index ac8ef49cb..7470ce420 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/data/ComponentRewriter1_13.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/data/ComponentRewriter1_13.java @@ -17,6 +17,7 @@ */ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data; +import com.github.steveice10.opennbt.stringified.SNBT; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.NumberTag; import com.github.steveice10.opennbt.tag.builtin.ShortTag; @@ -27,12 +28,10 @@ import com.google.gson.JsonPrimitive; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.minecraft.item.Item; -import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2; import com.viaversion.viaversion.rewriter.ComponentRewriter; -import java.io.IOException; public class ComponentRewriter1_13