From 63c109efdefb11611b918dad29a64b5e0a4a3971 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 8 Oct 2023 16:16:44 +1000 Subject: [PATCH] 3.0.0 Release - More general refactoring - Add SNBT serializer - Rebrand to ViaNBT, as the project has shifted greatly from the original Package rename will follow at a (much) later date when ViaVersion is ready for another major version bump --- README.md | 50 ++- pom.xml | 13 +- .../com/github/steveice10/opennbt/NBTIO.java | 9 +- .../ConverterRegisterException.java | 24 -- .../opennbt/conversion/ConverterRegistry.java | 120 +++--- .../opennbt/conversion/TagConverter.java | 4 +- .../ByteArrayTagConverter.java | 2 +- .../ByteTagConverter.java | 2 +- .../CompoundTagConverter.java | 2 +- .../DoubleTagConverter.java | 2 +- .../FloatTagConverter.java | 2 +- .../IntArrayTagConverter.java | 2 +- .../IntTagConverter.java | 2 +- .../ListTagConverter.java | 2 +- .../LongArrayTagConverter.java | 2 +- .../LongTagConverter.java | 2 +- .../ShortTagConverter.java | 2 +- .../StringTagConverter.java | 2 +- .../opennbt/stringified/CharBuffer.java | 148 ++++++++ .../steveice10/opennbt/stringified/SNBT.java | 54 +++ .../StringifiedTagParseException.java | 52 +++ .../opennbt/stringified/TagStringReader.java | 358 ++++++++++++++++++ .../opennbt/stringified/TagStringWriter.java | 244 ++++++++++++ .../opennbt/stringified/Tokens.java | 89 +++++ .../opennbt/tag/TagCreateException.java | 24 -- .../opennbt/tag/TagRegisterException.java | 24 -- .../steveice10/opennbt/tag/TagRegistry.java | 54 +-- .../opennbt/tag/builtin/CompoundTag.java | 3 - .../opennbt/tag/builtin/ListTag.java | 3 +- .../steveice10/opennbt/tag/builtin/Tag.java | 34 +- .../opennbt/tag/limiter/TagLimiter.java | 12 +- 31 files changed, 1105 insertions(+), 238 deletions(-) delete mode 100644 src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegisterException.java rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/ByteArrayTagConverter.java (89%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/ByteTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/CompoundTagConverter.java (94%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/DoubleTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/FloatTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/IntArrayTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/IntTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/ListTagConverter.java (94%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/LongArrayTagConverter.java (89%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/LongTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/ShortTagConverter.java (88%) rename src/main/java/com/github/steveice10/opennbt/conversion/{builtin => converter}/StringTagConverter.java (88%) create mode 100644 src/main/java/com/github/steveice10/opennbt/stringified/CharBuffer.java create mode 100644 src/main/java/com/github/steveice10/opennbt/stringified/SNBT.java create mode 100644 src/main/java/com/github/steveice10/opennbt/stringified/StringifiedTagParseException.java create mode 100644 src/main/java/com/github/steveice10/opennbt/stringified/TagStringReader.java create mode 100644 src/main/java/com/github/steveice10/opennbt/stringified/TagStringWriter.java create mode 100644 src/main/java/com/github/steveice10/opennbt/stringified/Tokens.java delete mode 100644 src/main/java/com/github/steveice10/opennbt/tag/TagCreateException.java delete mode 100644 src/main/java/com/github/steveice10/opennbt/tag/TagRegisterException.java diff --git a/README.md b/README.md index c679b46..f48e8a8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -# OpenNBT -OpenNBT is a library for reading and writing NBT files, with some extra custom tags added to allow the storage of more data types. +# ViaNBT + +ViaNBT is a library for dealing with [NBT](https://minecraft.wiki/w/NBT_format) and SNBT. + +This project is derived from an earlier version of [OpenNBT](https://github.com/GeyserMC/OpenNBT/) and contains various fundamental improvements and changes to it, including: -This fork contains various improvements and changes specifically made for use in Via plugins, including but not limited to the following list: * Most notably, move the tag name out the of tags themselves +* `SNBT` for string serialization * Add primitive getter methods to number types * Don't wrap values given in Tag#setValue / Tag constructors * Abstract NumberTag class for easier number handling @@ -12,8 +15,43 @@ This fork contains various improvements and changes specifically made for use in * Implement tag specific equals() methods * Update to Java 8 -## Building the Source -OpenNBT uses Maven to manage dependencies. Simply run 'mvn clean install' in the source's directory. +This project also includes code from [adventure](https://github.com/KyoriPowered/adventure) used for SNBT serialization. + +## Dependency + +**Maven:** + +```xml + + viaversion-repo + https://repo.viaversion.com + +``` + +```xml + + com.viaversion + nbt + 3.0.0 + +``` + +**Gradle:** + +```kotlin +repositories { + maven("https://repo.viaversion.com") +} + +dependencies { + implementation("com.viaversion:nbt:3.0.0") +} +``` + +## Building + +Run `mvn install` in the source's directory via Maven. ## License -OpenNBT is licensed under the **[MIT license](http://www.opensource.org/licenses/mit-license.html)**. + +ViaNBT is licensed under the **[MIT license](http://www.opensource.org/licenses/mit-license.html)**. diff --git a/pom.xml b/pom.xml index be2804d..7cbe020 100644 --- a/pom.xml +++ b/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.viaversion - opennbt - 2.1.3 + nbt + 3.0.0 jar - OpenNBT + ViaNBT A library for reading and writing NBT files, written in Java. - https://github.com/ViaVersion/OpenNBT + https://github.com/ViaVersion/ViaNBT @@ -52,6 +52,7 @@ + it.unimi.dsi fastutil @@ -61,7 +62,7 @@ org.jetbrains annotations - 24.0.0 + 24.0.1 provided @@ -90,7 +91,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.2.1 attach-sources diff --git a/src/main/java/com/github/steveice10/opennbt/NBTIO.java b/src/main/java/com/github/steveice10/opennbt/NBTIO.java index d012c38..1619f19 100644 --- a/src/main/java/com/github/steveice10/opennbt/NBTIO.java +++ b/src/main/java/com/github/steveice10/opennbt/NBTIO.java @@ -74,12 +74,7 @@ public final class NBTIO { in = new GZIPInputStream(in); } - CompoundTag tag = readTag(in, littleEndian); - if (!(tag instanceof CompoundTag)) { - throw new IOException("Root tag is not a CompoundTag!"); - } - - return tag; + return readTag(in, littleEndian); } finally { in.close(); } @@ -131,7 +126,7 @@ public final class NBTIO { */ public static void writeFile(CompoundTag tag, File file, boolean compressed, boolean littleEndian) throws IOException { if (!file.exists()) { - if (file.getParentFile() != null && !file.getParentFile().exists()) { + if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegisterException.java b/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegisterException.java deleted file mode 100644 index a71b675..0000000 --- a/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegisterException.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.github.steveice10.opennbt.conversion; - -/** - * An exception thrown when an error occurs while registering a converter. - */ -public class ConverterRegisterException extends RuntimeException { - private static final long serialVersionUID = -2022049594558041160L; - - public ConverterRegisterException() { - super(); - } - - public ConverterRegisterException(String message) { - super(message); - } - - public ConverterRegisterException(Throwable cause) { - super(cause); - } - - public ConverterRegisterException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegistry.java b/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegistry.java index 6613fa0..7622c34 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegistry.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/ConverterRegistry.java @@ -1,17 +1,18 @@ package com.github.steveice10.opennbt.conversion; -import com.github.steveice10.opennbt.conversion.builtin.ByteArrayTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.ByteTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.CompoundTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.DoubleTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.FloatTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.IntArrayTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.IntTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.ListTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.LongArrayTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.LongTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.ShortTagConverter; -import com.github.steveice10.opennbt.conversion.builtin.StringTagConverter; +import com.github.steveice10.opennbt.conversion.converter.ByteArrayTagConverter; +import com.github.steveice10.opennbt.conversion.converter.ByteTagConverter; +import com.github.steveice10.opennbt.conversion.converter.CompoundTagConverter; +import com.github.steveice10.opennbt.conversion.converter.DoubleTagConverter; +import com.github.steveice10.opennbt.conversion.converter.FloatTagConverter; +import com.github.steveice10.opennbt.conversion.converter.IntArrayTagConverter; +import com.github.steveice10.opennbt.conversion.converter.IntTagConverter; +import com.github.steveice10.opennbt.conversion.converter.ListTagConverter; +import com.github.steveice10.opennbt.conversion.converter.LongArrayTagConverter; +import com.github.steveice10.opennbt.conversion.converter.LongTagConverter; +import com.github.steveice10.opennbt.conversion.converter.ShortTagConverter; +import com.github.steveice10.opennbt.conversion.converter.StringTagConverter; +import com.github.steveice10.opennbt.tag.TagRegistry; import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; @@ -25,20 +26,19 @@ import com.github.steveice10.opennbt.tag.builtin.LongTag; 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.Serializable; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; +import org.jetbrains.annotations.Nullable; /** * A registry mapping tags and value types to converters. */ public class ConverterRegistry { - private static final Map, TagConverter> tagToConverter = new HashMap, TagConverter>(); - private static final Map, TagConverter> typeToConverter = new HashMap, TagConverter>(); + private static final Int2ObjectMap> TAG_TO_CONVERTER = new Int2ObjectOpenHashMap<>(); + private static final Map, TagConverter> TYPE_TO_CONVERTER = new HashMap<>(); static { register(ByteTag.class, Byte.class, new ByteTagConverter()); @@ -63,19 +63,22 @@ public class ConverterRegistry { * @param tag Tag type class to register the converter to. * @param type Value type class to register the converter to. * @param converter Converter to register. - * @throws ConverterRegisterException If an error occurs while registering the converter. + * @throws IllegalArgumentException if the tag or type are already registered */ - public static void register(Class tag, Class type, TagConverter converter) throws ConverterRegisterException { - if (tagToConverter.containsKey(tag)) { - throw new ConverterRegisterException("Type conversion to tag " + tag.getName() + " is already registered."); + public static void register(Class tag, Class type, TagConverter converter) { + int tagId = TagRegistry.getIdFor(tag); + if (tagId == -1) { + throw new IllegalArgumentException("Tag " + tag.getName() + " is not a registered tag."); + } + if (TAG_TO_CONVERTER.containsKey(tagId)) { + throw new IllegalArgumentException("Type conversion to tag " + tag.getName() + " is already registered."); + } + if (TYPE_TO_CONVERTER.containsKey(type)) { + throw new IllegalArgumentException("Tag conversion to type " + type.getName() + " is already registered."); } - if (typeToConverter.containsKey(type)) { - throw new ConverterRegisterException("Tag conversion to type " + type.getName() + " is already registered."); - } - - tagToConverter.put(tag, converter); - typeToConverter.put(type, converter); + TAG_TO_CONVERTER.put(tagId, converter); + TYPE_TO_CONVERTER.put(type, converter); } /** @@ -87,8 +90,8 @@ public class ConverterRegistry { * @param type Value type class to unregister. */ public static void unregister(Class tag, Class type) { - tagToConverter.remove(tag); - typeToConverter.remove(type); + TAG_TO_CONVERTER.remove(TagRegistry.getIdFor(tag)); + TYPE_TO_CONVERTER.remove(type); } /** @@ -100,17 +103,17 @@ public class ConverterRegistry { * @return The converted value. * @throws ConversionException If a suitable converter could not be found. */ - public static V convertToValue(T tag) throws ConversionException { + public static @Nullable V convertToValue(@Nullable T tag) throws ConversionException { if (tag == null || tag.getValue() == null) { return null; } - if (!tagToConverter.containsKey(tag.getClass())) { + TagConverter converter = (TagConverter) TAG_TO_CONVERTER.get(tag.getClass()); + if (converter == null) { throw new ConversionException("Tag type " + tag.getClass().getName() + " has no converter."); } - TagConverter converter = (TagConverter) tagToConverter.get(tag.getClass()); - return (V) converter.convert(tag); + return converter.convert(tag); } /** @@ -122,56 +125,19 @@ public class ConverterRegistry { * @return The converted tag. * @throws ConversionException If a suitable converter could not be found. */ - public static T convertToTag(V value) throws ConversionException { + public static @Nullable T convertToTag(@Nullable V value) throws ConversionException { if (value == null) { return null; } - TagConverter converter = (TagConverter) typeToConverter.get(value.getClass()); + // No need to check super classes since registering custom tags is not allowed + // and all the given ones cannot be extended, super class can't be instantiated + Class valueClass = value.getClass(); + TagConverter converter = (TagConverter) TYPE_TO_CONVERTER.get(valueClass); if (converter == null) { - for (Class clazz : getAllClasses(value.getClass())) { - if (typeToConverter.containsKey(clazz)) { - try { - converter = (TagConverter) typeToConverter.get(clazz); - break; - } catch (ClassCastException e) { - } - } - } - } - - if (converter == null) { - throw new ConversionException("Value type " + value.getClass().getName() + " has no converter."); + throw new ConversionException("Value type " + valueClass.getName() + " has no converter."); } return converter.convert(value); } - - private static Set> getAllClasses(Class clazz) { - Set> ret = new LinkedHashSet>(); - Class c = clazz; - while (c != null) { - ret.add(c); - ret.addAll(getAllSuperInterfaces(c)); - c = c.getSuperclass(); - } - - // Make sure Serializable is at the end to avoid mix-ups. - if (ret.contains(Serializable.class)) { - ret.remove(Serializable.class); - ret.add(Serializable.class); - } - - return ret; - } - - private static Set> getAllSuperInterfaces(Class clazz) { - Set> ret = new HashSet>(); - for (Class c : clazz.getInterfaces()) { - ret.add(c); - ret.addAll(getAllSuperInterfaces(c)); - } - - return ret; - } } diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/TagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/TagConverter.java index df56287..80f147e 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/TagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/TagConverter.java @@ -15,7 +15,7 @@ public interface TagConverter { * @param tag Tag to convert. * @return The converted value. */ - public V convert(T tag); + V convert(T tag); /** * Converts a value to a tag. @@ -23,5 +23,5 @@ public interface TagConverter { * @param value Value to convert. * @return The converted tag. */ - public T convert(V value); + T convert(V value); } diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteArrayTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ByteArrayTagConverter.java similarity index 89% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteArrayTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/ByteArrayTagConverter.java index 9b347de..48f47ed 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteArrayTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ByteArrayTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ByteTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/ByteTagConverter.java index 8df9610..eebe0f9 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ByteTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ByteTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.ByteTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/CompoundTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/CompoundTagConverter.java similarity index 94% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/CompoundTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/CompoundTagConverter.java index fba0dd1..1c834f4 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/CompoundTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/CompoundTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.ConverterRegistry; import com.github.steveice10.opennbt.conversion.TagConverter; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/DoubleTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/DoubleTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/DoubleTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/DoubleTagConverter.java index bec1bdd..0d2a87b 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/DoubleTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/DoubleTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.DoubleTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/FloatTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/FloatTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/FloatTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/FloatTagConverter.java index 2e4c57d..b81746d 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/FloatTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/FloatTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.FloatTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntArrayTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/IntArrayTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntArrayTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/IntArrayTagConverter.java index 64f7fd9..0d3f708 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntArrayTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/IntArrayTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/IntTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/IntTagConverter.java index de9f749..51a65e0 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/IntTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/IntTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.IntTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ListTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ListTagConverter.java similarity index 94% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/ListTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/ListTagConverter.java index 785d90f..bd1c010 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ListTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ListTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.ConverterRegistry; import com.github.steveice10.opennbt.conversion.TagConverter; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongArrayTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/LongArrayTagConverter.java similarity index 89% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongArrayTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/LongArrayTagConverter.java index 5959117..519e832 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongArrayTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/LongArrayTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/LongTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/LongTagConverter.java index ed800a4..6c33a71 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/LongTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/LongTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.LongTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ShortTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ShortTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/ShortTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/ShortTagConverter.java index 6063d2e..7edb9af 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/ShortTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/ShortTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.ShortTag; diff --git a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/StringTagConverter.java b/src/main/java/com/github/steveice10/opennbt/conversion/converter/StringTagConverter.java similarity index 88% rename from src/main/java/com/github/steveice10/opennbt/conversion/builtin/StringTagConverter.java rename to src/main/java/com/github/steveice10/opennbt/conversion/converter/StringTagConverter.java index 42080c4..8e6859b 100644 --- a/src/main/java/com/github/steveice10/opennbt/conversion/builtin/StringTagConverter.java +++ b/src/main/java/com/github/steveice10/opennbt/conversion/converter/StringTagConverter.java @@ -1,4 +1,4 @@ -package com.github.steveice10.opennbt.conversion.builtin; +package com.github.steveice10.opennbt.conversion.converter; import com.github.steveice10.opennbt.conversion.TagConverter; import com.github.steveice10.opennbt.tag.builtin.StringTag; diff --git a/src/main/java/com/github/steveice10/opennbt/stringified/CharBuffer.java b/src/main/java/com/github/steveice10/opennbt/stringified/CharBuffer.java new file mode 100644 index 0000000..083325e --- /dev/null +++ b/src/main/java/com/github/steveice10/opennbt/stringified/CharBuffer.java @@ -0,0 +1,148 @@ +/* + * 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.github.steveice10.opennbt.stringified; + +/** + * 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 StringifiedTagParseException { + 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 StringifiedTagParseException if EOF or non-matching value is found + */ + public CharBuffer expect(final char expectedChar) throws StringifiedTagParseException { + 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 int index() { + return this.index; + } + + public CharBuffer skipWhitespace() { + while (this.hasMore() && Character.isWhitespace(this.peek())) this.advance(); + return this; + } + + public StringifiedTagParseException makeError(final String message) { + return new StringifiedTagParseException(message, this.index); + } +} diff --git a/src/main/java/com/github/steveice10/opennbt/stringified/SNBT.java b/src/main/java/com/github/steveice10/opennbt/stringified/SNBT.java new file mode 100644 index 0000000..58ad0c6 --- /dev/null +++ b/src/main/java/com/github/steveice10/opennbt/stringified/SNBT.java @@ -0,0 +1,54 @@ +package com.github.steveice10.opennbt.stringified; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; + +/** + * Serialization of stringifies tags. + */ +public final class SNBT { + + private SNBT() { + } + + /** + * Reads a compound tag from a {@link String}. + * + * @param snbt SNBT input + * @return compound tag from the given SNBT input + * @throws StringifiedTagParseException if an exception was encountered while reading a compound tag + */ + public static Tag deserialize(final String snbt) { + final CharBuffer buffer = new CharBuffer(snbt); + final TagStringReader parser = new TagStringReader(buffer); + final Tag tag = parser.tag(); + if (buffer.skipWhitespace().hasMore()) { + throw new StringifiedTagParseException("Input has trailing content", buffer.index()); + } + return tag; + } + + public static CompoundTag deserializeCompoundTag(final String snbt) { + final CharBuffer buffer = new CharBuffer(snbt); + final TagStringReader reader = new TagStringReader(buffer); + final CompoundTag tag = reader.compound(); + if (buffer.skipWhitespace().hasMore()) { + throw new StringifiedTagParseException("Input has trailing content", buffer.index()); + } + return tag; + } + + /** + * Serializes a tag to SNBT. + * + * @param tag the compound tag + * @return serialized SNBT + * @throws IllegalArgumentException if an unknown tag is provided + */ + public static String serialize(final Tag tag) { + final StringBuilder builder = new StringBuilder(); + final TagStringWriter writer = new TagStringWriter(builder); + writer.writeTag(tag); + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/steveice10/opennbt/stringified/StringifiedTagParseException.java b/src/main/java/com/github/steveice10/opennbt/stringified/StringifiedTagParseException.java new file mode 100644 index 0000000..b66a2e6 --- /dev/null +++ b/src/main/java/com/github/steveice10/opennbt/stringified/StringifiedTagParseException.java @@ -0,0 +1,52 @@ +/* + * 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.github.steveice10.opennbt.stringified; + +// Specific Via changes: +// - Remove buffer field +// - Make public +// - Make unchecked +// - Rename to Stringified + +/** + * An exception thrown when parsing a stringified binary tag. + */ +public final class StringifiedTagParseException extends RuntimeException { + private static final long serialVersionUID = -3001637514903912905L; + private final int position; + + public StringifiedTagParseException(final String message, final int position) { + super(message); + this.position = position; + } + + @Override + public String getMessage() { + return super.getMessage() + "(at position " + this.position + ")"; + } + + public int getPosition() { + return position; + } +} diff --git a/src/main/java/com/github/steveice10/opennbt/stringified/TagStringReader.java b/src/main/java/com/github/steveice10/opennbt/stringified/TagStringReader.java new file mode 100644 index 0000000..80d9c4d --- /dev/null +++ b/src/main/java/com/github/steveice10/opennbt/stringified/TagStringReader.java @@ -0,0 +1,358 @@ +/* + * 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.github.steveice10.opennbt.stringified; + +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 ViaNBT 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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 StringifiedTagParseException { + 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/src/main/java/com/github/steveice10/opennbt/stringified/TagStringWriter.java b/src/main/java/com/github/steveice10/opennbt/stringified/TagStringWriter.java new file mode 100644 index 0000000..e279edc --- /dev/null +++ b/src/main/java/com/github/steveice10/opennbt/stringified/TagStringWriter.java @@ -0,0 +1,244 @@ +/* + * 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.github.steveice10.opennbt.stringified; + +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.util.Map; + +// Specific Via changes: +// - Use ViaNBT tags +// - Do not throw IOException for non-I/O operation, replace Appendable with explicit StringBuilder + +/** + * An emitter for the SNBT format. + * + *

Details on the format are described in the package documentation.

+ */ +final class TagStringWriter { + private final StringBuilder out; + /** + * Whether a {@link Tokens#VALUE_SEPARATOR} needs to be printed before the beginning of the next object. + */ + private boolean needsSeparator; + + public TagStringWriter(final StringBuilder out) { + this.out = out; + } + + // NBT-specific + + public TagStringWriter writeTag(final Tag tag) { + 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 IllegalArgumentException("Unknown tag type: " + tag.getClass().getSimpleName()); + // unknown! + } + } + + private TagStringWriter writeCompound(final CompoundTag tag) { + this.beginCompound(); + for (final Map.Entry entry : tag.entrySet()) { + this.key(entry.getKey()); + this.writeTag(entry.getValue()); + } + this.endCompound(); + return this; + } + + private TagStringWriter writeList(final ListTag tag) { + this.beginList(); + for (final Tag el : tag) { + this.printAndResetSeparator(); + this.writeTag(el); + } + this.endList(); + return this; + } + + private TagStringWriter writeByteArray(final ByteArrayTag tag) { + this.beginArray(Tokens.TYPE_BYTE); + + final byte[] value = tag.getValue(); + for (int i = 0, length = value.length; i < length; i++) { + this.printAndResetSeparator(); + this.value(Byte.toString(value[i]), Tokens.TYPE_BYTE); + } + this.endArray(); + return this; + } + + private TagStringWriter writeIntArray(final IntArrayTag tag) { + this.beginArray(Tokens.TYPE_INT); + + final int[] value = tag.getValue(); + for (int i = 0, length = value.length; i < length; i++) { + this.printAndResetSeparator(); + this.value(Integer.toString(value[i]), Tokens.TYPE_INT); + } + this.endArray(); + return this; + } + + private TagStringWriter writeLongArray(final LongArrayTag tag) { + this.beginArray(Tokens.TYPE_LONG); + + final long[] value = tag.getValue(); + for (int i = 0, length = value.length; i < length; i++) { + this.printAndResetSeparator(); + this.value(Long.toString(value[i]), Tokens.TYPE_LONG); + } + this.endArray(); + return this; + } + + // Value types + + public TagStringWriter beginCompound() { + this.printAndResetSeparator(); + this.out.append(Tokens.COMPOUND_BEGIN); + return this; + } + + public TagStringWriter endCompound() { + this.out.append(Tokens.COMPOUND_END); + this.needsSeparator = true; + return this; + } + + public TagStringWriter key(final String key) { + this.printAndResetSeparator(); + this.writeMaybeQuoted(key, false); + this.out.append(Tokens.COMPOUND_KEY_TERMINATOR); + return this; + } + + public TagStringWriter value(final String value, final char valueType) { + if (valueType == Tokens.EOF) { // string doesn't have its type + this.writeMaybeQuoted(value, true); + } else { + this.out.append(value); + if (valueType != Tokens.TYPE_INT) { + this.out.append(valueType); + } + } + this.needsSeparator = true; + return this; + } + + public TagStringWriter beginList() { + this.printAndResetSeparator(); + this.out.append(Tokens.ARRAY_BEGIN); + return this; + } + + public TagStringWriter endList() { + this.out.append(Tokens.ARRAY_END); + this.needsSeparator = true; + return this; + } + + private TagStringWriter beginArray(final char type) { + this.beginList() + .out.append(type) + .append(Tokens.ARRAY_SIGNATURE_SEPARATOR); + return this; + } + + private TagStringWriter endArray() { + return this.endList(); + } + + private void writeMaybeQuoted(final String content, boolean requireQuotes) { + if (!requireQuotes) { + for (int i = 0; i < content.length(); ++i) { + if (!Tokens.id(content.charAt(i))) { + requireQuotes = true; + break; + } + } + } + if (requireQuotes) { + this.out.append(Tokens.DOUBLE_QUOTE); + this.out.append(escape(content, Tokens.DOUBLE_QUOTE)); + this.out.append(Tokens.DOUBLE_QUOTE); + } else { + this.out.append(content); + } + } + + private static String escape(final String content, final char quoteChar) { + final StringBuilder output = new StringBuilder(content.length()); + for (int i = 0; i < content.length(); ++i) { + final char c = content.charAt(i); + if (c == quoteChar || c == '\\') { + output.append(Tokens.ESCAPE_MARKER); + } + output.append(c); + } + return output.toString(); + } + + private void printAndResetSeparator() { + if (this.needsSeparator) { + this.out.append(Tokens.VALUE_SEPARATOR); + this.needsSeparator = false; + } + } +} diff --git a/src/main/java/com/github/steveice10/opennbt/stringified/Tokens.java b/src/main/java/com/github/steveice10/opennbt/stringified/Tokens.java new file mode 100644 index 0000000..6575c43 --- /dev/null +++ b/src/main/java/com/github/steveice10/opennbt/stringified/Tokens.java @@ -0,0 +1,89 @@ +/* + * 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.github.steveice10.opennbt.stringified; + +final class Tokens { + // Compounds + static final char COMPOUND_BEGIN = '{'; + static final char COMPOUND_END = '}'; + static final char COMPOUND_KEY_TERMINATOR = ':'; + + // Arrays + static final char ARRAY_BEGIN = '['; + static final char ARRAY_END = ']'; + static final char ARRAY_SIGNATURE_SEPARATOR = ';'; + + static final char VALUE_SEPARATOR = ','; + + static final char SINGLE_QUOTE = '\''; + static final char DOUBLE_QUOTE = '"'; + static final char ESCAPE_MARKER = '\\'; + + static final char TYPE_BYTE = 'b'; + static final char TYPE_SHORT = 's'; + static final char TYPE_INT = 'i'; // array only + static final char TYPE_LONG = 'l'; + static final char TYPE_FLOAT = 'f'; + static final char TYPE_DOUBLE = 'd'; + + static final String LITERAL_TRUE = "true"; + static final String LITERAL_FALSE = "false"; + + static final String NEWLINE = System.getProperty("line.separator", "\n"); + static final char EOF = '\0'; + + private Tokens() { + } + + /** + * Return if a character is a valid component in an identifier. + * + *

An 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/src/main/java/com/github/steveice10/opennbt/tag/TagCreateException.java b/src/main/java/com/github/steveice10/opennbt/tag/TagCreateException.java deleted file mode 100644 index fabf11a..0000000 --- a/src/main/java/com/github/steveice10/opennbt/tag/TagCreateException.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.github.steveice10.opennbt.tag; - -/** - * An exception thrown when an error occurs while created a tag instance. - */ -public class TagCreateException extends Exception { - private static final long serialVersionUID = -2022049594558041160L; - - public TagCreateException() { - super(); - } - - public TagCreateException(String message) { - super(message); - } - - public TagCreateException(Throwable cause) { - super(cause); - } - - public TagCreateException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/com/github/steveice10/opennbt/tag/TagRegisterException.java b/src/main/java/com/github/steveice10/opennbt/tag/TagRegisterException.java deleted file mode 100644 index d44573f..0000000 --- a/src/main/java/com/github/steveice10/opennbt/tag/TagRegisterException.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.github.steveice10.opennbt.tag; - -/** - * An exception thrown when an error occurs while registering a tag. - */ -public class TagRegisterException extends RuntimeException { - private static final long serialVersionUID = -2022049594558041160L; - - public TagRegisterException() { - super(); - } - - public TagRegisterException(String message) { - super(message); - } - - public TagRegisterException(Throwable cause) { - super(cause); - } - - public TagRegisterException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/com/github/steveice10/opennbt/tag/TagRegistry.java b/src/main/java/com/github/steveice10/opennbt/tag/TagRegistry.java index d29e61d..17d71a2 100644 --- a/src/main/java/com/github/steveice10/opennbt/tag/TagRegistry.java +++ b/src/main/java/com/github/steveice10/opennbt/tag/TagRegistry.java @@ -23,12 +23,11 @@ import org.jetbrains.annotations.Nullable; */ public final class TagRegistry { private static final int HIGHEST_ID = LongArrayTag.ID; - private static final Class[] idToTag = new Class[HIGHEST_ID + 1]; - private static final Supplier[] instanceSuppliers = new Supplier[HIGHEST_ID + 1]; - private static final Object2IntMap> tagToId = new Object2IntOpenHashMap<>(); + private static final RegisteredTagType[] TAGS = new RegisteredTagType[HIGHEST_ID + 1]; + private static final Object2IntMap> TAG_TO_ID = new Object2IntOpenHashMap<>(); static { - tagToId.defaultReturnValue(-1); + TAG_TO_ID.defaultReturnValue(-1); register(ByteTag.ID, ByteTag.class, ByteTag::new); register(ShortTag.ID, ShortTag.class, ShortTag::new); @@ -49,22 +48,21 @@ public final class TagRegistry { * * @param id ID of the tag. * @param tag Tag class to register. - * @throws TagRegisterException If an error occurs while registering the tag. + * @throws IllegalArgumentException if the id is unexpectedly out of bounds, or if the id or tag have already been registered */ - public static void register(int id, Class tag, Supplier supplier) throws TagRegisterException { + public static void register(int id, Class tag, Supplier supplier) { if (id < 0 || id > HIGHEST_ID) { - throw new TagRegisterException("Tag ID must be between 0 and " + HIGHEST_ID); + throw new IllegalArgumentException("Tag ID must be between 0 and " + HIGHEST_ID); } - if (idToTag[id] != null) { - throw new TagRegisterException("Tag ID \"" + id + "\" is already in use."); + if (TAGS[id] != null) { + throw new IllegalArgumentException("Tag ID \"" + id + "\" is already in use."); } - if (tagToId.containsKey(tag)) { - throw new TagRegisterException("Tag \"" + tag.getSimpleName() + "\" is already registered."); + if (TAG_TO_ID.containsKey(tag)) { + throw new IllegalArgumentException("Tag \"" + tag.getSimpleName() + "\" is already registered."); } - instanceSuppliers[id] = supplier; - idToTag[id] = tag; - tagToId.put(tag, id); + TAGS[id] = new RegisteredTagType(tag, supplier); + TAG_TO_ID.put(tag, id); } /** @@ -73,9 +71,8 @@ public final class TagRegistry { * @param id ID of the tag to unregister. */ public static void unregister(int id) { - tagToId.removeInt(getClassFor(id)); - idToTag[id] = null; - instanceSuppliers[id] = null; + TAG_TO_ID.removeInt(getClassFor(id)); + TAGS[id] = null; } /** @@ -86,7 +83,7 @@ public final class TagRegistry { */ @Nullable public static Class getClassFor(int id) { - return id >= 0 && id < idToTag.length ? idToTag[id] : null; + return id >= 0 && id < TAGS.length ? TAGS[id].type : null; } /** @@ -96,7 +93,7 @@ public final class TagRegistry { * @return The id of the given tag class, or -1 if it cannot be found. */ public static int getIdFor(Class clazz) { - return tagToId.getInt(clazz); + return TAG_TO_ID.getInt(clazz); } /** @@ -104,14 +101,25 @@ public final class TagRegistry { * * @param id Id of the tag. * @return The created tag. - * @throws TagCreateException If an error occurs while creating the tag. + * @throws IllegalArgumentException if no tags is registered over the provided id */ - public static Tag createInstance(int id) throws TagCreateException { - Supplier supplier = id > 0 && id < instanceSuppliers.length ? instanceSuppliers[id] : null; + public static Tag createInstance(int id) { + Supplier supplier = id > 0 && id < TAGS.length ? TAGS[id].supplier : null; if (supplier == null) { - throw new TagCreateException("Could not find tag with ID \"" + id + "\"."); + throw new IllegalArgumentException("Could not find tag with ID \"" + id + "\"."); } return supplier.get(); } + + private static final class RegisteredTagType { + + private final Class type; + private final Supplier supplier; + + private RegisteredTagType(final Class type, final Supplier supplier) { + this.type = type; + this.supplier = supplier; + } + } } diff --git a/src/main/java/com/github/steveice10/opennbt/tag/builtin/CompoundTag.java b/src/main/java/com/github/steveice10/opennbt/tag/builtin/CompoundTag.java index 5e9ef41..8212d59 100644 --- a/src/main/java/com/github/steveice10/opennbt/tag/builtin/CompoundTag.java +++ b/src/main/java/com/github/steveice10/opennbt/tag/builtin/CompoundTag.java @@ -1,6 +1,5 @@ package com.github.steveice10.opennbt.tag.builtin; -import com.github.steveice10.opennbt.tag.TagCreateException; import com.github.steveice10.opennbt.tag.TagRegistry; import com.github.steveice10.opennbt.tag.limiter.TagLimiter; import java.io.DataInput; @@ -204,8 +203,6 @@ public class CompoundTag extends Tag implements Iterable> { tag.read(in, tagLimiter, newNestingLevel); this.value.put(name, tag); } - } catch (TagCreateException e) { - throw new IOException("Failed to create tag.", e); } catch (EOFException ignored) { throw new IOException("Closing tag was not found!"); } diff --git a/src/main/java/com/github/steveice10/opennbt/tag/builtin/ListTag.java b/src/main/java/com/github/steveice10/opennbt/tag/builtin/ListTag.java index 5832e81..c701523 100644 --- a/src/main/java/com/github/steveice10/opennbt/tag/builtin/ListTag.java +++ b/src/main/java/com/github/steveice10/opennbt/tag/builtin/ListTag.java @@ -1,6 +1,5 @@ package com.github.steveice10.opennbt.tag.builtin; -import com.github.steveice10.opennbt.tag.TagCreateException; import com.github.steveice10.opennbt.tag.TagRegistry; import com.github.steveice10.opennbt.tag.limiter.TagLimiter; import java.io.DataInput; @@ -160,7 +159,7 @@ public class ListTag extends Tag implements Iterable { Tag tag; try { tag = TagRegistry.createInstance(id); - } catch (TagCreateException e) { + } catch (IllegalArgumentException e) { throw new IOException("Failed to create tag.", e); } diff --git a/src/main/java/com/github/steveice10/opennbt/tag/builtin/Tag.java b/src/main/java/com/github/steveice10/opennbt/tag/builtin/Tag.java index a90a479..c86e7e9 100644 --- a/src/main/java/com/github/steveice10/opennbt/tag/builtin/Tag.java +++ b/src/main/java/com/github/steveice10/opennbt/tag/builtin/Tag.java @@ -1,10 +1,10 @@ package com.github.steveice10.opennbt.tag.builtin; +import com.github.steveice10.opennbt.stringified.SNBT; import com.github.steveice10.opennbt.tag.limiter.TagLimiter; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import java.lang.reflect.Array; /** * Represents an NBT tag. @@ -20,6 +20,16 @@ public abstract class Tag implements Cloneable { */ public abstract Object getValue(); + /** + * Returns the unchecked value of this tag. + * + * @return unchecked value of this tag + * @param expected type + */ + public T value() { + return (T) getValue(); + } + /** * Reads this tag from an input stream. * @@ -71,26 +81,6 @@ public abstract class Tag implements Cloneable { @Override public String toString() { - //TODO cleanup/push down - String value = ""; - if (this.getValue() != null) { - value = this.getValue().toString(); - if (this.getValue().getClass().isArray()) { - StringBuilder build = new StringBuilder(); - build.append("["); - for (int index = 0; index < Array.getLength(this.getValue()); index++) { - if (index > 0) { - build.append(", "); - } - - build.append(Array.get(this.getValue(), index)); - } - - build.append("]"); - value = build.toString(); - } - } - - return this.getClass().getSimpleName() + " { " + value + " }"; + return SNBT.serialize(this); } } diff --git a/src/main/java/com/github/steveice10/opennbt/tag/limiter/TagLimiter.java b/src/main/java/com/github/steveice10/opennbt/tag/limiter/TagLimiter.java index ca08513..f109b0d 100644 --- a/src/main/java/com/github/steveice10/opennbt/tag/limiter/TagLimiter.java +++ b/src/main/java/com/github/steveice10/opennbt/tag/limiter/TagLimiter.java @@ -39,27 +39,27 @@ public interface TagLimiter { void checkLevel(int nestedLevel); default void countByte() { - this.countBytes(1); + this.countBytes(Byte.BYTES); } default void countShort() { - this.countBytes(2); + this.countBytes(Short.BYTES); } default void countInt() { - this.countBytes(4); + this.countBytes(Integer.BYTES); } default void countFloat() { - this.countBytes(4); + this.countBytes(Double.BYTES); } default void countLong() { - this.countBytes(8); + this.countBytes(Long.BYTES); } default void countDouble() { - this.countBytes(8); + this.countBytes(Double.BYTES); } /**