From f27bebf6c9057ab6e2ba9e3726d5911b176c1ab7 Mon Sep 17 00:00:00 2001 From: ForeverZer0 Date: Sat, 18 Sep 2021 18:46:43 -0400 Subject: [PATCH] - Fixed SNBT bug that would not parse boolean values - Implemented BoolTag type for convenience - Implemented compiled regular expressions --- SharpNBT.Tests/Data/bigtest.snbt | 1 + SharpNBT.Tests/TagBuilderTest.cs | 2 ++ SharpNBT/SNBT/LexerRule.cs | 2 +- SharpNBT/SNBT/StringNbt.cs | 2 ++ SharpNBT/SNBT/TokenType.cs | 5 +++ SharpNBT/SharpNBT.csproj | 4 ++- SharpNBT/TagBuilder.cs | 17 +++++++++- SharpNBT/Tags/BoolTag.cs | 56 ++++++++++++++++++++++++++++++++ SharpNBT/Tags/Tag.cs | 10 +++++- 9 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 SharpNBT/Tags/BoolTag.cs diff --git a/SharpNBT.Tests/Data/bigtest.snbt b/SharpNBT.Tests/Data/bigtest.snbt index e4a523d..19760f0 100644 --- a/SharpNBT.Tests/Data/bigtest.snbt +++ b/SharpNBT.Tests/Data/bigtest.snbt @@ -1,4 +1,5 @@ { + "bool test": true, "test case": 90, noQuotes: "HELLO WORLD THIS IS A TEST STRING ÅÄÖ!", "test with \" escaped quote": 90, diff --git a/SharpNBT.Tests/TagBuilderTest.cs b/SharpNBT.Tests/TagBuilderTest.cs index a17b416..8366838 100644 --- a/SharpNBT.Tests/TagBuilderTest.cs +++ b/SharpNBT.Tests/TagBuilderTest.cs @@ -30,6 +30,8 @@ namespace SharpNBT.Tests .BeginCompound("egg").AddString("name", "Eggbert").AddFloat("value", 0.5f).EndCompound() .BeginCompound("ham").AddString("name", "Hampus").AddFloat("value", 0.75f).EndCompound() .EndCompound() + .AddBool("boolTest", true) + .AddBool("bool Test 2", false) .AddInt("iniTest", 2147483647) .AddByte("byteTest", 127) .AddString("stringTest", "HELLO WORLD THIS IS A TEST STRING \xc5\xc4\xd6!") diff --git a/SharpNBT/SNBT/LexerRule.cs b/SharpNBT/SNBT/LexerRule.cs index 68e21c3..f282754 100644 --- a/SharpNBT/SNBT/LexerRule.cs +++ b/SharpNBT/SNBT/LexerRule.cs @@ -24,7 +24,7 @@ namespace SharpNBT.SNBT public LexerRule(TokenType type, string pattern, ResultHandler handler, bool skipped = false) { Type = type; - Pattern = new Regex(pattern); + Pattern = new Regex(pattern, RegexOptions.Compiled); IsSkipped = skipped; processResult = handler; } diff --git a/SharpNBT/SNBT/StringNbt.cs b/SharpNBT/SNBT/StringNbt.cs index 9424f32..d8fe429 100644 --- a/SharpNBT/SNBT/StringNbt.cs +++ b/SharpNBT/SNBT/StringNbt.cs @@ -36,6 +36,7 @@ namespace SharpNBT.SNBT lexer.AddRule(TokenType.EndArray, @"\]"); lexer.AddRule(TokenType.Float, @"(-?[0-9]*\.[0-9]+)[Ff]", FirstGroupValue); lexer.AddRule(TokenType.Double, @"(-?[0-9]*\.[0-9]+)[Dd]?", FirstGroupValue); + lexer.AddRule(TokenType.Bool, "(true|false)", FirstGroupValue); lexer.AddRule(TokenType.Byte, "(-?[0-9]+)[Bb]", FirstGroupValue); lexer.AddRule(TokenType.Short, "(-?[0-9]+)[Ss]", FirstGroupValue); lexer.AddRule(TokenType.Long, "(-?[0-9]+)[Ll]", FirstGroupValue); @@ -142,6 +143,7 @@ namespace SharpNBT.SNBT TokenType.IntArray => ParseIntArray(name, queue), TokenType.LongArray => ParseLongArray(name, queue), TokenType.List => ParseList(name, queue), + TokenType.Bool => new BoolTag(name, bool.Parse(token.Value)), TokenType.Byte => new ByteTag(name, sbyte.Parse(token.Value)), TokenType.Short => new ShortTag(name, short.Parse(token.Value)), TokenType.Int => new IntTag(name, int.Parse(token.Value)), diff --git a/SharpNBT/SNBT/TokenType.cs b/SharpNBT/SNBT/TokenType.cs index 1d08a68..568c2db 100644 --- a/SharpNBT/SNBT/TokenType.cs +++ b/SharpNBT/SNBT/TokenType.cs @@ -70,6 +70,11 @@ namespace SharpNBT.SNBT /// Byte, + /// + /// A value. + /// + Bool, + /// /// A value. /// diff --git a/SharpNBT/SharpNBT.csproj b/SharpNBT/SharpNBT.csproj index 7afe40f..8c84bfc 100644 --- a/SharpNBT/SharpNBT.csproj +++ b/SharpNBT/SharpNBT.csproj @@ -13,7 +13,9 @@ nbt;named binary tag;minecraft;serialization;java;bedrock;pocket edition;varint;varlong;zlib Copyright © Eric Freed 2021 true - 1.1.0 + 1.2.0 + 1.2.0 + 1.2.0 diff --git a/SharpNBT/TagBuilder.cs b/SharpNBT/TagBuilder.cs index 601ffba..67397bf 100644 --- a/SharpNBT/TagBuilder.cs +++ b/SharpNBT/TagBuilder.cs @@ -36,6 +36,21 @@ namespace SharpNBT tree.Push(root); } + /// + /// Adds a new with the specified and to the tree at the current depth. + /// + /// The name of the node to add. + /// The value of the tag. + /// Returns this instance for chaining. + public TagBuilder AddBool([CanBeNull] string name, bool value) => AddTag(new BoolTag(name, value)); + + /// + /// Adds a new unnamed with the specified to the tree at the current depth. + /// + /// The value of the tag. + /// Returns this instance for chaining. + public TagBuilder AddBool(bool value) => AddBool(null, value); + /// /// Adds a new with the specified and to the tree at the current depth. /// @@ -58,7 +73,7 @@ namespace SharpNBT /// [CLSCompliant(false)] public TagBuilder AddByte(sbyte value) => AddByte(null, unchecked((byte)value)); - + /// /// Adds a new with the specified and to the tree at the current depth. /// diff --git a/SharpNBT/Tags/BoolTag.cs b/SharpNBT/Tags/BoolTag.cs new file mode 100644 index 0000000..f5ea46d --- /dev/null +++ b/SharpNBT/Tags/BoolTag.cs @@ -0,0 +1,56 @@ +using System; +using System.Runtime.Serialization; +using JetBrains.Annotations; + +namespace SharpNBT +{ + /// + /// A tag that contains a single 8-bit integer value. + /// + /// + /// This tag type does not exist in the NBT specification, and is included for convenience to differentiate it from the that it is + /// actually serialized as. + /// + [PublicAPI][Serializable] + public class BoolTag : Tag + { + private const string TRUE = "true"; + private const string FALSE = "false"; + + /// + /// Creates a new instance of the class with the specified . + /// + /// The name of the tag, or if tag has no name. + /// The value to assign to this tag. + public BoolTag([CanBeNull] string name, bool value) : base(TagType.Byte, name, value) + { + } + + /// + /// Required constructor for ISerializable implementation. + /// + /// The to describing this instance. + /// The destination (see ) for this serialization. + protected BoolTag(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + /// + public override string ToString() => $"TAG_Bool({PrettyName}): {(Value ? TRUE : FALSE)}"; + + /// + /// Implicit conversion of this tag to a . + /// + /// The tag to convert. + /// The tag represented as a . + public static implicit operator bool(BoolTag tag) => tag.Value; + + /// + /// Gets the string representation of this NBT tag (SNBT). + /// + /// This NBT tag in SNBT format. + /// + public override string Stringify() => $"{StringifyName}{(Value ? TRUE : FALSE)}"; + + } +} \ No newline at end of file diff --git a/SharpNBT/Tags/Tag.cs b/SharpNBT/Tags/Tag.cs index 6f592f3..cb838a8 100644 --- a/SharpNBT/Tags/Tag.cs +++ b/SharpNBT/Tags/Tag.cs @@ -19,6 +19,14 @@ namespace SharpNBT [PublicAPI][Serializable] public abstract class Tag : IEquatable, ISerializable, ICloneable { + private static Regex simpleNameMatcher; + + static Tag() + { + simpleNameMatcher = new Regex(@"^[A-Ba-z0-9_-]+$", RegexOptions.Compiled); + } + + private static IEnumerable GetKnownTypes() { return new[] @@ -229,7 +237,7 @@ namespace SharpNBT { if (string.IsNullOrEmpty(Name)) return string.Empty; - return Regex.IsMatch(Name, @"^[A-Ba-z0-9_-]+$") ? $"{Name}: " : $"\"{Name}\": "; + return simpleNameMatcher.IsMatch(Name) ? $"{Name}: " : $"\"{Name}\": "; } } }