From 0b905be7e017e42a64d05d9667735fe1722c2cbb Mon Sep 17 00:00:00 2001 From: Eric Freed Date: Fri, 25 Aug 2023 00:55:55 -0400 Subject: [PATCH] removed original files in preparation of reimplementation --- SharpNBT.Tests/ConversionTest.cs | 23 - SharpNBT.Tests/ParseTest.cs | 33 - SharpNBT.Tests/StringifiedTest.cs | 54 - SharpNBT.Tests/TagBuilderTest.cs | 122 --- SharpNBT.Tests/TestHelper.cs | 34 - SharpNBT.Tests/VarIntTest.cs | 191 ---- SharpNBT.Tests/VarLongTest.cs | 216 ---- SharpNBT/BufferedTagWriter.cs | 118 --- SharpNBT/CompressionType.cs | 33 - SharpNBT/EndianExtensions.cs | 75 -- SharpNBT/Events/TagEventArgs.cs | 35 - SharpNBT/Events/TagHandledEventArgs.cs | 53 - SharpNBT/Events/TagReaderCallback.cs | 12 - SharpNBT/FormatOptions.cs | 60 -- SharpNBT/JetBrains.Annotations.cs | 1355 ------------------------ SharpNBT/NbtFile.cs | 185 ---- SharpNBT/SNBT/Lexer.cs | 50 - SharpNBT/SNBT/LexerRule.cs | 37 - SharpNBT/SNBT/StringNbt.cs | 250 ----- SharpNBT/SNBT/Token.cs | 35 - SharpNBT/SNBT/TokenType.cs | 103 -- SharpNBT/TagBuilder.cs | 435 -------- SharpNBT/TagIO.cs | 72 -- SharpNBT/TagReader.cs | 511 --------- SharpNBT/TagWriter.cs | 388 ------- SharpNBT/Tags/BoolTag.cs | 56 - SharpNBT/Tags/ByteArrayTag.cs | 74 -- SharpNBT/Tags/ByteTag.cs | 81 -- SharpNBT/Tags/CompoundTag.cs | 143 --- SharpNBT/Tags/DoubleTag.cs | 48 - SharpNBT/Tags/EndTag.cs | 35 - SharpNBT/Tags/EnumerableTag.cs | 203 ---- SharpNBT/Tags/FloatTag.cs | 47 - SharpNBT/Tags/IntArrayTag.cs | 72 -- SharpNBT/Tags/IntTag.cs | 75 -- SharpNBT/Tags/ListTag.cs | 103 -- SharpNBT/Tags/LongArrayTag.cs | 77 -- SharpNBT/Tags/LongTag.cs | 75 -- SharpNBT/Tags/ShortTag.cs | 75 -- SharpNBT/Tags/StringTag.cs | 48 - SharpNBT/Tags/Tag.cs | 350 ------ SharpNBT/Tags/TagContainer.cs | 174 --- SharpNBT/Tags/TagType.cs | 77 -- SharpNBT/VarInt.cs | 117 -- SharpNBT/VarIntUtil.cs | 106 -- SharpNBT/VarLong.cs | 119 --- SharpNBT/ZLib/Adler32.cs | 115 -- SharpNBT/ZLib/ZLibHeader.cs | 115 -- SharpNBT/ZLib/ZLibStream.cs | 410 ------- 49 files changed, 7275 deletions(-) delete mode 100644 SharpNBT.Tests/ConversionTest.cs delete mode 100644 SharpNBT.Tests/ParseTest.cs delete mode 100644 SharpNBT.Tests/StringifiedTest.cs delete mode 100644 SharpNBT.Tests/TagBuilderTest.cs delete mode 100644 SharpNBT.Tests/TestHelper.cs delete mode 100644 SharpNBT.Tests/VarIntTest.cs delete mode 100644 SharpNBT.Tests/VarLongTest.cs delete mode 100644 SharpNBT/BufferedTagWriter.cs delete mode 100644 SharpNBT/CompressionType.cs delete mode 100644 SharpNBT/EndianExtensions.cs delete mode 100644 SharpNBT/Events/TagEventArgs.cs delete mode 100644 SharpNBT/Events/TagHandledEventArgs.cs delete mode 100644 SharpNBT/Events/TagReaderCallback.cs delete mode 100644 SharpNBT/FormatOptions.cs delete mode 100644 SharpNBT/JetBrains.Annotations.cs delete mode 100644 SharpNBT/NbtFile.cs delete mode 100644 SharpNBT/SNBT/Lexer.cs delete mode 100644 SharpNBT/SNBT/LexerRule.cs delete mode 100644 SharpNBT/SNBT/StringNbt.cs delete mode 100644 SharpNBT/SNBT/Token.cs delete mode 100644 SharpNBT/SNBT/TokenType.cs delete mode 100644 SharpNBT/TagBuilder.cs delete mode 100644 SharpNBT/TagIO.cs delete mode 100644 SharpNBT/TagReader.cs delete mode 100644 SharpNBT/TagWriter.cs delete mode 100644 SharpNBT/Tags/BoolTag.cs delete mode 100644 SharpNBT/Tags/ByteArrayTag.cs delete mode 100644 SharpNBT/Tags/ByteTag.cs delete mode 100644 SharpNBT/Tags/CompoundTag.cs delete mode 100644 SharpNBT/Tags/DoubleTag.cs delete mode 100644 SharpNBT/Tags/EndTag.cs delete mode 100644 SharpNBT/Tags/EnumerableTag.cs delete mode 100644 SharpNBT/Tags/FloatTag.cs delete mode 100644 SharpNBT/Tags/IntArrayTag.cs delete mode 100644 SharpNBT/Tags/IntTag.cs delete mode 100644 SharpNBT/Tags/ListTag.cs delete mode 100644 SharpNBT/Tags/LongArrayTag.cs delete mode 100644 SharpNBT/Tags/LongTag.cs delete mode 100644 SharpNBT/Tags/ShortTag.cs delete mode 100644 SharpNBT/Tags/StringTag.cs delete mode 100644 SharpNBT/Tags/Tag.cs delete mode 100644 SharpNBT/Tags/TagContainer.cs delete mode 100644 SharpNBT/Tags/TagType.cs delete mode 100644 SharpNBT/VarInt.cs delete mode 100644 SharpNBT/VarIntUtil.cs delete mode 100644 SharpNBT/VarLong.cs delete mode 100644 SharpNBT/ZLib/Adler32.cs delete mode 100644 SharpNBT/ZLib/ZLibHeader.cs delete mode 100644 SharpNBT/ZLib/ZLibStream.cs diff --git a/SharpNBT.Tests/ConversionTest.cs b/SharpNBT.Tests/ConversionTest.cs deleted file mode 100644 index e0510f3..0000000 --- a/SharpNBT.Tests/ConversionTest.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Xunit; -using Xunit.Abstractions; - -namespace SharpNBT.Tests -{ - public class ConversionTest - { - private readonly ITestOutputHelper output; - private readonly CompoundTag tag; - - public ConversionTest(ITestOutputHelper output) - { - this.output = output; - tag = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip); - } - - [Fact] - public void JsonOutput1() - { - output.WriteLine(tag.ToJsonString(true)); - } - } -} \ No newline at end of file diff --git a/SharpNBT.Tests/ParseTest.cs b/SharpNBT.Tests/ParseTest.cs deleted file mode 100644 index 362061d..0000000 --- a/SharpNBT.Tests/ParseTest.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.IO; -using System.IO.Compression; -using System.Reflection; -using Xunit; -using Xunit.Abstractions; - -namespace SharpNBT.Tests -{ - public class ReadWriteTest - { - private readonly ITestOutputHelper output; - - public ReadWriteTest(ITestOutputHelper output) - { - this.output = output; - } - - [Fact] - public void ReadUncompressed() - { - var compound = TestHelper.GetTag("hello_world.nbt", CompressionType.None); - output.WriteLine(compound.PrettyPrinted()); - } - - [Fact] - public void ReadGZipped() - { - var compound = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip); - output.WriteLine(compound.PrettyPrinted()); - } - - } -} \ No newline at end of file diff --git a/SharpNBT.Tests/StringifiedTest.cs b/SharpNBT.Tests/StringifiedTest.cs deleted file mode 100644 index 8b60ab9..0000000 --- a/SharpNBT.Tests/StringifiedTest.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using Microsoft.VisualStudio.TestPlatform.ObjectModel; -using SharpNBT.SNBT; -using Xunit; -using Xunit.Abstractions; - -namespace SharpNBT.Tests -{ - public class StringifiedTest - { - private readonly ITestOutputHelper output; - - - public StringifiedTest(ITestOutputHelper output) - { - this.output = output; - } - - [Fact] - public void BigOutput() - { - var tag = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip); - output.WriteLine(tag.Stringify(true)); - } - - [Fact] - public void HelloWorldOutput() - { - var tag = TestHelper.GetTag("hello_world.nbt", CompressionType.None); - output.WriteLine(tag.Stringify(true)); - } - - [Fact] - public void ParseSmall() - { - const string testString = "{name1:123,name2:\"sometext1\",name3:{subname1:456,subname2:\"sometext2\"}}"; - var tag = StringNbt.Parse(testString); - output.WriteLine(tag.PrettyPrinted()); - } - - [Fact] - public void ParseBig() - { - using var stream = TestHelper.GetFile("bigtest.snbt", CompressionType.None); - using var reader = new StreamReader(stream, Encoding.UTF8); - var testString = reader.ReadToEnd(); - - var tag = StringNbt.Parse(testString); - output.WriteLine(tag.PrettyPrinted()); - } - } -} \ No newline at end of file diff --git a/SharpNBT.Tests/TagBuilderTest.cs b/SharpNBT.Tests/TagBuilderTest.cs deleted file mode 100644 index 8366838..0000000 --- a/SharpNBT.Tests/TagBuilderTest.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using Xunit; -using Xunit.Abstractions; - -namespace SharpNBT.Tests -{ - public class TagBuilderTest - { - private readonly ITestOutputHelper output; - - public TagBuilderTest(ITestOutputHelper output) - { - this.output = output; - } - - private static byte[] GetByteArray() - { - var bytes = new byte[1000]; - for (var i = 0; i < 1000; i++) - bytes[i] = Convert.ToByte((i * i * 255 + i * 7) % 100); - return bytes; - } - - [Fact] - public void CreateBigTest() - { - - var builder = new TagBuilder("Level") - .BeginCompound("nested compound test") - .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!") - .BeginList(TagType.Long, "listTest (long)") - .AddLong(11).AddLong(12).AddLong(13).AddLong(14).AddLong(15) - .EndList() - .AddDouble("doubleTest", 0.49312871321823148) - .AddFloat("floatTest", 0.49823147058486938f) - .AddLong("longTest", 9223372036854775807L) - .BeginList(TagType.Compound, "listTest (compound)") - .BeginCompound().AddLong("created-on", 1264099775885L).AddString("name", "Compound tag #0").EndCompound() - .BeginCompound().AddLong("created-on", 1264099775885L).AddString("name", "Compound tag #1").EndCompound() - .EndList() - .AddByteArray("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))", GetByteArray()) - .AddShort("shortTest", 32767); - - output.WriteLine(builder.Create().PrettyPrinted()); - } - - [Fact] - public void CreateBigTest2() - { - var tb = new TagBuilder("Level"); - using (tb.NewCompound("nested compound test")) - { - using (tb.NewCompound("egg")) - { - tb.AddString("name", "Eggbert"); - tb.AddFloat("value", 0.5f); - } - - using (tb.NewCompound("ham")) - { - tb.AddString("name", "Hampus"); - tb.AddFloat("value", 0.75f); - } - } - - tb.AddInt("iniTest", 2147483647); - tb.AddByte("byteTest", 127); - tb .AddString("stringTest", "HELLO WORLD THIS IS A TEST STRING \xc5\xc4\xd6!"); - - using (tb.NewList(TagType.Long, "listTest (long")) - { - tb.AddLong(11); - tb.AddLong(12); - tb.AddLong(13); - tb.AddLong(14); - tb.AddLong(15); - } - - tb.AddDouble("doubleTest", 0.49312871321823148); - tb.AddFloat("floatTest", 0.49823147058486938f); - tb.AddLong("longTest", 9223372036854775807L); - - using (tb.NewList(TagType.Compound, "listTest (compound)")) - { - using (tb.NewCompound(null)) - { - tb.AddLong("created-on", 1264099775885L); - tb.AddString("name", "Compound tag #0"); - } - using (tb.NewCompound(null)) - { - tb.AddLong("created-on", 1264099775885L); - tb.AddString("name", "Compound tag #1"); - } - } - - tb.AddByteArray("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))", GetByteArray()); - tb.AddShort("shortTest", 32767); - - - output.WriteLine(tb.Create().PrettyPrinted()); - } - - [Fact] - public void Test3() - { - var builder = new TagBuilder("My NBT Structure"); - builder.AddInt("Health", 9000); - builder.AddString("PlayerName", "Herobrine"); - var result = builder.Create(); - - output.WriteLine(result.PrettyPrinted()); - } - } -} \ No newline at end of file diff --git a/SharpNBT.Tests/TestHelper.cs b/SharpNBT.Tests/TestHelper.cs deleted file mode 100644 index 809a86e..0000000 --- a/SharpNBT.Tests/TestHelper.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Reflection; -using SharpNBT.ZLib; - -namespace SharpNBT.Tests -{ - public class TestHelper - { - public static Stream GetFile(string filename, CompressionType compression) - { - var assembly = Assembly.GetExecutingAssembly(); - var stream = assembly.GetManifestResourceStream($"SharpNBT.Tests.Data.{filename}"); - if (stream is null) - throw new FileNotFoundException(filename); - - return compression switch - { - CompressionType.None => stream, - CompressionType.GZip => new GZipStream(stream, CompressionMode.Decompress), - CompressionType.ZLib => new ZLibStream(stream, CompressionMode.Decompress), - _ => throw new Exception() - }; - } - - public static CompoundTag GetTag(string filename, CompressionType compression) - { - using var stream = GetFile(filename, compression); - using var reader = new TagReader(stream, FormatOptions.Java); - return reader.ReadTag(); - } - } -} \ No newline at end of file diff --git a/SharpNBT.Tests/VarIntTest.cs b/SharpNBT.Tests/VarIntTest.cs deleted file mode 100644 index 7ab773e..0000000 --- a/SharpNBT.Tests/VarIntTest.cs +++ /dev/null @@ -1,191 +0,0 @@ -using System; -using Xunit; - -namespace SharpNBT.Tests -{ - public class VarIntTest - { - - [Fact] - public void Encode1() - { - var value = -2147483648; - var expected = new byte[] { 0x80, 0x80, 0x80, 0x80, 0x08 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode2() - { - var value = -1; - var expected = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x0f }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode3() - { - var value = 2147483647; - var expected = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x07 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode4() - { - var value = 2097151; - var expected = new byte[] { 0xff, 0xff, 0x7f }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode5() - { - var value = 255; - var expected = new byte[] { 0xff, 0x01 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode6() - { - var value = 128; - var expected = new byte[] { 0x80, 0x01 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode7() - { - var value = 127; - var expected = new byte[] { 0x7f }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - - [Fact] - public void Encode8() - { - var value = 2; - var expected = new byte[] { 0x02 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode9() - { - var value = 1; - var expected = new byte[] { 0x01 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode10() - { - var value = 0; - var expected = new byte[] { 0x00 }; - var actual = VarInt.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode1() - { - var expected = -2147483648; - var bytes = new byte[] { 0x80, 0x80, 0x80, 0x80, 0x08 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode2() - { - var expected = -1; - var bytes = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x0f }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode3() - { - var expected = 2147483647; - var bytes = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x07 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode4() - { - var expected = 2097151; - var bytes = new byte[] { 0xff, 0xff, 0x7f }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode5() - { - var expected = 255; - var bytes = new byte[] { 0xff, 0x01 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode6() - { - var expected = 128; - var bytes = new byte[] { 0x80, 0x01 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode7() - { - var expected = 127; - var bytes = new byte[] { 0x7f }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - - [Fact] - public void Decode8() - { - var expected = 2; - var bytes = new byte[] { 0x02 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode9() - { - var expected = 1; - var bytes = new byte[] { 0x01 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode10() - { - var expected = 0; - var bytes = new byte[] { 0x00 }; - var actual = VarInt.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - } -} \ No newline at end of file diff --git a/SharpNBT.Tests/VarLongTest.cs b/SharpNBT.Tests/VarLongTest.cs deleted file mode 100644 index cdf58d8..0000000 --- a/SharpNBT.Tests/VarLongTest.cs +++ /dev/null @@ -1,216 +0,0 @@ -using Xunit; - -namespace SharpNBT.Tests -{ - public class VarLongTest - { - [Fact] - public void Encode1() - { - long value = -9223372036854775808; - var expected = new byte[] { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode2() - { - long value = -2147483648; - var expected = new byte[] { 0x80, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode3() - { - long value = -1; - var expected = new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode4() - { - long value = 9223372036854775807; - var expected = new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode5() - { - long value = 2147483647; - var expected = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x07 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode6() - { - long value = 255; - var expected = new byte[] { 0xff, 0x01 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode7() - { - long value = 128; - var expected = new byte[] { 0x80, 0x01 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode8() - { - long value = 127; - var expected = new byte[] { 0x7f }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode9() - { - long value = 2; - var expected = new byte[] { 0x02 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode10() - { - long value = 1; - var expected = new byte[] { 0x01 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - [Fact] - public void Encode11() - { - long value = 0; - var expected = new byte[] { 0x00 }; - var actual = VarLong.Encode(value); - Assert.Equal(expected, actual); - } - - - - - - - - - - - - - [Fact] - public void Decode1() - { - long expected = -9223372036854775808; - var bytes = new byte[] { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode2() - { - long expected = -2147483648; - var bytes = new byte[] { 0x80, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode3() - { - long expected = -1; - var bytes = new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode4() - { - long expected = 9223372036854775807; - var bytes = new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode5() - { - long expected = 2147483647; - var bytes = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x07 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode6() - { - long expected = 255; - var bytes = new byte[] { 0xff, 0x01 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode7() - { - long expected = 128; - var bytes = new byte[] { 0x80, 0x01 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode8() - { - long expected = 127; - var bytes = new byte[] { 0x7f }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode9() - { - long expected = 2; - var bytes = new byte[] { 0x02 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode10() - { - long expected = 1; - var bytes = new byte[] { 0x01 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - - [Fact] - public void Decode11() - { - long expected = 0; - var bytes = new byte[] { 0x00 }; - var actual = VarLong.Decode(bytes, out var dummy); - Assert.Equal(expected, actual); - } - } -} \ No newline at end of file diff --git a/SharpNBT/BufferedTagWriter.cs b/SharpNBT/BufferedTagWriter.cs deleted file mode 100644 index 99564e1..0000000 --- a/SharpNBT/BufferedTagWriter.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Threading.Tasks; -using JetBrains.Annotations; -using SharpNBT.ZLib; - -namespace SharpNBT -{ - /// - /// Provides a object that writes to an internal buffer instead of a object, which then can be retrieved as - /// an array of bytes or written directly to a stream. This is especially convenient when creating packets to be sent over a network, where the size of - /// the packet must be pre-determined before sending. - /// - [PublicAPI] - public class BufferedTagWriter : TagWriter - { - private readonly MemoryStream buffer; - - /// - /// Creates a new instance of the class. - /// - /// Indicates the compression algorithm used to compress the file. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// A newly created instance. - /// Thrown when an invalid compression type is specified. - public static BufferedTagWriter Create(CompressionType compression, FormatOptions options) - { - // ReSharper disable once IntroduceOptionalParameters.Global - return Create(compression, options, 4096); - } - - /// - /// Creates a new instance of the class. - /// - /// Indicates the compression algorithm used to compress the file. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// The initial capacity of the buffer. - /// A newly created instance. - /// Thrown when an invalid compression type is specified. - public static BufferedTagWriter Create(CompressionType compression, FormatOptions options, int capacity) - { - var buffer = new MemoryStream(capacity); - Stream stream = compression switch - { - CompressionType.None => buffer, - CompressionType.GZip => new GZipStream(buffer, CompressionMode.Compress, false), - CompressionType.ZLib => new ZLibStream(buffer, CompressionMode.Compress), - _ => throw new ArgumentOutOfRangeException(nameof(compression), compression, null) - }; - - return new BufferedTagWriter(stream, buffer, options); - } - - private BufferedTagWriter([NotNull] Stream stream, MemoryStream buffer, FormatOptions options) : base(stream, options, false) - { - this.buffer = buffer; - } - - /// - /// Gets the number of bytes in the internal buffer. - /// - public long Length - { - get - { - BaseStream.Flush(); - return buffer.Length; - } - } - - /// - /// Gets the capacity of the internal buffer. - /// - /// The capacity will expand automatically as-needed. - public long Capacity => buffer.Capacity; - - /// - /// Gets the internal buffer as an array of bytes containing the NBT data written so far. - /// - /// An array of bytes containing the NBT data. - [Pure] - public byte[] ToArray() - { - BaseStream.Flush(); - return buffer.ToArray(); - } - - /// - /// Copies the internal buffer to the specified ; - /// - /// A instance to write to. - public void CopyTo([NotNull] Stream stream) - { - BaseStream.Flush(); - buffer.CopyTo(stream); - } - - /// - /// Asynchronously copies the internal buffer to the specified ; - /// - /// A instance to write to. - public async Task CopyToAsync([NotNull] Stream stream) - { - await BaseStream.FlushAsync(); - await buffer.CopyToAsync(stream); - } - - /// - /// Implicit conversion of to a . - /// - public static implicit operator ReadOnlySpan(BufferedTagWriter writer) - { - writer.BaseStream.Flush(); - return writer.buffer.ToArray(); - } - } -} \ No newline at end of file diff --git a/SharpNBT/CompressionType.cs b/SharpNBT/CompressionType.cs deleted file mode 100644 index bfc81c7..0000000 --- a/SharpNBT/CompressionType.cs +++ /dev/null @@ -1,33 +0,0 @@ -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Describes compression formats supported by the NBT specification. - /// - [PublicAPI] - public enum CompressionType : byte - { - /// - /// No compression. - /// - None, - - /// - /// GZip compression - /// - GZip, - - /// - /// ZLib compression - /// - ZLib, - - /// - /// Automatically detect compression using magic numbers. - /// - /// This is not a valid value when specifying a compression type for writing. - AutoDetect = 0xFF - } - -} \ No newline at end of file diff --git a/SharpNBT/EndianExtensions.cs b/SharpNBT/EndianExtensions.cs deleted file mode 100644 index 8e91f26..0000000 --- a/SharpNBT/EndianExtensions.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Contains extension methods dealing with endianness of numeric types. - /// - [PublicAPI] - public static class EndianExtensions - { - /// - /// Swap the endian of the given . - /// - /// The value to swap endian of. - /// The value with bytes in opposite format. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short SwapEndian(this short value) - { - return (short) ((value << 8) | ((value >> 8) & 0xFF)); - } - - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort SwapEndian(this ushort value) - { - return (ushort)((value << 8) | (value >> 8 )); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SwapEndian(this int value) => unchecked((int) SwapEndian(unchecked((uint)value))); - - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SwapEndian(this uint value) - { - value = ((value << 8) & 0xFF00FF00 ) | ((value >> 8) & 0xFF00FF ); - return (value << 16) | (value >> 16); - } - - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SwapEndian(this ulong value) - { - value = ((value << 8) & 0xFF00FF00FF00FF00UL) | ((value >> 8) & 0x00FF00FF00FF00FFUL); - value = ((value << 16) & 0xFFFF0000FFFF0000UL) | ((value >> 16) & 0x0000FFFF0000FFFFUL); - return (value << 32) | (value >> 32); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SwapEndian(this long value) => unchecked((long) SwapEndian(unchecked((ulong)value))); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float SwapEndian(this float value) - { - var n = BitConverter.SingleToInt32Bits(value); - return BitConverter.Int32BitsToSingle(n.SwapEndian()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static double SwapEndian(this double value) - { - var n = BitConverter.DoubleToInt64Bits(value); - return BitConverter.Int64BitsToDouble(n.SwapEndian()); - } - } -} \ No newline at end of file diff --git a/SharpNBT/Events/TagEventArgs.cs b/SharpNBT/Events/TagEventArgs.cs deleted file mode 100644 index a104fde..0000000 --- a/SharpNBT/Events/TagEventArgs.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Arguments supplied with tag-related events. - /// - [PublicAPI] - public class TagEventArgs : EventArgs - { - /// - /// Gets a constant describing the basic NBT type of the tag. - /// - public TagType Type { get; } - - /// - /// Gets the parsed instance. - /// - [NotNull] - public Tag Tag { get; } - - /// - /// Creates a new instance of the class. - /// - /// A constant describing the basic NBT type of the tag. - /// The parsed instance. - /// Thrown when is . - public TagEventArgs(TagType type, [NotNull] Tag tag) - { - Type = type; - Tag = tag ?? throw new ArgumentNullException(nameof(tag)); - } - } -} \ No newline at end of file diff --git a/SharpNBT/Events/TagHandledEventArgs.cs b/SharpNBT/Events/TagHandledEventArgs.cs deleted file mode 100644 index e842893..0000000 --- a/SharpNBT/Events/TagHandledEventArgs.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.ComponentModel; -using System.IO; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Arguments supplied when an event that can be handled by an event subscriber. - /// - [PublicAPI] - public class TagHandledEventArgs : HandledEventArgs - { - /// - /// Gets a constant describing the basic NBT type of the tag. - /// - public TagType Type { get; } - - /// - /// Gets flag indicating if this tag is named, only when a tag is a direct child of a . - /// - public bool IsNamed { get; } - - /// - /// Gets the stream being read from, positioned at the beginning of the tag payload. - /// - /// When handling this event, the stream position must be moved to the end of the payload, ready for the next tag to be parsed. - /// - [NotNull] - public Stream Stream { get; } - - /// - /// Gets or sets the resulting tag from this event being handled. - /// - /// This property must set to a non-null value when is . - [CanBeNull] - public Tag Result { get; set; } - - /// - /// Creates a new instance of the class. - /// - /// A constant describing the basic NBT type of the tag. - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// The stream being read from, positioned at the beginning of the tag payload. - /// Thrown when is . - public TagHandledEventArgs(TagType type, bool isNamed, [NotNull] Stream stream) - { - Type = type; - IsNamed = isNamed; - Stream = stream ?? throw new ArgumentNullException(nameof(stream)); - } - } -} \ No newline at end of file diff --git a/SharpNBT/Events/TagReaderCallback.cs b/SharpNBT/Events/TagReaderCallback.cs deleted file mode 100644 index 4f7b7b6..0000000 --- a/SharpNBT/Events/TagReaderCallback.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace SharpNBT -{ - /// - /// Handler for events used with the class. - /// - /// A type derived from . - /// The instance invoking the event. - /// Any relevant args to be supplied with the callback, - public delegate void TagReaderCallback(TagReader reader, T args) where T : EventArgs; -} \ No newline at end of file diff --git a/SharpNBT/FormatOptions.cs b/SharpNBT/FormatOptions.cs deleted file mode 100644 index 99ebfb2..0000000 --- a/SharpNBT/FormatOptions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Describes the specification to use for reading/writing. - /// - /// - /// There are some major changes between the original Java version, and the Bedrock editions of Minecraft that makes them incompatible with one another. - /// Furthermore, the Bedrock editions use a different specification depending on whether it is writing to disk or sending over a network. - /// - /// - [PublicAPI][Flags] - public enum FormatOptions - { - /// - /// None/invalid option flags. - /// - None = 0, - - /// - /// Numeric values will be read/written in big-endian format. - /// - /// This is the default for the Java edition of Minecraft. - BigEndian = 0x01, - - /// - /// Numeric values will be read/written in little-endian format. - /// - /// This is the default for Bedrock editions of Minecraft. - LittleEndian = 0x02, - - /// - /// Integer types will be read/written as variable-length integers. - /// - VarIntegers = 0x04, - - /// - /// Variable-length integers will be written using ZigZag encoding. - /// - /// - ZigZagEncoding = 0x08, - - /// - /// Flags for using a format compatible with Java editions of Minecraft. - /// - Java = BigEndian, - - /// - /// Flags for using a format compatible with Bedrock editions of Minecraft when writing to a file. - /// - BedrockFile = LittleEndian, - - /// - /// Flags for using a format compatible with Bedrock editions of Minecraft when transporting across a network.. - /// - BedrockNetwork = LittleEndian | VarIntegers | ZigZagEncoding - } -} \ No newline at end of file diff --git a/SharpNBT/JetBrains.Annotations.cs b/SharpNBT/JetBrains.Annotations.cs deleted file mode 100644 index a7a2fd4..0000000 --- a/SharpNBT/JetBrains.Annotations.cs +++ /dev/null @@ -1,1355 +0,0 @@ -/* MIT License - -Copyright (c) 2016 JetBrains http://www.jetbrains.com - -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. */ - -using System; - -// ReSharper disable UnusedType.Global - -#pragma warning disable 1591 -// ReSharper disable UnusedMember.Global -// ReSharper disable MemberCanBePrivate.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -// ReSharper disable IntroduceOptionalParameters.Global -// ReSharper disable MemberCanBeProtected.Global -// ReSharper disable InconsistentNaming - -namespace JetBrains.Annotations -{ - /// - /// Indicates that the value of the marked element could be null sometimes, - /// so checking for null is required before its usage. - /// - /// - /// [CanBeNull] object Test() => null; - /// - /// void UseTest() { - /// var p = Test(); - /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | - AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | - AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] -internal sealed class CanBeNullAttribute : Attribute { } - - /// - /// Indicates that the value of the marked element can never be null. - /// - /// - /// [NotNull] object Foo() { - /// return null; // Warning: Possible 'null' assignment - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | - AttributeTargets.Delegate | AttributeTargets.Field | AttributeTargets.Event | - AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.GenericParameter)] -internal sealed class NotNullAttribute : Attribute { } - - /// - /// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task - /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property - /// or of the Lazy.Value property can never be null. - /// - /// - /// public void Foo([ItemNotNull]List<string> books) - /// { - /// foreach (var book in books) { - /// if (book != null) // Warning: Expression is always true - /// Console.WriteLine(book.ToUpper()); - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | - AttributeTargets.Delegate | AttributeTargets.Field)] -internal sealed class ItemNotNullAttribute : Attribute { } - - /// - /// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task - /// and Lazy classes to indicate that the value of a collection item, of the Task.Result property - /// or of the Lazy.Value property can be null. - /// - /// - /// public void Foo([ItemCanBeNull]List<string> books) - /// { - /// foreach (var book in books) - /// { - /// // Warning: Possible 'System.NullReferenceException' - /// Console.WriteLine(book.ToUpper()); - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | - AttributeTargets.Delegate | AttributeTargets.Field)] -internal sealed class ItemCanBeNullAttribute : Attribute { } - - /// - /// Indicates that the marked method builds string by the format pattern and (optional) arguments. - /// The parameter, which contains the format string, should be given in the constructor. The format string - /// should be in -like form. - /// - /// - /// [StringFormatMethod("message")] - /// void ShowError(string message, params object[] args) { /* do something */ } - /// - /// void Foo() { - /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string - /// } - /// - [AttributeUsage( - AttributeTargets.Constructor | AttributeTargets.Method | - AttributeTargets.Property | AttributeTargets.Delegate)] -internal sealed class StringFormatMethodAttribute : Attribute - { - /// - /// Specifies which parameter of an annotated method should be treated as the format string - /// - public StringFormatMethodAttribute([NotNull] string formatParameterName) - { - FormatParameterName = formatParameterName; - } - - [NotNull] public string FormatParameterName { get; } - } - - /// - /// Indicates that the marked parameter is a message template where placeholders are to be replaced by the following arguments - /// in the order in which they appear - /// - /// - /// void LogInfo([StructuredMessageTemplate]string message, params object[] args) { /* do something */ } - /// - /// void Foo() { - /// LogInfo("User created: {username}"); // Warning: Non-existing argument in format string - /// } - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class StructuredMessageTemplateAttribute : Attribute {} - - /// - /// Use this annotation to specify a type that contains static or const fields - /// with values for the annotated property/field/parameter. - /// The specified type will be used to improve completion suggestions. - /// - /// - /// namespace TestNamespace - /// { - /// public class Constants - /// { - /// public static int INT_CONST = 1; - /// public const string STRING_CONST = "1"; - /// } - /// - /// public class Class1 - /// { - /// [ValueProvider("TestNamespace.Constants")] public int myField; - /// public void Foo([ValueProvider("TestNamespace.Constants")] string str) { } - /// - /// public void Test() - /// { - /// Foo(/*try completion here*/);// - /// myField = /*try completion here*/ - /// } - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field, - AllowMultiple = true)] -internal sealed class ValueProviderAttribute : Attribute - { - public ValueProviderAttribute([NotNull] string name) - { - Name = name; - } - - [NotNull] public string Name { get; } - } - - /// - /// Indicates that the integral value falls into the specified interval. - /// It's allowed to specify multiple non-intersecting intervals. - /// Values of interval boundaries are inclusive. - /// - /// - /// void Foo([ValueRange(0, 100)] int value) { - /// if (value == -1) { // Warning: Expression is always 'false' - /// ... - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | - AttributeTargets.Method | AttributeTargets.Delegate, - AllowMultiple = true)] -internal sealed class ValueRangeAttribute : Attribute - { - public object From { get; } - public object To { get; } - - public ValueRangeAttribute(long from, long to) - { - From = from; - To = to; - } - - public ValueRangeAttribute(ulong from, ulong to) - { - From = from; - To = to; - } - - public ValueRangeAttribute(long value) - { - From = To = value; - } - - public ValueRangeAttribute(ulong value) - { - From = To = value; - } - } - - /// - /// Indicates that the integral value never falls below zero. - /// - /// - /// void Foo([NonNegativeValue] int value) { - /// if (value == -1) { // Warning: Expression is always 'false' - /// ... - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | - AttributeTargets.Method | AttributeTargets.Delegate)] -internal sealed class NonNegativeValueAttribute : Attribute { } - - /// - /// Indicates that the function argument should be a string literal and match one - /// of the parameters of the caller function. For example, ReSharper annotates - /// the parameter of . - /// - /// - /// void Foo(string param) { - /// if (param == null) - /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol - /// } - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class InvokerParameterNameAttribute : Attribute { } - - /// - /// Indicates that the method is contained in a type that implements - /// System.ComponentModel.INotifyPropertyChanged interface and this method - /// is used to notify that some property value changed. - /// - /// - /// The method should be non-static and conform to one of the supported signatures: - /// - /// NotifyChanged(string) - /// NotifyChanged(params string[]) - /// NotifyChanged{T}(Expression{Func{T}}) - /// NotifyChanged{T,U}(Expression{Func{T,U}}) - /// SetProperty{T}(ref T, T, string) - /// - /// - /// - /// public class Foo : INotifyPropertyChanged { - /// public event PropertyChangedEventHandler PropertyChanged; - /// - /// [NotifyPropertyChangedInvocator] - /// protected virtual void NotifyChanged(string propertyName) { ... } - /// - /// string _name; - /// - /// public string Name { - /// get { return _name; } - /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } - /// } - /// } - /// - /// Examples of generated notifications: - /// - /// NotifyChanged("Property") - /// NotifyChanged(() => Property) - /// NotifyChanged((VM x) => x.Property) - /// SetProperty(ref myField, value, "Property") - /// - /// - [AttributeUsage(AttributeTargets.Method)] -internal sealed class NotifyPropertyChangedInvocatorAttribute : Attribute - { - public NotifyPropertyChangedInvocatorAttribute() { } - public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) - { - ParameterName = parameterName; - } - - [CanBeNull] public string ParameterName { get; } - } - - /// - /// Describes dependency between method input and output. - /// - /// - ///

Function Definition Table syntax:

- /// - /// FDT ::= FDTRow [;FDTRow]* - /// FDTRow ::= Input => Output | Output <= Input - /// Input ::= ParameterName: Value [, Input]* - /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} - /// Value ::= true | false | null | notnull | canbenull - /// - /// If the method has a single input parameter, its name could be omitted.
- /// Using halt (or void/nothing, which is the same) for the method output - /// means that the method doesn't return normally (throws or terminates the process).
- /// Value canbenull is only applicable for output parameters.
- /// You can use multiple [ContractAnnotation] for each FDT row, or use single attribute - /// with rows separated by the semicolon. There is no notion of order rows, all rows are checked - /// for applicability and applied per each program state tracked by the analysis engine.
- ///
- /// - /// - /// [ContractAnnotation("=> halt")] - /// public void TerminationMethod() - /// - /// - /// [ContractAnnotation("null <= param:null")] // reverse condition syntax - /// public string GetName(string surname) - /// - /// - /// [ContractAnnotation("s:null => true")] - /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() - /// - /// - /// // A method that returns null if the parameter is null, - /// // and not null if the parameter is not null - /// [ContractAnnotation("null => null; notnull => notnull")] - /// public object Transform(object data) - /// - /// - /// [ContractAnnotation("=> true, result: notnull; => false, result: null")] - /// public bool TryParse(string s, out Person result) - /// - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] -internal sealed class ContractAnnotationAttribute : Attribute - { - public ContractAnnotationAttribute([NotNull] string contract) - : this(contract, false) { } - - public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) - { - Contract = contract; - ForceFullStates = forceFullStates; - } - - [NotNull] public string Contract { get; } - - public bool ForceFullStates { get; } - } - - /// - /// Indicates whether the marked element should be localized. - /// - /// - /// [LocalizationRequiredAttribute(true)] - /// class Foo { - /// string str = "my string"; // Warning: Localizable string - /// } - /// - [AttributeUsage(AttributeTargets.All)] -internal sealed class LocalizationRequiredAttribute : Attribute - { - public LocalizationRequiredAttribute() : this(true) { } - - public LocalizationRequiredAttribute(bool required) - { - Required = required; - } - - public bool Required { get; } - } - - /// - /// Indicates that the value of the marked type (or its derivatives) - /// cannot be compared using '==' or '!=' operators and Equals() - /// should be used instead. However, using '==' or '!=' for comparison - /// with null is always permitted. - /// - /// - /// [CannotApplyEqualityOperator] - /// class NoEquality { } - /// - /// class UsesNoEquality { - /// void Test() { - /// var ca1 = new NoEquality(); - /// var ca2 = new NoEquality(); - /// if (ca1 != null) { // OK - /// bool condition = ca1 == ca2; // Warning - /// } - /// } - /// } - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Struct)] -internal sealed class CannotApplyEqualityOperatorAttribute : Attribute { } - - /// - /// When applied to a target attribute, specifies a requirement for any type marked - /// with the target attribute to implement or inherit specific type or types. - /// - /// - /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement - /// class ComponentAttribute : Attribute { } - /// - /// [Component] // ComponentAttribute requires implementing IComponent interface - /// class MyComponent : IComponent { } - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - [BaseTypeRequired(typeof(Attribute))] -internal sealed class BaseTypeRequiredAttribute : Attribute - { - public BaseTypeRequiredAttribute([NotNull] Type baseType) - { - BaseType = baseType; - } - - [NotNull] public Type BaseType { get; } - } - - /// - /// Indicates that the marked symbol is used implicitly (e.g. via reflection, in external library), - /// so this symbol will be ignored by usage-checking inspections.
- /// You can use and - /// to configure how this attribute is applied. - ///
- /// - /// [UsedImplicitly] - /// public class TypeConverter {} - /// - /// public class SummaryData - /// { - /// [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] - /// public SummaryData() {} - /// } - /// - /// [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors | ImplicitUseTargetFlags.Default)] - /// public interface IService {} - /// - [AttributeUsage(AttributeTargets.All)] -internal sealed class UsedImplicitlyAttribute : Attribute - { - public UsedImplicitlyAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } - - public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) { } - - public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) { } - - public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) - { - UseKindFlags = useKindFlags; - TargetFlags = targetFlags; - } - - public ImplicitUseKindFlags UseKindFlags { get; } - - public ImplicitUseTargetFlags TargetFlags { get; } - } - - /// - /// Can be applied to attributes, type parameters, and parameters of a type assignable from . - /// When applied to an attribute, the decorated attribute behaves the same as . - /// When applied to a type parameter or to a parameter of type , - /// indicates that the corresponding type is used implicitly. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter | AttributeTargets.Parameter)] -internal sealed class MeansImplicitUseAttribute : Attribute - { - public MeansImplicitUseAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } - - public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) { } - - public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) { } - - public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) - { - UseKindFlags = useKindFlags; - TargetFlags = targetFlags; - } - - [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; } - - [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; } - } - - /// - /// Specifies the details of implicitly used symbol when it is marked - /// with or . - /// - [Flags] -internal enum ImplicitUseKindFlags - { - Default = Access | Assign | InstantiatedWithFixedConstructorSignature, - /// Only entity marked with attribute considered used. - Access = 1, - /// Indicates implicit assignment to a member. - Assign = 2, - /// - /// Indicates implicit instantiation of a type with fixed constructor signature. - /// That means any unused constructor parameters won't be reported as such. - /// - InstantiatedWithFixedConstructorSignature = 4, - /// Indicates implicit instantiation of a type. - InstantiatedNoFixedConstructorSignature = 8, - } - - /// - /// Specifies what is considered to be used implicitly when marked - /// with or . - /// - [Flags] -internal enum ImplicitUseTargetFlags - { - Default = Itself, - Itself = 1, - /// Members of the type marked with the attribute are considered used. - Members = 2, - /// Inherited entities are considered used. - WithInheritors = 4, - /// Entity marked with the attribute and all its members considered used. - WithMembers = Itself | Members - } - - /// - /// This attribute is intended to mark publicly available API, - /// which should not be removed and so is treated as used. - /// - [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] - [AttributeUsage(AttributeTargets.All, Inherited = false)] -internal sealed class PublicAPIAttribute : Attribute - { - public PublicAPIAttribute() { } - - public PublicAPIAttribute([NotNull] string comment) - { - Comment = comment; - } - - [CanBeNull] public string Comment { get; } - } - - /// - /// Tells the code analysis engine if the parameter is completely handled when the invoked method is on stack. - /// If the parameter is a delegate, indicates that delegate is executed while the method is executed. - /// If the parameter is an enumerable, indicates that it is enumerated while the method is executed. - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class InstantHandleAttribute : Attribute { } - - /// - /// Indicates that a method does not make any observable state changes. - /// The same as System.Diagnostics.Contracts.PureAttribute. - /// - /// - /// [Pure] int Multiply(int x, int y) => x * y; - /// - /// void M() { - /// Multiply(123, 42); // Warning: Return value of pure method is not used - /// } - /// - [AttributeUsage(AttributeTargets.Method)] -internal sealed class PureAttribute : Attribute { } - - /// - /// Indicates that the return value of the method invocation must be used. - /// - /// - /// Methods decorated with this attribute (in contrast to pure methods) might change state, - /// but make no sense without using their return value.
- /// Similarly to , this attribute - /// will help to detect usages of the method when the return value is not used. - /// Optionally, you can specify a message to use when showing warnings, e.g. - /// [MustUseReturnValue("Use the return value to...")]. - ///
- [AttributeUsage(AttributeTargets.Method)] -internal sealed class MustUseReturnValueAttribute : Attribute - { - public MustUseReturnValueAttribute() { } - - public MustUseReturnValueAttribute([NotNull] string justification) - { - Justification = justification; - } - - [CanBeNull] public string Justification { get; } - } - - /// - /// This annotation allows to enforce allocation-less usage patterns of delegates for performance-critical APIs. - /// When this annotation is applied to the parameter of delegate type, IDE checks the input argument of this parameter: - /// * When lambda expression or anonymous method is passed as an argument, IDE verifies that the passed closure - /// has no captures of the containing local variables and the compiler is able to cache the delegate instance - /// to avoid heap allocations. Otherwise the warning is produced. - /// * IDE warns when method name or local function name is passed as an argument as this always results - /// in heap allocation of the delegate instance. - /// - /// - /// In C# 9.0 code IDE would also suggest to annotate the anonymous function with 'static' modifier - /// to make use of the similar analysis provided by the language/compiler. - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal class RequireStaticDelegateAttribute : Attribute - { - public bool IsError { get; set; } - } - - /// - /// Indicates the type member or parameter of some type, that should be used instead of all other ways - /// to get the value of that type. This annotation is useful when you have some "context" value evaluated - /// and stored somewhere, meaning that all other ways to get this value must be consolidated with existing one. - /// - /// - /// class Foo { - /// [ProvidesContext] IBarService _barService = ...; - /// - /// void ProcessNode(INode node) { - /// DoSomething(node, node.GetGlobalServices().Bar); - /// // ^ Warning: use value of '_barService' field - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Method | - AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.GenericParameter)] -internal sealed class ProvidesContextAttribute : Attribute { } - - /// - /// Indicates that a parameter is a path to a file or a folder within a web project. - /// Path can be relative or absolute, starting from web root (~). - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class PathReferenceAttribute : Attribute - { - public PathReferenceAttribute() { } - - public PathReferenceAttribute([NotNull, PathReference] string basePath) - { - BasePath = basePath; - } - - [CanBeNull] public string BasePath { get; } - } - - /// - /// An extension method marked with this attribute is processed by code completion - /// as a 'Source Template'. When the extension method is completed over some expression, its source code - /// is automatically expanded like a template at call site. - /// - /// - /// Template method body can contain valid source code and/or special comments starting with '$'. - /// Text inside these comments is added as source code when the template is applied. Template parameters - /// can be used either as additional method parameters or as identifiers wrapped in two '$' signs. - /// Use the attribute to specify macros for parameters. - /// - /// - /// In this example, the 'forEach' method is a source template available over all values - /// of enumerable types, producing ordinary C# 'foreach' statement and placing caret inside block: - /// - /// [SourceTemplate] - /// public static void forEach<T>(this IEnumerable<T> xs) { - /// foreach (var x in xs) { - /// //$ $END$ - /// } - /// } - /// - /// - [AttributeUsage(AttributeTargets.Method)] -internal sealed class SourceTemplateAttribute : Attribute { } - - /// - /// Allows specifying a macro for a parameter of a source template. - /// - /// - /// You can apply the attribute on the whole method or on any of its additional parameters. The macro expression - /// is defined in the property. When applied on a method, the target - /// template parameter is defined in the property. To apply the macro silently - /// for the parameter, set the property value = -1. - /// - /// - /// Applying the attribute on a source template method: - /// - /// [SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")] - /// public static void forEach<T>(this IEnumerable<T> collection) { - /// foreach (var item in collection) { - /// //$ $END$ - /// } - /// } - /// - /// Applying the attribute on a template method parameter: - /// - /// [SourceTemplate] - /// public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid) { - /// /*$ var $x$Id = "$newguid$" + x.ToString(); - /// x.DoSomething($x$Id); */ - /// } - /// - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = true)] -internal sealed class MacroAttribute : Attribute - { - /// - /// Allows specifying a macro that will be executed for a source template - /// parameter when the template is expanded. - /// - [CanBeNull] public string Expression { get; set; } - - /// - /// Allows specifying which occurrence of the target parameter becomes editable when the template is deployed. - /// - /// - /// If the target parameter is used several times in the template, only one occurrence becomes editable; - /// other occurrences are changed synchronously. To specify the zero-based index of the editable occurrence, - /// use values >= 0. To make the parameter non-editable when the template is expanded, use -1. - /// - public int Editable { get; set; } - - /// - /// Identifies the target parameter of a source template if the - /// is applied on a template method. - /// - [CanBeNull] public string Target { get; set; } - } - - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] -internal sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute - { - public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) - { - Format = format; - } - - [NotNull] public string Format { get; } - } - - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] -internal sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute - { - public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) - { - Format = format; - } - - [NotNull] public string Format { get; } - } - - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] -internal sealed class AspMvcAreaViewLocationFormatAttribute : Attribute - { - public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) - { - Format = format; - } - - [NotNull] public string Format { get; } - } - - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] -internal sealed class AspMvcMasterLocationFormatAttribute : Attribute - { - public AspMvcMasterLocationFormatAttribute([NotNull] string format) - { - Format = format; - } - - [NotNull] public string Format { get; } - } - - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] -internal sealed class AspMvcPartialViewLocationFormatAttribute : Attribute - { - public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) - { - Format = format; - } - - [NotNull] public string Format { get; } - } - - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)] -internal sealed class AspMvcViewLocationFormatAttribute : Attribute - { - public AspMvcViewLocationFormatAttribute([NotNull] string format) - { - Format = format; - } - - [NotNull] public string Format { get; } - } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC action. If applied to a method, the MVC action name is calculated - /// implicitly from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcActionAttribute : Attribute - { - public AspMvcActionAttribute() { } - - public AspMvcActionAttribute([NotNull] string anonymousProperty) - { - AnonymousProperty = anonymousProperty; - } - - [CanBeNull] public string AnonymousProperty { get; } - } - - /// - /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC area. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcAreaAttribute : Attribute - { - public AspMvcAreaAttribute() { } - - public AspMvcAreaAttribute([NotNull] string anonymousProperty) - { - AnonymousProperty = anonymousProperty; - } - - [CanBeNull] public string AnonymousProperty { get; } - } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is - /// an MVC controller. If applied to a method, the MVC controller name is calculated - /// implicitly from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcControllerAttribute : Attribute - { - public AspMvcControllerAttribute() { } - - public AspMvcControllerAttribute([NotNull] string anonymousProperty) - { - AnonymousProperty = anonymousProperty; - } - - [CanBeNull] public string AnonymousProperty { get; } - } - - /// - /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC Master. Use this attribute - /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcMasterAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC model type. Use this attribute - /// for custom wrappers similar to System.Web.Mvc.Controller.View(String, Object). - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class AspMvcModelTypeAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter is an MVC - /// partial view. If applied to a method, the MVC partial view name is calculated implicitly - /// from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcPartialViewAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Allows disabling inspections for MVC views within a class or a method. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] -internal sealed class AspMvcSuppressViewErrorAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcDisplayTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC editor template. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcEditorTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that the marked parameter is an MVC template. - /// Use this attribute for custom wrappers similar to - /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC view component. If applied to a method, the MVC view name is calculated implicitly - /// from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(Object). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcViewAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC view component name. - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcViewComponentAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC view component view. If applied to a method, the MVC view component view name is default. - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class AspMvcViewComponentViewAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. When applied to a parameter of an attribute, - /// indicates that this parameter is an MVC action name. - /// - /// - /// [ActionName("Foo")] - /// public ActionResult Login(string returnUrl) { - /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK - /// return RedirectToAction("Bar"); // Error: Cannot resolve action - /// } - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] -internal sealed class AspMvcActionSelectorAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)] -internal sealed class HtmlElementAttributesAttribute : Attribute - { - public HtmlElementAttributesAttribute() { } - - public HtmlElementAttributesAttribute([NotNull] string name) - { - Name = name; - } - - [CanBeNull] public string Name { get; } - } - - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class HtmlAttributeValueAttribute : Attribute - { - public HtmlAttributeValueAttribute([NotNull] string name) - { - Name = name; - } - - [NotNull] public string Name { get; } - } - - /// - /// Razor attribute. Indicates that the marked parameter or method is a Razor section. - /// Use this attribute for custom wrappers similar to - /// System.Web.WebPages.WebPageBase.RenderSection(String). - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] -internal sealed class RazorSectionAttribute : Attribute { } - - /// - /// Indicates how method, constructor invocation, or property access - /// over collection type affects the contents of the collection. - /// Use to specify the access type. - /// - /// - /// Using this attribute only makes sense if all collection methods are marked with this attribute. - /// - /// - /// public class MyStringCollection : List<string> - /// { - /// [CollectionAccess(CollectionAccessType.Read)] - /// public string GetFirstString() - /// { - /// return this.ElementAt(0); - /// } - /// } - /// class Test - /// { - /// public void Foo() - /// { - /// // Warning: Contents of the collection is never updated - /// var col = new MyStringCollection(); - /// string x = col.GetFirstString(); - /// } - /// } - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] -internal sealed class CollectionAccessAttribute : Attribute - { - public CollectionAccessAttribute(CollectionAccessType collectionAccessType) - { - CollectionAccessType = collectionAccessType; - } - - public CollectionAccessType CollectionAccessType { get; } - } - - /// - /// Provides a value for the to define - /// how the collection method invocation affects the contents of the collection. - /// - [Flags] -internal enum CollectionAccessType - { - /// Method does not use or modify content of the collection. - None = 0, - /// Method only reads content of the collection but does not modify it. - Read = 1, - /// Method can change content of the collection but does not add new elements. - ModifyExistingContent = 2, - /// Method can add new elements to the collection. - UpdatedContent = ModifyExistingContent | 4 - } - - /// - /// Indicates that the marked method is assertion method, i.e. it halts the control flow if - /// one of the conditions is satisfied. To set the condition, mark one of the parameters with - /// attribute. - /// - [AttributeUsage(AttributeTargets.Method)] -internal sealed class AssertionMethodAttribute : Attribute { } - - /// - /// Indicates the condition parameter of the assertion method. The method itself should be - /// marked by attribute. The mandatory argument of - /// the attribute is the assertion type. - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class AssertionConditionAttribute : Attribute - { - public AssertionConditionAttribute(AssertionConditionType conditionType) - { - ConditionType = conditionType; - } - - public AssertionConditionType ConditionType { get; } - } - - /// - /// Specifies assertion type. If the assertion method argument satisfies the condition, - /// then the execution continues. Otherwise, execution is assumed to be halted. - /// -internal enum AssertionConditionType - { - /// Marked parameter should be evaluated to true. - IS_TRUE = 0, - /// Marked parameter should be evaluated to false. - IS_FALSE = 1, - /// Marked parameter should be evaluated to null value. - IS_NULL = 2, - /// Marked parameter should be evaluated to not null value. - IS_NOT_NULL = 3, - } - - /// - /// Indicates that the marked method unconditionally terminates control flow execution. - /// For example, it could unconditionally throw exception. - /// - [Obsolete("Use [ContractAnnotation('=> halt')] instead")] - [AttributeUsage(AttributeTargets.Method)] -internal sealed class TerminatesProgramAttribute : Attribute { } - - /// - /// Indicates that the method is a pure LINQ method, with postponed enumeration (like Enumerable.Select, - /// .Where). This annotation allows inference of [InstantHandle] annotation for parameters - /// of delegate type by analyzing LINQ method chains. - /// - [AttributeUsage(AttributeTargets.Method)] -internal sealed class LinqTunnelAttribute : Attribute { } - - /// - /// Indicates that IEnumerable passed as a parameter is not enumerated. - /// Use this annotation to suppress the 'Possible multiple enumeration of IEnumerable' inspection. - /// - /// - /// static void ThrowIfNull<T>([NoEnumeration] T v, string n) where T : class - /// { - /// // custom check for null but no enumeration - /// } - /// - /// void Foo(IEnumerable<string> values) - /// { - /// ThrowIfNull(values, nameof(values)); - /// var x = values.ToList(); // No warnings about multiple enumeration - /// } - /// - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class NoEnumerationAttribute : Attribute { } - - /// - /// Indicates that the marked parameter, field, or property is a regular expression pattern. - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class RegexPatternAttribute : Attribute { } - - /// - /// Prevents the Member Reordering feature from tossing members of the marked class. - /// - /// - /// The attribute must be mentioned in your member reordering patterns. - /// - [AttributeUsage( - AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum)] -internal sealed class NoReorderAttribute : Attribute { } - - /// - /// XAML attribute. Indicates the type that has ItemsSource property and should be treated - /// as ItemsControl-derived type, to enable inner items DataContext type resolve. - /// - [AttributeUsage(AttributeTargets.Class)] -internal sealed class XamlItemsControlAttribute : Attribute { } - - /// - /// XAML attribute. Indicates the property of some BindingBase-derived type, that - /// is used to bind some item of ItemsControl-derived type. This annotation will - /// enable the DataContext type resolve for XAML bindings for such properties. - /// - /// - /// Property should have the tree ancestor of the ItemsControl type or - /// marked with the attribute. - /// - [AttributeUsage(AttributeTargets.Property)] -internal sealed class XamlItemBindingOfItemsControlAttribute : Attribute { } - - /// - /// XAML attribute. Indicates the property of some Style-derived type, that - /// is used to style items of ItemsControl-derived type. This annotation will - /// enable the DataContext type resolve for XAML bindings for such properties. - /// - /// - /// Property should have the tree ancestor of the ItemsControl type or - /// marked with the attribute. - /// - [AttributeUsage(AttributeTargets.Property)] -internal sealed class XamlItemStyleOfItemsControlAttribute : Attribute { } - - /// - /// XAML attribute. Indicates that DependencyProperty has OneWay binding mode by default. - /// - /// - /// This attribute must be applied to DependencyProperty's CLR accessor property if it is present, to DependencyProperty descriptor field otherwise. - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class XamlOneWayBindingModeByDefaultAttribute : Attribute { } - - /// - /// XAML attribute. Indicates that DependencyProperty has TwoWay binding mode by default. - /// - /// - /// This attribute must be applied to DependencyProperty's CLR accessor property if it is present, to DependencyProperty descriptor field otherwise. - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class XamlTwoWayBindingModeByDefaultAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -internal sealed class AspChildControlTypeAttribute : Attribute - { - public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) - { - TagName = tagName; - ControlType = controlType; - } - - [NotNull] public string TagName { get; } - - [NotNull] public Type ControlType { get; } - } - - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] -internal sealed class AspDataFieldAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] -internal sealed class AspDataFieldsAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Property)] -internal sealed class AspMethodPropertyAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -internal sealed class AspRequiredAttributeAttribute : Attribute - { - public AspRequiredAttributeAttribute([NotNull] string attribute) - { - Attribute = attribute; - } - - [NotNull] public string Attribute { get; } - } - - [AttributeUsage(AttributeTargets.Property)] -internal sealed class AspTypePropertyAttribute : Attribute - { - public bool CreateConstructorReferences { get; } - - public AspTypePropertyAttribute(bool createConstructorReferences) - { - CreateConstructorReferences = createConstructorReferences; - } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -internal sealed class RazorImportNamespaceAttribute : Attribute - { - public RazorImportNamespaceAttribute([NotNull] string name) - { - Name = name; - } - - [NotNull] public string Name { get; } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -internal sealed class RazorInjectionAttribute : Attribute - { - public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) - { - Type = type; - FieldName = fieldName; - } - - [NotNull] public string Type { get; } - - [NotNull] public string FieldName { get; } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -internal sealed class RazorDirectiveAttribute : Attribute - { - public RazorDirectiveAttribute([NotNull] string directive) - { - Directive = directive; - } - - [NotNull] public string Directive { get; } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -internal sealed class RazorPageBaseTypeAttribute : Attribute - { - public RazorPageBaseTypeAttribute([NotNull] string baseType) - { - BaseType = baseType; - } - public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName) - { - BaseType = baseType; - PageName = pageName; - } - - [NotNull] public string BaseType { get; } - [CanBeNull] public string PageName { get; } - } - - [AttributeUsage(AttributeTargets.Method)] -internal sealed class RazorHelperCommonAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Property)] -internal sealed class RazorLayoutAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Method)] -internal sealed class RazorWriteLiteralMethodAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Method)] -internal sealed class RazorWriteMethodAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Parameter)] -internal sealed class RazorWriteMethodParameterAttribute : Attribute { } - - /// - /// Indicates that the marked parameter, field, or property is a route template. - /// - /// - /// This attribute allows IDE to recognize the use of web frameworks' route templates - /// to enable syntax highlighting, code completion, navigation, rename and other features in string literals. - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class RouteTemplateAttribute : Attribute { } - - /// - /// Indicates that the marked type is custom route parameter constraint, - /// which is registered in application's Startup with name ConstraintName - /// - /// - /// You can specify ProposedType if target constraint matches only route parameters of specific type, - /// it will allow IDE to create method's parameter from usage in route template - /// with specified type instead of default System.String - /// and check if constraint's proposed type conflicts with matched parameter's type - /// - [AttributeUsage(AttributeTargets.Class)] -internal sealed class RouteParameterConstraintAttribute : Attribute - { - [NotNull] public string ConstraintName { get; } - [CanBeNull] public Type ProposedType { get; set; } - - public RouteParameterConstraintAttribute([NotNull] string constraintName) - { - ConstraintName = constraintName; - } - } - - /// - /// Indicates that the marked parameter, field, or property is an URI string. - /// - /// - /// This attribute enables code completion, navigation, rename and other features - /// in URI string literals assigned to annotated parameter, field or property. - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)] -internal sealed class UriStringAttribute : Attribute - { - public UriStringAttribute() { } - - public UriStringAttribute(string httpVerb) - { - HttpVerb = httpVerb; - } - - [CanBeNull] public string HttpVerb { get; } - } -} diff --git a/SharpNBT/NbtFile.cs b/SharpNBT/NbtFile.cs deleted file mode 100644 index 901ea09..0000000 --- a/SharpNBT/NbtFile.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Threading.Tasks; -using JetBrains.Annotations; -using SharpNBT.ZLib; - -namespace SharpNBT -{ - /// - /// Provides static convenience methods for working with NBT-formatted files, including both reading and writing. - /// - [PublicAPI] - public static class NbtFile - { - - /// - /// Reads a file at the given and deserializes the top-level contained in the file. - /// - /// The path to the file to be read. - /// Indicates the compression algorithm used to compress the file. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// The type of tag to deserialize. - /// The deserialized instance. - public static T Read([NotNull] string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) where T : TagContainer - { - using var reader = new TagReader(GetReadStream(path, compression), options); - return reader.ReadTag(); - } - - /// - /// Reads a file at the given and deserializes the top-level contained in the file. - /// - /// The path to the file to be read. - /// Indicates the compression algorithm used to compress the file. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// The deserialized instance. - public static CompoundTag Read([NotNull] string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) - { - using var reader = new TagReader(GetReadStream(path, compression), options); - return reader.ReadTag(); - } - - /// - /// Asynchronously reads a file at the given and deserializes the top-level contained in the file. - /// - /// The path to the file to be read. - /// Indicates the compression algorithm used to compress the file. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// The deserialized instance. - public static async Task ReadAsync([NotNull] string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) where T : TagContainer - { - await using var reader = new TagReader(GetReadStream(path, compression), options); - return await reader.ReadTagAsync(); - } - - /// - /// Asynchronously reads a file at the given and deserializes the top-level contained in the file. - /// - /// The path to the file to be read. - /// Indicates the compression algorithm used to compress the file. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// The deserialized instance. - public static async Task ReadAsync([NotNull] string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) - { - await using var reader = new TagReader(GetReadStream(path, compression), options); - return await reader.ReadTagAsync(); - } - - /// - /// Writes the given to a file at the specified . - /// - /// The path to the file to be written to. - /// The top-level instance to be serialized. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// A flag indicating the type of compression to use. - /// Indicates a compression strategy to be used, if any. - public static void Write([NotNull] string path, [NotNull] CompoundTag tag, FormatOptions options, CompressionType type = CompressionType.GZip, CompressionLevel level = CompressionLevel.Fastest) - { - using var stream = File.OpenWrite(path); - using var writer = new TagWriter(GetWriteStream(stream, type, level), options); - writer.WriteTag(tag); - } - - /// - public static void Write([NotNull] string path, [NotNull] ListTag tag, FormatOptions options, CompressionType type = CompressionType.GZip, CompressionLevel level = CompressionLevel.Fastest) - { - using var stream = File.OpenWrite(path); - using var writer = new TagWriter(GetWriteStream(stream, type, level), options); - writer.WriteTag(tag); - } - - /// - /// Asynchronously writes the given to a file at the specified . - /// - /// The path to the file to be written to. - /// The top-level instance to be serialized. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// A flag indicating the type of compression to use. - /// Indicates a compression strategy to be used, if any. - public static async Task WriteAsync([NotNull] string path, [NotNull] CompoundTag tag, FormatOptions options, CompressionType type = CompressionType.GZip, CompressionLevel level = CompressionLevel.Fastest) - { - await using var stream = File.OpenWrite(path); - await using var writer = new TagWriter(GetWriteStream(stream, type, level), options); - await writer.WriteTagAsync(tag); - } - - /// - public static async Task WriteAsync([NotNull] string path, [NotNull] ListTag tag, FormatOptions options, CompressionType type = CompressionType.GZip, CompressionLevel level = CompressionLevel.Fastest) - { - await using var stream = File.OpenWrite(path); - await using var writer = new TagWriter(GetWriteStream(stream, type, level), options); - await writer.WriteTagAsync(tag); - } - - /// - /// Opens an existing NBT file for reading, and returns a instance for it. - /// - /// The path of the file to query write. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// Indicates the compression algorithm used to compress the file. - /// A instance for the file stream. - /// File compression will be automatically detected and used handled when necessary. - public static TagReader OpenRead([NotNull] string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) - { - return new TagReader(GetReadStream(path, compression), options); - } - - /// - /// Opens an existing NBT file or creates a new one if one if it does not exist, and returns a instance for it. - /// - /// The path of the file to query write. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// A flag indicating the type of compression to use. - /// A flag indicating the compression strategy that will be used, if any. - /// A instance for the file stream. - public static TagWriter OpenWrite([NotNull] string path, FormatOptions options, CompressionType type = CompressionType.GZip, CompressionLevel level = CompressionLevel.Fastest) - { - var stream = GetWriteStream(File.OpenWrite(path), type, level); - return new TagWriter(stream, options); - } - - private static Stream GetWriteStream(Stream stream, CompressionType type, CompressionLevel level) - { - switch (type) - { - case CompressionType.None: return stream; - case CompressionType.GZip: return new GZipStream(stream, level, false); - case CompressionType.ZLib: return new ZLibStream(stream, level); - case CompressionType.AutoDetect: - throw new ArgumentOutOfRangeException(nameof(type), Strings.AutoDetectNotValid); - default: - throw new ArgumentOutOfRangeException(nameof(type), type, null); - } - } - - private static Stream GetReadStream(string path, CompressionType compression) - { - var stream = File.OpenRead(path); - if (compression == CompressionType.AutoDetect) - { - var firstByte = (byte) stream.ReadByte(); - stream.Seek(0, SeekOrigin.Begin); - - compression = firstByte switch - { - 0x78 => CompressionType.ZLib, - 0x1F => CompressionType.GZip, - 0x08 => CompressionType.None, // ListTag (valid in Bedrock) - 0x0A => CompressionType.None, // CompoundTag - _ => throw new FormatException(Strings.CannotDetectCompression) - }; - } - - return compression switch - { - CompressionType.None => stream, - CompressionType.GZip => new GZipStream(stream, CompressionMode.Decompress, false), - CompressionType.ZLib => new ZLibStream(stream, CompressionMode.Decompress), - _ => throw new ArgumentOutOfRangeException(nameof(compression), compression, null) - }; - } - - } -} \ No newline at end of file diff --git a/SharpNBT/SNBT/Lexer.cs b/SharpNBT/SNBT/Lexer.cs deleted file mode 100644 index 03fb767..0000000 --- a/SharpNBT/SNBT/Lexer.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using System.Data; - -namespace SharpNBT.SNBT -{ - internal sealed class Lexer - { - private readonly List ruleList; - - public Lexer() - { - ruleList = new List(); - } - - public void AddRule(TokenType type, string pattern, bool skipped = false) => ruleList.Add(new LexerRule(type, pattern, null, skipped)); - - public void AddRule(TokenType type, string pattern, ResultHandler handler, bool skipped = false) - { - ruleList.Add(new LexerRule(type, pattern, handler, skipped)); - } - - public IEnumerable Tokenize(string source) - { - var index = 0; - while (index < source.Length) - { - var success = false; - - foreach (var rule in ruleList) - { - var match = rule.Pattern.Match(source, index); - if (!match.Success || match.Index - index != 0) - continue; - - if (!rule.IsSkipped) - yield return new Token(rule.Type, rule.Process(source, index, match)); - - index += match.Length; - success = true; - break; - } - - if (!success) - throw new SyntaxErrorException($"Unrecognized sequence at index {index}: '{source[index]}'"); - } - } - - - } -} \ No newline at end of file diff --git a/SharpNBT/SNBT/LexerRule.cs b/SharpNBT/SNBT/LexerRule.cs deleted file mode 100644 index f282754..0000000 --- a/SharpNBT/SNBT/LexerRule.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Text.RegularExpressions; - -namespace SharpNBT.SNBT -{ - - internal delegate string ResultHandler(Match match); - - internal class LexerRule - { - private readonly ResultHandler processResult; - - public TokenType Type { get; } - - public Regex Pattern { get; } - - public bool IsSkipped { get; } - - - public LexerRule(TokenType type, string pattern, bool skipped = false) : this(type, pattern, null, skipped) - { - } - - public LexerRule(TokenType type, string pattern, ResultHandler handler, bool skipped = false) - { - Type = type; - Pattern = new Regex(pattern, RegexOptions.Compiled); - IsSkipped = skipped; - processResult = handler; - } - - public string Process(string source, int index, Match match) - { - return processResult is null ? source.Substring(index, match.Length) : processResult.Invoke(match); - } - } -} \ No newline at end of file diff --git a/SharpNBT/SNBT/StringNbt.cs b/SharpNBT/SNBT/StringNbt.cs deleted file mode 100644 index d8fe429..0000000 --- a/SharpNBT/SNBT/StringNbt.cs +++ /dev/null @@ -1,250 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using JetBrains.Annotations; - -namespace SharpNBT.SNBT -{ - /// - /// Provides static methods for parsing string-NBT (SNBT) source text into a complete . - /// - [PublicAPI] - public static class StringNbt - { - private static readonly Lexer lexer; - - static StringNbt() - { - lexer = new Lexer(); - lexer.AddRule(TokenType.Whitespace, @"(\r|\t|\v|\f|\s)+?", true); - lexer.AddRule(TokenType.Separator, ",", true); - lexer.AddRule(TokenType.Compound, @"{"); - lexer.AddRule(TokenType.EndCompound, @"}"); - lexer.AddRule(TokenType.Identifier, "\"(.*?)\"\\s*(?>:)", FirstGroupValue); - lexer.AddRule(TokenType.Identifier, "'(.*?)'\\s*(?>:)", FirstGroupValue); - lexer.AddRule(TokenType.Identifier, "([A-Za-z0-9_-]+)\\s*(?>:)", FirstGroupValue); - lexer.AddRule(TokenType.String, "\"(.*?)\"", FirstGroupValue); - lexer.AddRule(TokenType.String, "'(.*?)'", FirstGroupValue); - lexer.AddRule(TokenType.ByteArray, @"\[B;"); - lexer.AddRule(TokenType.IntArray, @"\[I;"); - lexer.AddRule(TokenType.LongArray, @"\[L;"); - lexer.AddRule(TokenType.List, @"\["); - 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); - lexer.AddRule(TokenType.Int, "(-?[0-9]+)", FirstGroupValue); - } - - /// - /// Parse the text in the given into a . - /// - /// A containing the SNBT data. - /// The number of bytes to read from the , advancing its position. - /// The instance described in the source text. - /// When is . - /// When is not opened for reading. - /// When is negative. - /// When contains invalid SNBT code. - [NotNull] - public static CompoundTag Parse(Stream stream, int length) - { - Validate(stream, length); - if (length == 0) - return new CompoundTag(null); - - var buffer = new byte[length]; - stream.Read(buffer, 0, length); - var str = Encoding.UTF8.GetString(buffer, 0, buffer.Length); - - return Parse(str); - } - - /// - /// Asynchronously parses the text in the given into a . - /// - /// A containing the SNBT data. - /// The number of bytes to read from the , advancing its position. - /// The instance described in the source text. - /// When is . - /// When is not opened for reading. - /// When is negative. - /// When contains invalid SNBT code. - [NotNull] - public static async Task ParseAsync(Stream stream, int length) - { - Validate(stream, length); - if (length == 0) - return new CompoundTag(null); - - var buffer = new byte[length]; - await stream.ReadAsync(buffer, 0, length); - var str = Encoding.UTF8.GetString(buffer, 0, buffer.Length); - - return Parse(str); - } - - private static void Validate(Stream stream, int length) - { - if (stream is null) - throw new ArgumentNullException(nameof(stream)); - if (!stream.CanRead) - throw new IOException("Stream is not opened for reading."); - - if (length < 0) - throw new ArgumentException(Strings.NegativeLengthSpecified, nameof(length)); - } - - /// - /// Parse the given text into a . - /// - /// A string containing the SNBT code to parse. - /// The instance described in the source text. - /// When is . - /// When is invalid SNBT code. - [NotNull] - public static CompoundTag Parse([NotNull] string source) - { - if (source is null) - throw new ArgumentNullException(nameof(source)); - - if (string.IsNullOrWhiteSpace(source)) - return new CompoundTag(null); - - var queue = new Queue(lexer.Tokenize(source)); - return Parse(queue); - } - - private static T Parse(Queue queue) where T : Tag => (T)Parse(queue); - - private static Tag Parse(Queue queue) - { - string name = null; - var token = MoveNext(queue); - - if (token.Type == TokenType.Identifier) - { - name = token.Value; - token = MoveNext(queue); - } - - return token.Type switch - { - TokenType.Compound => ParseCompound(name, queue), - TokenType.String => new StringTag(name, token.Value), - TokenType.ByteArray => ParseByteArray(name, queue), - 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)), - TokenType.Long => new LongTag(name, long.Parse(token.Value)), - TokenType.Float => new FloatTag(name, float.Parse(token.Value)), - TokenType.Double => new DoubleTag(name, double.Parse(token.Value)), - _ => throw new SyntaxErrorException() - }; - } - - [NotNull] - private static Token MoveNext(Queue queue) - { - if (queue.TryDequeue(out var token)) - return token; - - throw new SyntaxErrorException("Unexpected end-of-input"); - } - - private static void MoveNext(Queue queue, TokenType assertType) - { - var token = MoveNext(queue); - if (token.Type != assertType) - throw new SyntaxErrorException($"Expected token of type {assertType}, but encountered {token.Type}."); - } - - private static CompoundTag ParseCompound(string name, Queue queue) - { - var compound = new CompoundTag(name); - while (queue.TryPeek(out var token) && token.Type != TokenType.EndCompound) - { - compound.Add(Parse(queue)); - } - MoveNext(queue, TokenType.EndCompound); - return compound; - } - - private static ListTag ParseList(string name, Queue queue) - { - var values = new List(); - while (queue.TryPeek(out var token) && token.Type != TokenType.EndArray) - { - values.Add(Parse(queue)); - } - - MoveNext(queue, TokenType.EndArray); - if (values.Count > 0) - { - var type = values[0].Type; - return new ListTag(name, type, values); - } - return new ListTag(name, TagType.End); - } - - private static ByteArrayTag ParseByteArray(string name, Queue queue) - { - var values = new List(); - foreach (var token in DequeueUntil(queue, TokenType.EndArray)) - { - if (token.Type != TokenType.Byte) - throw new SyntaxErrorException($"Invalid token type in array, expected {TokenType.Byte}, got {token.Type}."); - values.Add(unchecked((byte) sbyte.Parse(token.Value))); - } - return new ByteArrayTag(name, values); - } - - private static IntArrayTag ParseIntArray(string name, Queue queue) - { - var values = new List(); - foreach (var token in DequeueUntil(queue, TokenType.EndArray)) - { - if (token.Type != TokenType.Int) - throw new SyntaxErrorException($"Invalid token type in array, expected {TokenType.Int}, got {token.Type}."); - values.Add(int.Parse(token.Value)); - } - return new IntArrayTag(name, values); - } - - private static LongArrayTag ParseLongArray(string name, Queue queue) - { - var values = new List(); - foreach (var token in DequeueUntil(queue, TokenType.EndArray)) - { - if (token.Type != TokenType.Long) - throw new SyntaxErrorException($"Invalid token type in array, expected {TokenType.Long}, got {token.Type}."); - values.Add(long.Parse(token.Value)); - } - return new LongArrayTag(name, values); - } - - private static IEnumerable DequeueUntil(Queue queue, TokenType type) - { - while (true) - { - var token = MoveNext(queue); - if (token.Type == type) - yield break; - yield return token; - } - } - - private static string FirstGroupValue(Match match) => match.Groups[1].Value; - } -} \ No newline at end of file diff --git a/SharpNBT/SNBT/Token.cs b/SharpNBT/SNBT/Token.cs deleted file mode 100644 index c915f5d..0000000 --- a/SharpNBT/SNBT/Token.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JetBrains.Annotations; - -namespace SharpNBT.SNBT -{ - /// - /// An object emitted by the lexer to describe a logical fragment of code that can be parsed. - /// - [PublicAPI] - public sealed class Token - { - /// - /// Gets a value describing the general type code fragment this represents. - /// - public TokenType Type { get; } - - /// - /// Gets a value of this fragment, which can vary depending on context and the . - /// - public string Value { get; } - - /// - /// Creates a new instance of the class. - /// - /// A value describing the general type code fragment this represents. - /// Ahe value of this code fragment. - public Token(TokenType type, [NotNull] string value) - { - Type = type; - Value = value; - } - - /// - public override string ToString() => $"[{Type}] \"{Value}\""; - } -} \ No newline at end of file diff --git a/SharpNBT/SNBT/TokenType.cs b/SharpNBT/SNBT/TokenType.cs deleted file mode 100644 index 568c2db..0000000 --- a/SharpNBT/SNBT/TokenType.cs +++ /dev/null @@ -1,103 +0,0 @@ -using JetBrains.Annotations; - -namespace SharpNBT.SNBT -{ - /// - /// Describes types of tokens that the SNBT lexer can emit. - /// - [PublicAPI] - public enum TokenType - { - /// - /// Any whitespace/newline not found within a string or identifier. - /// - /// This type is not yielded during tokenization. - Whitespace, - - /// - /// A separator between objects and array elements. - /// - /// This type is not yielded during tokenization. - Separator, - - /// - /// The beginning of new object. - /// - Compound, - - /// - /// The end of a . - /// - EndCompound, - - /// - /// The name of an tag. - /// - Identifier, - - /// - /// A value, which may be contain escaped quotes. - /// - String, - - /// - /// The beginning of a . - /// - ByteArray, - - /// - /// The beginning of a . - /// - IntArray, - - /// - /// The beginning of a . - /// - LongArray, - - /// - /// The beginning of a . - /// - List, - - /// - /// The end of a , , or . - /// - EndArray, - - /// - /// A value or element of a depending on context. - /// - Byte, - - /// - /// A value. - /// - Bool, - - /// - /// A value. - /// - Short, - - /// - /// A value or element of a depending on context. - /// - Int, - - /// - /// A value or element of a depending on context. - /// - Long, - - /// - /// A value. - /// - Float, - - /// - /// A value. - /// - Double - } -} \ No newline at end of file diff --git a/SharpNBT/TagBuilder.cs b/SharpNBT/TagBuilder.cs deleted file mode 100644 index 67397bf..0000000 --- a/SharpNBT/TagBuilder.cs +++ /dev/null @@ -1,435 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Provides a mechanism for easily building a tree of NBT objects by handling the intermediate step of creating tags, allowing the direct adding of their - /// equivalent values. - /// - /// All methods return the instance itself, allowing for easily chaining calls to build a document. - /// - [PublicAPI] - public class TagBuilder - { - private readonly CompoundTag root; - private readonly Stack tree; - - /// - /// Gets the zero-based depth of the current node, indicating how deeply nested it is within other tags. - /// - /// The implicit top-level is not factored into this value. - public int Depth => tree.Count - 1; - - /// - /// Creates a new instance of the class, optionally with a to assign the top-level - /// of the final result. - /// - /// - public TagBuilder([CanBeNull] string name = null) - { - root = new CompoundTag(name); - tree = new Stack(); - 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. - /// - /// The name of the node to add. - /// The value of the tag. - /// Returns this instance for chaining. - public TagBuilder AddByte([CanBeNull] string name, byte value) => AddTag(new ByteTag(name, value)); - - /// - [CLSCompliant(false)] - public TagBuilder AddByte([CanBeNull] string name, sbyte value) => AddByte(name, unchecked((byte)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 AddByte(byte value) => AddByte(null, value); - - /// - [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. - /// - /// The name of the node to add. - /// The value of the tag. - /// Returns this instance for chaining. - public TagBuilder AddShort([CanBeNull]string name, short value) => AddTag(new ShortTag(name, value)); - - /// - [CLSCompliant(false)] - public TagBuilder AddShort([CanBeNull] string name, ushort value) => AddShort(name, unchecked((short)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 AddShort(short value) => AddShort(null, value); - - /// - [CLSCompliant(false)] - public TagBuilder AddShort(ushort value) => AddShort(null, unchecked((short)value)); - - /// - /// 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 AddInt([CanBeNull]string name, int value) => AddTag(new IntTag(name, value)); - - /// - [CLSCompliant(false)] - public TagBuilder AddInt([CanBeNull] string name, uint value) => AddInt(name, unchecked((int)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 AddInt(int value) => AddInt(null, value); - - /// - [CLSCompliant(false)] - public TagBuilder AddInt(uint value) => AddInt(null, unchecked((int)value)); - - /// - /// 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 AddLong([CanBeNull]string name, long value) => AddTag(new LongTag(name, value)); - - /// - [CLSCompliant(false)] - public TagBuilder AddLong([CanBeNull] string name, ulong value) => AddLong(name, unchecked((long)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 AddLong(long value) => AddLong(null, value); - - /// - [CLSCompliant(false)] - public TagBuilder AddLong(ulong value) => AddLong(null, unchecked((long)value)); - - /// - /// 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 AddFloat([CanBeNull]string name, float value) => AddTag(new FloatTag(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 AddFloat(float value) => AddFloat(null, value); - - /// - /// 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 AddDouble([CanBeNull]string name, double value) => AddTag(new DoubleTag(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 AddDouble(double value) => AddDouble(null, value); - - /// - /// 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. - public TagBuilder AddString([CanBeNull]string name, [CanBeNull] string value) => AddTag(new StringTag(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 AddString([CanBeNull] string value) => AddString(null, value); - - /// - /// Adds a new with the specified to the tree at the current depth. - /// - /// The name of the node to add. - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - public TagBuilder AddByteArray([CanBeNull] string name, params byte[] values) => AddTag(new ByteArrayTag(name, new ReadOnlySpan(values))); - - /// - public TagBuilder AddByteArray([CanBeNull] string name, [NotNull] IEnumerable values) => AddByteArray(name, values.ToArray()); - - /// - /// Adds a new unnamed with the specified to the tree at the current depth. - /// - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - public TagBuilder AddByteArray(params byte[] values) => AddByteArray(null, values); - - /// - public TagBuilder AddByteArray([NotNull] IEnumerable values) => AddByteArray(null, values.ToArray()); - - /// - /// Adds a new with the specified to the tree at the current depth. - /// - /// The name of the node to add. - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - [CLSCompliant(false)] - public TagBuilder AddByteArray([CanBeNull] string name, params sbyte[] values) - { - var span = new ReadOnlySpan(values); - return AddTag(new ByteArrayTag(name, MemoryMarshal.Cast(span))); - } - - /// - [CLSCompliant(false)] - public TagBuilder AddByteArray([CanBeNull] string name, [NotNull] IEnumerable values) => AddByteArray(name, values.ToArray()); - - /// - /// Adds a new unnamed with the specified to the tree at the current depth. - /// - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - [CLSCompliant(false)] - public TagBuilder AddByteArray(params sbyte[] values) => AddByteArray(null, values); - - /// - [CLSCompliant(false)] - public TagBuilder AddByteArray([NotNull] IEnumerable values) => AddByteArray(null, values.ToArray()); - - - /// - /// Adds a new with the specified to the tree at the current depth. - /// - /// The name of the node to add. - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - public TagBuilder AddIntArray([CanBeNull] string name, params int[] values) => AddTag(new IntArrayTag(name, values as IEnumerable)); - - /// - public TagBuilder AddIntArray([CanBeNull] string name, [NotNull] IEnumerable values) => AddIntArray(name, values.ToArray()); - - /// - /// Adds a new unnamed with the specified to the tree at the current depth. - /// - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - public TagBuilder AddIntArray(params int[] values) => AddIntArray(null, values); - - /// - public TagBuilder AddIntArray([NotNull] IEnumerable values) => AddIntArray(null, values.ToArray()); - - /// - /// Adds a new with the specified to the tree at the current depth. - /// - /// The name of the node to add. - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - public TagBuilder AddLongArray([CanBeNull] string name, params long[] values) => AddTag(new LongArrayTag(name, new ReadOnlySpan(values))); - - /// - public TagBuilder AddLongArray([CanBeNull] string name, IEnumerable values) => AddLongArray(name, values.ToArray()); - - /// - /// Adds a new unnamed with the specified to the tree at the current depth. - /// - /// The value(s) that will be included in the tag. - /// Returns this instance for chaining. - public TagBuilder AddLongArray(params long[] values) => AddLongArray(null, values); - - /// - public TagBuilder AddLongArray([NotNull] IEnumerable values) => AddLongArray(null, values.ToArray()); - - /// - /// Adds an existing object to the tree at the current depth. - /// - /// The instance to add. - /// Returns this instance for chaining. - /// Thrown if adding to a node, and the type does not match. - /// Thrown when is . - public TagBuilder AddTag([NotNull] Tag tag) - { - var top = tree.Peek(); - top.Add(tag ?? throw new ArgumentNullException(nameof(tag))); - return this; - } - - /// - /// Opens a new section, increasing the current depth level by one. - /// - /// The of the child items this list will contain. - /// The name to apply to the , or to omit a name. - /// Returns this instance for chaining. - /// - public TagBuilder BeginList(TagType childType, [CanBeNull] string name = null) - { - var list = new ListTag(name, childType); - AddTag(list); - tree.Push(list); - return this; - } - - /// - /// Closes the current section and decreases the by one. Does nothing if the the current node does not - /// represent a . - /// - /// Returns this instance for chaining. - /// - public TagBuilder EndList() - { - if (tree.TryPeek(out var result) && result is ListTag) - tree.Pop(); - - return this; - } - - /// - /// Opens a new section, increasing the current depth level by one. - /// - /// The name to apply to the , or to omit a name. - /// Returns this instance for chaining. - /// - public TagBuilder BeginCompound([CanBeNull] string name = null) - { - var compound = new CompoundTag(name); - AddTag(compound); - tree.Push(compound); - return this; - } - - /// - /// Closes the current section and decreases the by one. Does nothing if the the current node does not - /// represent a . - /// - /// Returns this instance for chaining. - /// - public TagBuilder EndCompound() - { - if (tree.Count > 1 && tree.TryPeek(out var result) && result is CompoundTag) - tree.Pop(); - - return this; - } - - /// - /// Closes the current or section and decreases the by one. - /// - /// Returns this instance for chaining. - /// This method does nothing if the current location is already at the top-level. - public TagBuilder End() - { - if ((tree.Peek() is ListTag) || (tree.Count > 1 && tree.Peek() is CompoundTag)) - tree.Pop(); - return this; - } - - /// - /// Closes any open compound/list sections, and returns the result as a . - /// - /// Invoking this method moves the current back to the top-level. - /// A representing the result of this tree. - public CompoundTag Create() - { - tree.Clear(); - tree.Push(root); - return root; - } - - /// - /// Creates a new and pushes it to the current scope level, returning a object that pulls the current - /// scope back out one level when disposed. - /// - /// The name to apply to the , or to omit a name. - /// A that will close the when disposed. - /// This is essentially no different than and but can use `using` blocks to distinguish scope. - public Context NewCompound([CanBeNull] string name) - { - BeginCompound(name); - return new Context(tree.Peek(), EndCompound); - } - - /// - /// Creates a new and pushes it to the current scope level, returning a object that pulls the current - /// scope back out one level when disposed. - /// - /// The of the child items this list will contain. - /// The name to apply to the , or to omit a name. - /// A that will close the when disposed. - /// This is essentially no different than and but can use `using` blocks to distinguish scope. - public Context NewList(TagType childType, [CanBeNull] string name) - { - BeginList(childType, name); - return new Context(tree.Peek(), EndList); - } - - /// - /// Represents the context of a single "level" of depth into a AST. - /// - /// Implements to that each node can used with using statements for easily distinguishable scope. - [PublicAPI] - public class Context: IDisposable - { - internal delegate TagBuilder CloseHandler(); - private readonly CloseHandler closeHandler; - - /// - /// Gets the top-level tag for this context. - /// - [NotNull] - public TagContainer Tag { get; } - - internal Context([NotNull] TagContainer tag, [NotNull] CloseHandler handler) - { - Tag = tag; - closeHandler = handler; - } - - /// Closes this context. - public void Dispose() - { - Console.WriteLine(Tag); - closeHandler.Invoke(); - } - } - } -} \ No newline at end of file diff --git a/SharpNBT/TagIO.cs b/SharpNBT/TagIO.cs deleted file mode 100644 index 537071a..0000000 --- a/SharpNBT/TagIO.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Abstract base class for the and classes, providing shared functionality. - /// - [PublicAPI] - public abstract class TagIO : IDisposable - { - /// - /// Gets the underlying stream this instance is operating on. - /// - [NotNull] - protected Stream BaseStream { get; } - - /// - /// Gets a flag indicating if byte swapping is required for numeric values, accounting for both the endianness of the host machine and the - /// specified . - /// - protected bool SwapEndian { get; } - - /// - /// Gets a flag indicating if variable-length integers should be used in applicable places. - /// - protected bool UseVarInt { get; } - - /// - /// Gets a flag indicating if variable-length integers will be "ZigZag encoded". - /// - /// - public bool ZigZagEncoding { get; } - - /// - /// Gets the format to be followed for compatibility. - /// - public FormatOptions FormatOptions { get; } - - /// - /// Initializes a new instance of the class. - /// - /// A instance that the writer will be writing to. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// Thrown when is - protected TagIO([NotNull] Stream stream, FormatOptions options) - { - BaseStream = stream ?? throw new ArgumentNullException(nameof(stream)); - - if (options.HasFlag(FormatOptions.BigEndian)) - SwapEndian = BitConverter.IsLittleEndian; - else if (options.HasFlag(FormatOptions.LittleEndian)) - SwapEndian = !BitConverter.IsLittleEndian; - - UseVarInt = options.HasFlag(FormatOptions.VarIntegers); - ZigZagEncoding = options.HasFlag(FormatOptions.ZigZagEncoding); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public abstract void Dispose(); - - /// - /// Asynchronously releases the unmanaged resources used by the instance. - /// - public abstract ValueTask DisposeAsync(); - - } -} \ No newline at end of file diff --git a/SharpNBT/TagReader.cs b/SharpNBT/TagReader.cs deleted file mode 100644 index 42366d2..0000000 --- a/SharpNBT/TagReader.cs +++ /dev/null @@ -1,511 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Provides methods for reading NBT data from a stream. - /// - [PublicAPI] - public class TagReader : TagIO - { - /// - /// Occurs when a tag has been fully deserialized from the stream. - /// - public event TagReaderCallback TagRead; - - /// - /// Occurs when a tag has been encountered in the stream, after reading the first byte to determine its . - /// - public event TagReaderCallback TagEncountered; - - private readonly bool leaveOpen; - - /// - /// Creates a new instance of the class from the given . - /// - /// A instance that the reader will be reading from. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// - /// to leave the object open after disposing the - /// object; otherwise, . - public TagReader([NotNull] Stream stream, FormatOptions options, bool leaveOpen = false) : base(stream, options) - { - if (!stream.CanRead) - throw new IOException(Strings.CannotReadStream); - this.leaveOpen = leaveOpen; - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public ByteTag ReadByte(bool named = true) - { - var name = named ? ReadUTF8String() : null; - return new ByteTag(name, (byte) BaseStream.ReadByte()); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public ShortTag ReadShort(bool named = true) - { - var name = named ? ReadUTF8String() : null; - short value; - - if (UseVarInt) - { - value = (short)VarInt.Read(BaseStream, ZigZagEncoding); - } - else - { - Span buffer = stackalloc byte[sizeof(short)]; - ReadToFixSizedBuffer(buffer); - value = BitConverter.ToInt16(buffer); - if (SwapEndian) - value = value.SwapEndian(); - } - - return new ShortTag(name, value); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public IntTag ReadInt(bool named = true) - { - var name = named ? ReadUTF8String() : null; - return new IntTag(name, UseVarInt ? VarInt.Read(BaseStream, ZigZagEncoding) : ReadInt32()); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public LongTag ReadLong(bool named = true) - { - var name = named ? ReadUTF8String() : null; - long value; - - if (UseVarInt) - { - value = VarLong.Read(BaseStream, ZigZagEncoding); - } - else - { - Span buffer = stackalloc byte[sizeof(long)]; - ReadToFixSizedBuffer(buffer); - value = BitConverter.ToInt64(buffer); - if (SwapEndian) - value = value.SwapEndian(); - } - - return new LongTag(name, value); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public FloatTag ReadFloat(bool named = true) - { - var name = named ? ReadUTF8String() : null; - - var buffer = new byte[sizeof(float)]; - ReadToFixSizedBuffer(buffer, 0, sizeof(float)); - if (SwapEndian) - Array.Reverse(buffer); - - return new FloatTag( name, BitConverter.ToSingle(buffer)); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public DoubleTag ReadDouble(bool named = true) - { - var name = named ? ReadUTF8String() : null; - var buffer = new byte[sizeof(double)]; - ReadToFixSizedBuffer(buffer, 0, buffer.Length); - if (SwapEndian) - Array.Reverse(buffer); - - return new DoubleTag( name, BitConverter.ToDouble(buffer, 0)); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public StringTag ReadString(bool named = true) - { - var name = named ? ReadUTF8String() : null; - var value = ReadUTF8String(); - return new StringTag(name, value); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public ByteArrayTag ReadByteArray(bool named = true) - { - var name = named ? ReadUTF8String() : null; - var count = ReadCount(); - var buffer = new byte[count]; - ReadToFixSizedBuffer(buffer, 0, count); - return new ByteArrayTag(name, buffer); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public IntArrayTag ReadIntArray(bool named = true) - { - const int INT_SIZE = sizeof(int); - - var name = named ? ReadUTF8String() : null; - var count = ReadCount(); - - if (UseVarInt) - { - var array = new int[count]; - for (var i = 0; i < count; i++) - array[i] = VarInt.Read(BaseStream, ZigZagEncoding); - return new IntArrayTag(name, array); - } - - var buffer = new byte[count * INT_SIZE]; - ReadToFixSizedBuffer(buffer, 0, count * INT_SIZE); - - Span values = MemoryMarshal.Cast(buffer); - if (SwapEndian) - { - for (var i = 0; i < count; i++) - values[i] = values[i].SwapEndian(); - } - return new IntArrayTag(name, values); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public LongArrayTag ReadLongArray(bool named = true) - { - const int LONG_SIZE = sizeof(long); - - var name = named ? ReadUTF8String() : null; - var count = ReadCount(); - - if (UseVarInt) - { - var array = new long[count]; - for (var i = 0; i < count; i++) - array[i] = VarLong.Read(BaseStream, ZigZagEncoding); - return new LongArrayTag(name, array); - } - - var buffer = new byte[count * LONG_SIZE]; - ReadToFixSizedBuffer(buffer, 0, count * LONG_SIZE); - - Span values = MemoryMarshal.Cast(buffer); - if (SwapEndian) - { - for (var i = 0; i < count; i++) - values[i] = values[i].SwapEndian(); - } - return new LongArrayTag(name, values); - } - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public ListTag ReadList(bool named = true) - { - var name = named ? ReadUTF8String() : null; - var childType = ReadType(); - var count = ReadCount(); - - if (childType == TagType.End && count > 0) - throw new FormatException(Strings.InvalidEndTagChild); - - var list = new ListTag(name, childType); - while (count-- > 0) - { - list.Add(ReadTag(childType, false)); - } - return list; - } - - - /// - /// Reads a from the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// It is assumed that the stream is positioned at the beginning of the tag payload. - /// The deserialized instance. - public CompoundTag ReadCompound(bool named = true) - { - var name = named ? ReadUTF8String() : null; - var compound = new CompoundTag(name); - - while (true) - { - var type = ReadType(); - if (type == TagType.End) - break; - - compound.Add(ReadTag(type, true)); - } - - return compound; - } - - /// - /// Reads a from the current position in the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// The tag instance that was read from the stream. - public Tag ReadTag(bool named = true) - { - var type = ReadType(); - return ReadTag(type, named); - } - - /// - /// Asynchronously reads a from the current position in the stream. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// The tag instance that was read from the stream. - public async Task ReadTagAsync(bool named = true) - { - return await Task.Run(() => ReadTag(named)); - } - - /// - /// Convenience method to read a tag and cast it automatically. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// The tag type that is being read from the stream. - /// The tag instance that was read from the stream. - /// This is typically only used when reading the top-level of a document where the type is already known. - public T ReadTag(bool named = true) where T : Tag - { - return (T)ReadTag(named); - } - - /// - /// Convenience method to asynchronously read a tag and cast it automatically. - /// - /// Flag indicating if this tag is named, only when a tag is a direct child of a . - /// The tag type that is being read from the stream. - /// The tag instance that was read from the stream. - /// This is typically only used when reading the top-level of a document where the type is already known. - public async Task ReadTagAsync(bool named = true) where T : Tag - { - var tag = await ReadTagAsync(named); - return (T)tag; - } - - [NotNull] - private Tag ReadTag(TagType type, bool named) - { - var result = OnTagEncountered(type, named); - if (result != null) - { - OnTagRead(result); - return result; - } - - Tag tag = type switch - { - TagType.End => new EndTag(), - TagType.Byte => ReadByte(named), - TagType.Short => ReadShort(named), - TagType.Int => ReadInt(named), - TagType.Long => ReadLong(named), - TagType.Float => ReadFloat(named), - TagType.Double => ReadDouble(named), - TagType.ByteArray => ReadByteArray(named), - TagType.String => ReadString(named), - TagType.List => ReadList(named), - TagType.Compound => ReadCompound(named), - TagType.IntArray => ReadIntArray(named), - TagType.LongArray => ReadLongArray(named), - _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) - }; - OnTagRead(tag); - return tag; - } - - - private TagType ReadType() - { - try - { - return (TagType)BaseStream.ReadByte(); - } - catch (EndOfStreamException) - { - return TagType.End; - } - } - - /// - /// Reads a length-prefixed UTF-8 string from the stream. - /// - /// The deserialized string instance. - [CanBeNull] - protected string ReadUTF8String() - { - int length; - if (UseVarInt) - length = VarInt.Read(BaseStream); - else - { - Span buffer = stackalloc byte[sizeof(ushort)]; - ReadToFixSizedBuffer(buffer); - var uint16 = BitConverter.ToUInt16(buffer); - length = SwapEndian ? uint16.SwapEndian() : uint16; - } - - if (length == 0) - return null; - - var utf8 = new byte[length]; - ReadToFixSizedBuffer(utf8, 0, length); - return Encoding.UTF8.GetString(utf8); - } - - private int ReadCount() => UseVarInt ? VarInt.Read(BaseStream, ZigZagEncoding) : ReadInt32(); - - /// - /// Reads a 64-bit signed (big-endian) integer from the stream, converting to native endian when necessary. - /// - /// The deserialized value. - private int ReadInt32() - { - Span buffer = stackalloc byte[sizeof(int)]; - ReadToFixSizedBuffer(buffer); - var value = BitConverter.ToInt32(buffer); - return SwapEndian ? value.SwapEndian() : value; - } - - /// - /// Reads bytes from the streams and stores them into the . - /// The number of read bytes is dictated by the size of the buffer. - /// This method ensures that all requested bytes are read. - /// - /// - /// Use this instead of BaseStream.Read(buffer). - /// There was a breaking change in .NET 6 where the can read less bytes than requested for certain streams. - /// Read more here: https://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/partial-byte-reads-in-streams - /// - /// The buffer where the read bytes are written to. the buffer size defines the number of bytes to read. - /// Throws if no more bytes could be read from the stream, but the buffer wasn't completely filled yet. - protected void ReadToFixSizedBuffer(Span buffer) - { - var totalBytes = 0; - while (totalBytes < buffer.Length) - { - var readBytes = BaseStream.Read(buffer.Slice(totalBytes)); - if (readBytes == 0) - throw new EndOfStreamException(); - totalBytes += readBytes; - } - } - - /// - /// Reads bytes from the streams and stores them into the . - /// This method ensures that all requested bytes are read. - /// - /// - /// Use this instead of BaseStream.Read(buffer, offset, count). - /// There was a breaking change in .NET 6 where the can read less bytes than requested for certain streams. - /// Read more here: https://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/partial-byte-reads-in-streams - /// - /// The buffer where the read bytes are written to. The data will be stored starting at to + - 1. - /// The offset in where the read data is stored. - /// The number of bytes to read. Must be positive. - /// Throws if no more bytes could be read from the stream, but the buffer wasn't completely filled yet. - protected void ReadToFixSizedBuffer(byte[] buffer, int offset, int count) - { - ReadToFixSizedBuffer(new Span(buffer, offset, count)); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public override void Dispose() - { - if (!leaveOpen) - BaseStream.Dispose(); - } - - /// - /// Asynchronously releases the unmanaged resources used by the . - /// - public override async ValueTask DisposeAsync() - { - if (!leaveOpen) - await BaseStream.DisposeAsync(); - } - - /// - /// Invokes the event when a tag has been fully deserialized from the . - /// - /// The deserialized instance. - protected virtual void OnTagRead(Tag tag) => TagRead?.Invoke(this, new TagEventArgs(tag.Type, tag)); - - /// - /// Invokes the event when the stream is positioned at the beginning of a an unread tag. - /// - /// The type of tag next to be read from the stream. - /// Flag indicating if this tag is named. - /// When handled by an event subscriber, returns a parsed instance, otherwise returns . - [CanBeNull] - protected virtual Tag OnTagEncountered(TagType type, bool named) - { - // Early out if no subscribers. - if (TagEncountered is null) - return null; - - var args = new TagHandledEventArgs(type, named, BaseStream); - TagEncountered.Invoke(this, args); - return args.Handled ? args.Result : null; - } - } -} \ No newline at end of file diff --git a/SharpNBT/TagWriter.cs b/SharpNBT/TagWriter.cs deleted file mode 100644 index b9cfaa0..0000000 --- a/SharpNBT/TagWriter.cs +++ /dev/null @@ -1,388 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Provides methods for writing NBT tags to a stream. - /// - [PublicAPI] - public class TagWriter : TagIO - { - private readonly bool leaveOpen; - - /// - /// Creates a new instance of the class from the given . - /// - /// A instance that the writer will be writing to. - /// Bitwise flags to configure how data should be handled for compatibility between different specifications. - /// - /// to leave the object open after disposing the - /// object; otherwise, . - public TagWriter([NotNull] Stream stream, FormatOptions options, bool leaveOpen = false) : base(stream, options) - { - if (!stream.CanWrite) - throw new IOException(Strings.CannotWriteStream); - this.leaveOpen = leaveOpen; - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteByte(ByteTag tag) - { - WriteTypeAndName(tag); - BaseStream.WriteByte(tag.Value); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteShort(ShortTag tag) - { - WriteTypeAndName(tag); - if (UseVarInt) - VarInt.Write(BaseStream, tag.Value, ZigZagEncoding); - else - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(short)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteInt(IntTag tag) - { - WriteTypeAndName(tag); - if (UseVarInt) - VarInt.Write(BaseStream, tag.Value, ZigZagEncoding); - else - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(int)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteLong(LongTag tag) - { - WriteTypeAndName(tag); - if (UseVarInt) - VarLong.Write(BaseStream, tag.Value, ZigZagEncoding); - else - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(long)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteFloat(FloatTag tag) - { - WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(float)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteDouble(DoubleTag tag) - { - WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(double)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteString(StringTag tag) - { - WriteTypeAndName(tag); - WriteUTF8String(tag.Value); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteByteArray(ByteArrayTag tag) - { - WriteTypeAndName(tag); - WriteCount(tag); - BaseStream.Write(tag.ToArray(), 0, tag.Count); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteIntArray(IntArrayTag tag) - { - WriteTypeAndName(tag); - WriteCount(tag); - - var values = new Span(tag.ToArray()); - if (UseVarInt) - { - // VarInt is effectively always little-endian - foreach (var n in values) - VarInt.Write(BaseStream, n, ZigZagEncoding); - return; - } - if (SwapEndian) - { - for (var i = 0; i < values.Length; i++) - values[i] = values[i].SwapEndian(); - } - BaseStream.Write(MemoryMarshal.AsBytes(values)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteLongArray(LongArrayTag tag) - { - - WriteTypeAndName(tag); - WriteCount(tag); - - var values = new Span(tag.ToArray()); - if (UseVarInt) - { - // VarLong is effectively always little-endian - foreach (var n in values) - VarLong.Write(BaseStream, n, ZigZagEncoding); - return; - } - if (SwapEndian) - { - for (var i = 0; i < values.Length; i++) - values[i] = values[i].SwapEndian(); - - } - BaseStream.Write(MemoryMarshal.AsBytes(values)); - } - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteList(ListTag tag) - { - WriteTypeAndName(tag); - BaseStream.WriteByte((byte) tag.ChildType); - WriteCount(tag); - - foreach (var child in tag) - WriteTag(child); - } - - - /// - /// Writes a to the stream. - /// - /// The instance to write. - public virtual void WriteCompound(CompoundTag tag) - { - WriteTypeAndName(tag); - foreach (var child in tag) - { - if (tag.Type == TagType.End) - break; - - child.Parent = tag; - WriteTag(child); - } - - BaseStream.WriteByte((byte) TagType.End); - } - - /// - /// Convenience method to build and write a instance to the underlying stream. - /// - /// A instance to write. - public virtual void WriteBuilder([NotNull] TagBuilder builder) => WriteCompound(builder.Create()); - - /// - /// - /// - /// - public virtual void WriteEndTag([CanBeNull] EndTag tag = null) => BaseStream.WriteByte(0); - - /// - /// Writes the given to the stream. - /// - /// The instance to be written. - /// Thrown when the tag type is unrecognized. - public void WriteTag(Tag tag) - { - switch (tag.Type) - { - case TagType.End: - WriteEndTag((EndTag) tag); - break; - case TagType.Byte: - WriteByte((ByteTag) tag); - break; - case TagType.Short: - WriteShort((ShortTag) tag); - break; - case TagType.Int: - WriteInt((IntTag) tag); - break; - case TagType.Long: - WriteLong((LongTag)tag); - break; - case TagType.Float: - WriteFloat((FloatTag)tag); - break; - case TagType.Double: - WriteDouble((DoubleTag)tag); - break; - case TagType.ByteArray: - WriteByteArray((ByteArrayTag)tag); - break; - case TagType.String: - WriteString((StringTag)tag); - break; - case TagType.List: - WriteList((ListTag)tag); - break; - case TagType.Compound: - WriteCompound((CompoundTag)tag); - break; - case TagType.IntArray: - WriteIntArray((IntArrayTag)tag); - break; - case TagType.LongArray: - WriteLongArray((LongArrayTag)tag); - break; - default: - throw new ArgumentOutOfRangeException(nameof(tag.Type), Strings.UnknownTagType); - } - } - - /// - /// Asynchronously writes the given to the stream. - /// - /// The instance to be written. - /// Thrown when the tag type is unrecognized. - public async Task WriteTagAsync(Tag tag) - { - await Task.Run(() => WriteTag(tag)); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public override void Dispose() - { - BaseStream.Flush(); - if (!leaveOpen) - BaseStream.Dispose(); - } - - /// - /// Asynchronously releases the unmanaged resources used by the . - /// - public override async ValueTask DisposeAsync() - { - await BaseStream.FlushAsync(); - if (!leaveOpen) - await BaseStream.DisposeAsync(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteTypeAndName(Tag tag) - { - if (tag.Parent is ListTag) - return; - - BaseStream.WriteByte((byte) tag.Type); - WriteUTF8String(tag.Name); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteUTF8String(string value) - { - // String length prefixes never use ZigZag encoding - - if (string.IsNullOrEmpty(value)) - { - if (UseVarInt) - VarInt.Write(BaseStream, 0); - else - BaseStream.Write(GetBytes((ushort) 0), 0, sizeof(ushort)); - } - else - { - var utf8 = Encoding.UTF8.GetBytes(value); - if (UseVarInt) - VarInt.Write(BaseStream, utf8.Length); - else - BaseStream.Write(GetBytes((ushort) utf8.Length), 0, sizeof(ushort)); - - BaseStream.Write(utf8, 0, utf8.Length); - } - } - - /// - /// Gets the bytes for this number, accounting for the host machine endianness and target format. - /// - /// The value to convert. - /// An array of bytes representing the value in compatible format. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte[] GetBytes(short n) => BitConverter.GetBytes(SwapEndian ? n.SwapEndian() : n); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte[] GetBytes(int n) => BitConverter.GetBytes(SwapEndian ? n.SwapEndian() : n); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte[] GetBytes(long n) => BitConverter.GetBytes(SwapEndian ? n.SwapEndian() : n); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte[] GetBytes(ushort n) => BitConverter.GetBytes(SwapEndian ? n.SwapEndian() : n); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte[] GetBytes(float n) - { - var bytes = BitConverter.GetBytes(n); - if (SwapEndian) - Array.Reverse(bytes); - return bytes; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte[] GetBytes(double n) - { - var bytes = BitConverter.GetBytes(n); - if (SwapEndian) - Array.Reverse(bytes); - return bytes; - } - - private void WriteCount(EnumerableTag tag) - { - if (UseVarInt) - VarInt.Write(BaseStream, tag.Count, ZigZagEncoding); - else - BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int)); - } - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/BoolTag.cs b/SharpNBT/Tags/BoolTag.cs deleted file mode 100644 index f5ea46d..0000000 --- a/SharpNBT/Tags/BoolTag.cs +++ /dev/null @@ -1,56 +0,0 @@ -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/ByteArrayTag.cs b/SharpNBT/Tags/ByteArrayTag.cs deleted file mode 100644 index 4638e7f..0000000 --- a/SharpNBT/Tags/ByteArrayTag.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that whose value is a contiguous sequence of 8-bit integers. - /// - /// - /// While this class uses the CLS compliant (0..255), the NBT specification uses a signed value with a range of -128..127, so ensure - /// the bits are equivalent for your values. - /// - [PublicAPI][Serializable] - public class ByteArrayTag : EnumerableTag - { - /// - /// Initializes a new instance of the . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public ByteArrayTag([CanBeNull] string name, byte[] values) : base(TagType.ByteArray, name, values) - { - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public ByteArrayTag([CanBeNull] string name, [NotNull] IEnumerable values) : base(TagType.ByteArray, name, values) - { - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public ByteArrayTag([CanBeNull] string name, ReadOnlySpan values) : base(TagType.ByteArray, name, values) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected ByteArrayTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() - { - var word = Count == 1 ? Strings.WordElement : Strings.WordElements; - return $"TAG_Byte_Array({PrettyName}): [{Count} {word}]"; - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() - { - var values = new string[Count]; - for (var i = 0; i < Count; i++) - values[i] = $"{this[i]}b"; - return $"{StringifyName}[B;{string.Join(',', values)}]"; - } - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/ByteTag.cs b/SharpNBT/Tags/ByteTag.cs deleted file mode 100644 index de1eb85..0000000 --- a/SharpNBT/Tags/ByteTag.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Runtime.Serialization; -using System.Text; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that contains a single 8-bit integer value. - /// - /// - /// While this class uses the CLS compliant (0..255), the NBT specification uses a signed value with a range of -128..127. It is - /// recommended to use the property if your language supports a signed 8-bit value, otherwise simply ensure the bits are - /// equivalent. - /// - [PublicAPI][Serializable] - public class ByteTag : Tag - { - /// - /// Gets or sets the value of this tag as an unsigned value. - /// - /// - /// This is only a reinterpretation of the bytes, no actual conversion is performed. - /// - [CLSCompliant(false)] - public sbyte SignedValue - { - get => unchecked((sbyte)Value); - set => Value = unchecked((byte)value); - } - - /// - /// 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 ByteTag([CanBeNull] string name, byte value) : base(TagType.Byte, name, value) - { - } - - /// - [CLSCompliant(false)] - public ByteTag([CanBeNull] string name, sbyte value) : base(TagType.Byte, name, unchecked((byte) value)) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected ByteTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_Byte({PrettyName}): {Value}"; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator byte(ByteTag tag) => tag.Value; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - [CLSCompliant(false)] - public static implicit operator sbyte(ByteTag tag) => unchecked((sbyte)tag.Value); - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}{Value}B"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/CompoundTag.cs b/SharpNBT/Tags/CompoundTag.cs deleted file mode 100644 index a0aeb4e..0000000 --- a/SharpNBT/Tags/CompoundTag.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Top-level tag that acts as a container for other named tags. - /// - /// - /// This along with the class define the structure of the NBT format. Children are not order-dependent, nor is order guaranteed. The - /// closing does not require to be explicitly added, it will be added automatically during serialization. - /// - [PublicAPI][Serializable] - public class CompoundTag : TagContainer - { - /// - /// Creates a new instance of the class. - /// - /// The name of the tag, or if tag has no name. - public CompoundTag([CanBeNull] string name) : base(TagType.Compound, name) - { - NamedChildren = true; - RequiredType = null; - } - - /// - /// Creates a new instance of the class. - /// - /// The name of the tag, or if tag has no name. - /// A collection objects that are children of this object. - public CompoundTag([CanBeNull] string name, [NotNull] IEnumerable values) : this(name) - { - AddRange(values); - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected CompoundTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// Returns a string that represents the current object. - /// A string that represents the current object. - /// - public override string ToString() - { - var word = Count == 1 ? Strings.WordEntry : Strings.WordEntries; - return $"TAG_Compound({PrettyName}): [{Count} {word}]"; - } - - /// - /// Retrieves a "pretty-printed" multiline string representing the complete tree structure of the tag. - /// - /// The prefix that will be applied to each indent-level of nested nodes in the tree structure. - /// The pretty-printed string. - [NotNull] - public string PrettyPrinted([CanBeNull] string indent = " ") - { - var buffer = new StringBuilder(); - PrettyPrinted(buffer, 0, indent ?? string.Empty); - return buffer.ToString(); - } - - /// - /// Searches the children of this tag, returning the first child with the specified . - /// - /// The name of the tag to search for. - /// to recursively search children, otherwise to only search direct descendants. - /// The first tag found with , otherwise if none was found. - [CanBeNull] - public Tag Find([NotNull] string name, bool deep) - { - foreach (var tag in this) - { - if (string.CompareOrdinal(name, tag.Name) == 0) - return tag; - - if (deep && tag is CompoundTag child) - { - var result = child.Find(name, true); - if (result != null) - return result; - } - } - - return null; - } - - /// - /// Retrieves a child tag with the specified , or if no match was found. - /// - /// The name of the tag to retrieve. - [CanBeNull] - public Tag this[[NotNull] string name] => Find(name, false); - - /// - protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent) - { - var space = new StringBuilder(); - for (var i = 0; i < level; i++) - space.Append(indent); - - buffer.AppendLine(space + ToString()); - buffer.AppendLine(space + "{"); - foreach (var tag in this) - tag.PrettyPrinted(buffer, level + 1, indent); - buffer.AppendLine(space + "}"); - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() - { - var strings = new string[Count]; - for (var i = 0; i < strings.Length; i++) - strings[i] = this[i].Stringify(); - - return $"{StringifyName}{{{string.Join(',', strings)}}}"; - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// Flag indicating if this is the top-level tag that should be wrapped in braces. - /// This NBT tag in SNBT format. - /// - public string Stringify(bool topLevel) - { - var str = Stringify(); - return topLevel ? $"{{{str}}}" : str; - } - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/DoubleTag.cs b/SharpNBT/Tags/DoubleTag.cs deleted file mode 100644 index f745c66..0000000 --- a/SharpNBT/Tags/DoubleTag.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that contains a single IEEE-754 double-precision floating point number. - /// - [PublicAPI][Serializable] - public class DoubleTag : Tag - { - /// - /// 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 DoubleTag([CanBeNull] string name, double value) : base(TagType.Double, name, value) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected DoubleTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_Double({PrettyName}): {Value:0.0}"; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator double(DoubleTag tag) => tag.Value; - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}{Value:0.0}D"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/EndTag.cs b/SharpNBT/Tags/EndTag.cs deleted file mode 100644 index cdd7a75..0000000 --- a/SharpNBT/Tags/EndTag.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Text; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Represents the end of . - /// - [PublicAPI] - public sealed class EndTag : Tag - { - /// - /// Creates a new instance of the class. - /// - public EndTag() : base(TagType.End, null) - { - } - - /// - public override string ToString() => $"TAG_End"; - - /// - protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent) - { - // Do nothing - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => string.Empty; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/EnumerableTag.cs b/SharpNBT/Tags/EnumerableTag.cs deleted file mode 100644 index 3ac1640..0000000 --- a/SharpNBT/Tags/EnumerableTag.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.Serialization; -using System.Text; -using JetBrains.Annotations; -using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; - -namespace SharpNBT -{ - /// - /// Base class for tags that contain a collection of values and can be enumerated. - /// - /// The type of the item the tag contains. - [PublicAPI][Serializable] - public abstract class EnumerableTag : Tag, IList - { - /// - /// Internal list implementation. - /// - private readonly List internalList = new List(); - - /// - /// Initializes a new instance of the . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - protected EnumerableTag(TagType type, [CanBeNull] string name) : base(type, name) - { - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - protected EnumerableTag(TagType type, [CanBeNull] string name, [NotNull] T[] values) : base(type, name) - { - internalList.AddRange(values); - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - protected EnumerableTag(TagType type, [CanBeNull] string name, [NotNull] IEnumerable values) : base(type, name) - { - internalList.AddRange(values); - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - protected EnumerableTag(TagType type, [CanBeNull] string name, ReadOnlySpan values) : base(type, name) - { - internalList.AddRange(values.ToArray()); - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected EnumerableTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - var dummy = info.GetInt32("count"); - internalList.AddRange((T[]) info.GetValue("values", typeof(T[]))); - } - - /// Populates a with the data needed to serialize the target object. - /// The to populate with data. - /// The destination (see ) for this serialization. - /// The caller does not have the required permission. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("count", Count); - info.AddValue("values", internalList.ToArray(), typeof(T[])); - } - - /// Returns an enumerator that iterates through the collection. - /// An enumerator that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() => internalList.GetEnumerator(); - - /// Returns an enumerator that iterates through a collection. - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)internalList).GetEnumerator(); - - /// Adds an item to the . - /// The object to add to the . - /// The is read-only. - /// - [SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")] - public virtual void Add([NotNull] T item) => internalList.Add(item); - - /// - /// Adds the elements of the specified collection to the . - /// - /// A collection containing the items to add. - public void AddRange([NotNull] [ItemNotNull] IEnumerable items) - { - foreach (var item in items) - Add(item); - } - - /// Inserts an item to the at the specified index. - /// The zero-based index at which should be inserted. - /// The object to insert into the . - /// - /// is not a valid index in the . - /// The is read-only. - /// - [SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")] - public virtual void Insert(int index, [NotNull] T item) => internalList.Insert(index, item); - - /// Gets or sets the element at the specified index. - /// The zero-based index of the element to get or set. - /// - /// is not a valid index in the . - /// The property is set and the is read-only. - /// The element at the specified index. - /// - [NotNull] - public virtual T this[int index] - { - get => internalList[index]; - set => internalList[index] = value; - } - - /// Removes all items from the . - /// The is read-only. - /// - public virtual void Clear() => internalList.Clear(); - - /// Determines whether the contains a specific value. - /// The object to locate in the . - /// - /// if is found in the ; otherwise, . - /// - public bool Contains(T item) => internalList.Contains(item); - - /// Copies the elements of the to an , starting at a particular index. - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - /// - /// is . - /// - /// is less than 0. - /// The number of elements in the source is greater than the available space from to the end of the destination . - /// - public void CopyTo(T[] array, int arrayIndex) => internalList.CopyTo(array, arrayIndex); - - /// Removes the first occurrence of a specific object from the . - /// The object to remove from the . - /// The is read-only. - /// - /// if was successfully removed from the ; otherwise, . This method also returns if is not found in the original . - /// - public virtual bool Remove(T item) => internalList.Remove(item); - - /// Gets the number of elements contained in the . - /// The number of elements contained in the . - /// - public int Count => internalList.Count; - - /// Gets a value indicating whether the is read-only. - /// - /// if the is read-only; otherwise, . - /// - public bool IsReadOnly => false; - - /// Determines the index of a specific item in the . - /// The object to locate in the . - /// The index of if found in the list; otherwise, -1. - /// - public int IndexOf(T item) => internalList.IndexOf(item); - - /// Removes the item at the specified index. - /// The zero-based index of the item to remove. - /// - /// is not a valid index in the . - /// The is read-only. - /// - public virtual void RemoveAt(int index) => internalList.RemoveAt(index); - - /// - protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent) - { - for (var i = 0; i < level; i++) - buffer.Append(indent); - buffer.AppendLine(ToString()); - } - } - -} \ No newline at end of file diff --git a/SharpNBT/Tags/FloatTag.cs b/SharpNBT/Tags/FloatTag.cs deleted file mode 100644 index a7025ea..0000000 --- a/SharpNBT/Tags/FloatTag.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that contains a single IEEE-754 single-precision floating point number. - /// - [PublicAPI][Serializable] - public class FloatTag : Tag - { - /// - /// 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 FloatTag([CanBeNull] string name, float value) : base(TagType.Float, name, value) - { - } - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected FloatTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_Float({PrettyName}): {Value:0.0}"; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator float(FloatTag tag) => tag.Value; - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}{Value:0.0}F"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/IntArrayTag.cs b/SharpNBT/Tags/IntArrayTag.cs deleted file mode 100644 index 1709d33..0000000 --- a/SharpNBT/Tags/IntArrayTag.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that whose value is a contiguous sequence of 32-bit integers. - /// - [PublicAPI][Serializable] - public class IntArrayTag : EnumerableTag - { - /// - /// Initializes a new instance of the . - /// - /// The name of the tag, or if tag has no name. - public IntArrayTag([CanBeNull] string name) : base(TagType.IntArray, name) - { - } - /// - /// Initializes a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public IntArrayTag([CanBeNull] string name, [NotNull] int[] values) : base(TagType.IntArray, name, values) - { - } - - - /// - /// Initializes a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public IntArrayTag([CanBeNull] string name, [NotNull] IEnumerable values) : base(TagType.IntArray, name, values) - { - } - - /// - /// Initializes a new instance of the . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public IntArrayTag([CanBeNull] string name, ReadOnlySpan values) : base(TagType.IntArray, name, values) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected IntArrayTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() - { - var word = Count == 1 ? Strings.WordElement : Strings.WordElements; - return $"TAG_Int_Array({PrettyName}): [{Count} {word}]"; - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}[I;{string.Join(',', this)}]"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/IntTag.cs b/SharpNBT/Tags/IntTag.cs deleted file mode 100644 index 0538c97..0000000 --- a/SharpNBT/Tags/IntTag.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that contains a single 32-bit integer value. - /// - [PublicAPI][Serializable] - public class IntTag : Tag - { - /// - /// Gets or sets the value of this tag as an unsigned value. - /// - /// - /// This is only a reinterpretation of the bytes, no actual conversion is performed. - /// - [CLSCompliant(false)] - public uint UnsignedValue - { - get => unchecked((uint)Value); - set => Value = unchecked((int)value); - } - - /// - /// 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 IntTag([CanBeNull] string name, int value) : base(TagType.Int, name, value) - { - } - - /// - [CLSCompliant(false)] - public IntTag([CanBeNull] Tag parent, [CanBeNull] string name, uint value) : base(TagType.Int, name, unchecked((int) value)) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected IntTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_Int({PrettyName}): {Value}"; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator int(IntTag tag) => tag.Value; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - [CLSCompliant(false)] - public static implicit operator uint(IntTag tag) => unchecked((uint)tag.Value); - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}{Value}"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/ListTag.cs b/SharpNBT/Tags/ListTag.cs deleted file mode 100644 index 5a51db6..0000000 --- a/SharpNBT/Tags/ListTag.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using System.Text; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Represents a collection of a tags. - /// - /// - /// All child tags must be have the same value, and their value will be omitted during serialization. - /// - [PublicAPI][Serializable] - public class ListTag : TagContainer - { - /// - /// Gets the NBT type of this tag's children. - /// - public TagType ChildType { get; private set; } - - /// - /// Creates a new instance of the class. - /// - /// The name of the tag, or if tag has no name. - /// A constant describing the NBT type for children in this tag. - public ListTag([CanBeNull] string name, TagType childType) : base(TagType.List, name) - { - RequiredType = childType; - NamedChildren = false; - ChildType = childType; - } - - /// - /// Creates a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A constant describing the NBT type for children in this tag. - /// A collection of values to include in this tag. - public ListTag([CanBeNull] string name, TagType childType, [NotNull][ItemNotNull] IEnumerable children) : this(name, childType) - { - AddRange(children); - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected ListTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() - { - var word = Count == 1 ? Strings.WordEntry : Strings.WordEntries; - return $"TAG_List({PrettyName}): [{Count} {word}]"; - } - - /// - protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent) - { - var space = new StringBuilder(); - for (var i = 0; i < level; i++) - space.Append(indent); - - buffer.AppendLine(space + ToString()); - buffer.AppendLine(space + "{"); - foreach (var tag in this) - tag.PrettyPrinted(buffer, level + 1, indent); - buffer.AppendLine(space + "}"); - } - - /// - /// Retrieves a "pretty-printed" multiline string representing the complete tree structure of the tag. - /// - /// The prefix that will be applied to each indent-level of nested nodes in the tree structure. - /// The pretty-printed string. - [NotNull] - public string PrettyPrinted([NotNull] string indent = " ") - { - var buffer = new StringBuilder(); - PrettyPrinted(buffer, 0, indent); - return buffer.ToString(); - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() - { - var strings = new string[Count]; - for (var i = 0; i < strings.Length; i++) - strings[i] = this[i].Stringify(); - - return $"{StringifyName}[{string.Join(',', strings)}]"; - } - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/LongArrayTag.cs b/SharpNBT/Tags/LongArrayTag.cs deleted file mode 100644 index a6d0f09..0000000 --- a/SharpNBT/Tags/LongArrayTag.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that whose value is a contiguous sequence of 64-bit integers. - /// - [PublicAPI][Serializable] - public class LongArrayTag : EnumerableTag - { - /// - /// Initializes a new instance of the . - /// - /// The name of the tag, or if tag has no name. - public LongArrayTag([CanBeNull] string name) : base(TagType.LongArray, name) - { - } - /// - /// Initializes a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public LongArrayTag([CanBeNull] string name, [NotNull] long[] values) : base(TagType.LongArray, name, values) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected LongArrayTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public LongArrayTag([CanBeNull] string name, [NotNull] IEnumerable values) : base(TagType.LongArray, name, values) - { - } - - /// - /// Initializes a new instance of the . - /// - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - public LongArrayTag([CanBeNull] string name, ReadOnlySpan values) : base(TagType.LongArray, name, values) - { - } - - /// - public override string ToString() - { - var word = Count == 1 ? Strings.WordElement : Strings.WordElements; - return $"TAG_Long_Array({PrettyName}): [{Count} {word}]"; - } - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() - { - var values = new string[Count]; - for (var i = 0; i < Count; i++) - values[i] = $"{this[i]}l"; - return $"{StringifyName}[L;{string.Join(',', values)}]"; - } - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/LongTag.cs b/SharpNBT/Tags/LongTag.cs deleted file mode 100644 index 0e34115..0000000 --- a/SharpNBT/Tags/LongTag.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that contains a single 64-bit integer value. - /// - [PublicAPI][Serializable] - public class LongTag : Tag - { - /// - /// Gets or sets the value of this tag as an unsigned value. - /// - /// - /// This is only a reinterpretation of the bytes, no actual conversion is performed. - /// - [CLSCompliant(false)] - public ulong UnsignedValue - { - get => unchecked((ulong)Value); - set => Value = unchecked((long)value); - } - - /// - /// 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 LongTag([CanBeNull] string name, long value) : base(TagType.Long, name, value) - { - } - - /// - [CLSCompliant(false)] - public LongTag([CanBeNull] string name, ulong value) : base(TagType.Long, name, unchecked((long) value)) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected LongTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_Long({PrettyName}): {Value}"; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator long(LongTag tag) => tag.Value; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - [CLSCompliant(false)] - public static implicit operator ulong(LongTag tag) => unchecked((ulong)tag.Value); - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}{Value}L"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/ShortTag.cs b/SharpNBT/Tags/ShortTag.cs deleted file mode 100644 index 2e404e7..0000000 --- a/SharpNBT/Tags/ShortTag.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag that contains a single 16-bit integer value. - /// - [PublicAPI][Serializable] - public class ShortTag : Tag - { - /// - /// Gets or sets the value of this tag as an unsigned value. - /// - /// - /// This is only a reinterpretation of the bytes, no actual conversion is performed. - /// - [CLSCompliant(false)] - public ushort UnsignedValue - { - get => unchecked((ushort)Value); - set => Value = unchecked((short)value); - } - - /// - /// 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 ShortTag([CanBeNull] string name, short value) : base(TagType.Short, name, value) - { - } - - /// - [CLSCompliant(false)] - public ShortTag([CanBeNull] string name, ushort value) : base(TagType.Short, name, unchecked((short) value)) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected ShortTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_Short({PrettyName}): {Value}"; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator short(ShortTag tag) => tag.Value; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - [CLSCompliant(false)] - public static implicit operator ushort(ShortTag tag) => unchecked((ushort)tag.Value); - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}{Value}S"; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/StringTag.cs b/SharpNBT/Tags/StringTag.cs deleted file mode 100644 index 4c53992..0000000 --- a/SharpNBT/Tags/StringTag.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Runtime.Serialization; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// A tag the contains a UTF-8 string. - /// - [PublicAPI][Serializable] - public class StringTag : Tag - { - /// - /// 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 StringTag([CanBeNull] string name, [CanBeNull] string value) : base(TagType.String, name, value) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected StringTag(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - /// - public override string ToString() => $"TAG_String({PrettyName}): \"{Value}\""; - - /// - /// Implicit conversion of this tag to a . - /// - /// The tag to convert. - /// The tag represented as a . - public static implicit operator string(StringTag tag) => tag.Value; - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public override string Stringify() => $"{StringifyName}\"{Value}\""; - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/Tag.cs b/SharpNBT/Tags/Tag.cs deleted file mode 100644 index cb838a8..0000000 --- a/SharpNBT/Tags/Tag.cs +++ /dev/null @@ -1,350 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Json; -using System.Text; -using System.Text.RegularExpressions; -using JetBrains.Annotations; - -[assembly: CLSCompliant(true)] -[assembly: InternalsVisibleTo("SharpNBT.Tests")] - -namespace SharpNBT -{ - /// - /// Abstract base class that all NBT tags inherit from. - /// - [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[] - { - typeof(TagType), - typeof(Tag<>), - typeof(Tag[]), - typeof(EnumerableTag<>), - typeof(TagContainer), - typeof(ByteTag), - typeof(ShortTag), - typeof(IntTag), - typeof(LongTag), - typeof(FloatTag), - typeof(DoubleTag), - typeof(StringTag), - typeof(ByteArrayTag), - typeof(IntArrayTag), - typeof(LongArrayTag), - typeof(ListTag), - typeof(CompoundTag) - }; - } - - /// - /// Text applied in a pretty-print sting when a tag has no defined value. - /// - protected const string NO_NAME = "None"; - - /// - /// Gets a constant describing the NBT type this object represents. - /// - public TagType Type { get; private set; } - - /// - /// Gets the parent this object is a child of. - /// - [CanBeNull] - public Tag Parent { get; internal set; } - - /// - /// Gets the name assigned to this . - /// - [CanBeNull] - public string Name { get; set; } - - /// - /// Initialized a new instance of the class. - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - protected Tag(TagType type, [CanBeNull] string name) - { - Type = type; - Name = name; - } - - /// - /// Writes this tag as a formatted string to the given . - /// - /// A instance to write to. - /// The current indent depth to write at. - /// The string to use for indents. - protected internal abstract void PrettyPrinted([NotNull] StringBuilder buffer, int level, [NotNull] string indent); - - /// - /// Gets the name of the object as a human-readable quoted string, or a default name to indicate it has no name when applicable. - /// - protected internal string PrettyName => Name is null ? "None" : $"\"{Name}\""; - - /// - /// Gets a representation of this as a JSON string. - /// - /// Flag indicating if formatting should be applied to make the string human-readable. - /// When is , indicates the indent characters(s) to use. - /// A JSON string describing this object. - public string ToJsonString(bool pretty = false, string indent = " ") - { - var settings = new DataContractJsonSerializerSettings - { - UseSimpleDictionaryFormat = true, - EmitTypeInformation = EmitTypeInformation.Never, - KnownTypes = GetKnownTypes() - }; - var serializer = new DataContractJsonSerializer(typeof(Tag), settings); - using var stream = new MemoryStream(); - if (pretty) - { - using var writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, false, true, indent); - serializer.WriteObject(writer, this); - writer.Flush(); - } - else - { - serializer.WriteObject(stream, this); - } - stream.Flush(); - return Encoding.UTF8.GetString(stream.ToArray()); - } - - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// - /// if the current object is equal to the parameter; otherwise, . - /// - public bool Equals(Tag other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Type == other.Type && Name == other.Name; - } - - /// Determines whether the specified object is equal to the current object. - /// The object to compare with the current object. - /// - /// if the specified object is equal to the current object; otherwise, . - /// - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((Tag)obj); - } - - /// Serves as the default hash function. - /// A hash code for the current object. - /// - public override int GetHashCode() - { - unchecked - { - // ReSharper disable NonReadonlyMemberInGetHashCode - return ((int)Type * 373) ^ (Name != null ? Name.GetHashCode() : 0); - // ReSharper restore NonReadonlyMemberInGetHashCode - } - } - - /// Creates a new object that is a copy of the current instance. - /// A new object that is a copy of this instance. - public object Clone() - { - // Serialize then deserialize to make a deep-copy - using var stream = new MemoryStream(); - - // Might as well not worry about swapping bits, just use native endian - var opts = BitConverter.IsLittleEndian ? FormatOptions.LittleEndian : FormatOptions.BigEndian; - using var writer = new TagWriter(stream, opts, true); - using var reader = new TagReader(stream, opts, true); - - writer.WriteTag(this); - stream.Seek(0, SeekOrigin.Begin); - - return reader.ReadTag(!(Parent is ListTag)); - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected Tag(SerializationInfo info, StreamingContext context) - { - Type = (TagType) info.GetByte("type"); - Name = info.GetString("name"); - } - - /// Populates a with the data needed to serialize the target object. - /// The to populate with data. - /// The destination (see ) for this serialization. - /// The caller does not have the required permission. - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("type", (byte) Type); - info.AddValue("name", Name); - } - - /// - /// Tests for equality of this object with another instance. - /// - /// First value to compare. - /// Second value to compare. - /// Result of comparison. - public static bool operator ==(Tag left, Tag right) => Equals(left, right); - - /// - /// Tests for inequality of this object with another instance. - /// - /// First value to compare. - /// Second value to compare. - /// Result of comparison. - public static bool operator !=(Tag left, Tag right) => !Equals(left, right); - - /// - /// Gets the string representation of this NBT tag (SNBT). - /// - /// This NBT tag in SNBT format. - /// - public abstract string Stringify(); - - /// - /// Gets the name in a formatted properly for SNBT. - /// - [NotNull] - protected internal string StringifyName - { - get - { - if (string.IsNullOrEmpty(Name)) - return string.Empty; - return simpleNameMatcher.IsMatch(Name) ? $"{Name}: " : $"\"{Name}\": "; - } - } - } - - /// - /// Abstract base class for types that contain a single primitive value. - /// - /// The type of the value the tag represents. - [PublicAPI][Serializable] - public abstract class Tag : Tag, IEquatable> - { - /// - /// Gets or sets the value of the tag. - /// - public T Value { get; set; } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected Tag(SerializationInfo info, StreamingContext context) : base(info, context) - { - Value = (T)info.GetValue("value", typeof(T)); - } - - /// Populates a with the data needed to serialize the target object. - /// The to populate with data. - /// The destination (see ) for this serialization. - /// The caller does not have the required permission. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("value", Value, typeof(T)); - } - - /// - /// Creates a new instance of the class with the specified . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - /// The value to assign to this tag. - protected Tag(TagType type, [CanBeNull] string name, T value) : base(type, name) - { - Value = value; - } - - /// - protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent) - { - for (var i = 0; i < level; i++) - buffer.Append(indent); - buffer.AppendLine(ToString()); - } - - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// - /// if the current object is equal to the parameter; otherwise, . - /// - public bool Equals(Tag other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return base.Equals(other) && EqualityComparer.Default.Equals(Value, other.Value); - } - - /// Determines whether the specified object is equal to the current object. - /// The object to compare with the current object. - /// - /// if the specified object is equal to the current object; otherwise, . - /// - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((Tag)obj); - } - - /// Serves as the default hash function. - /// A hash code for the current object. - /// - public override int GetHashCode() - { - unchecked - { - // ReSharper disable NonReadonlyMemberInGetHashCode - return (base.GetHashCode() * 421) ^ EqualityComparer.Default.GetHashCode(Value); - // ReSharper restore NonReadonlyMemberInGetHashCode - } - } - - /// - /// Tests for equality of this object with another instance. - /// - /// First value to compare. - /// Second value to compare. - /// Result of comparison. - public static bool operator ==(Tag left, Tag right) => Equals(left, right); - - /// - /// Tests for inequality of this object with another instance. - /// - /// First value to compare. - /// Second value to compare. - /// Result of comparison. - public static bool operator !=(Tag left, Tag right) => !Equals(left, right); - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/TagContainer.cs b/SharpNBT/Tags/TagContainer.cs deleted file mode 100644 index 8b2bfd0..0000000 --- a/SharpNBT/Tags/TagContainer.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Runtime.Serialization; -using JetBrains.Annotations; -using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute; - -namespace SharpNBT -{ - /// - /// Base class for tags that contain a collection of other objects and can be enumerated. - /// - [PublicAPI][Serializable] - public abstract class TagContainer : EnumerableTag - { - /// - /// A value indicating if children of this container are required to have be named. - /// - protected bool NamedChildren; - - /// - /// When not , indicates that a child must be of a specific type to be added. - /// - protected TagType? RequiredType; - - /// - /// Initializes a new instance of the . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - protected TagContainer(TagType type, [CanBeNull] string name) : base(type, name) - { - } - - /// - /// Initializes a new instance of the with the specified . - /// - /// A constant describing the NBT type for this tag. - /// The name of the tag, or if tag has no name. - /// A collection of values to include in this tag. - protected TagContainer(TagType type, [CanBeNull] string name, [NotNull][ItemNotNull] IEnumerable values) : base(type, name, values) - { - } - - /// - /// Required constructor for ISerializable implementation. - /// - /// The to describing this instance. - /// The destination (see ) for this serialization. - protected TagContainer(SerializationInfo info, StreamingContext context) : base(info, context) - { - RequiredType = (TagType?) info.GetValue("child_type", typeof(TagType?)); - NamedChildren = !RequiredType.HasValue; - } - - /// Populates a with the data needed to serialize the target object. - /// The to populate with data. - /// The destination (see ) for this serialization. - /// The caller does not have the required permission. - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - if (RequiredType.HasValue) - info.AddValue("child_type", RequiredType.Value); - } - - /// Adds an item to the . - /// The object to add to the . - /// The is read-only. - /// - [SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")] - public sealed override void Add(Tag item) - { - base.Add(AssertConventions(item)); - item.Parent = this; - } - - /// Inserts an item to the at the specified index. - /// The zero-based index at which should be inserted. - /// The object to insert into the . - /// - /// is not a valid index in the . - /// The is read-only. - /// - [SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")] - public sealed override void Insert(int index, Tag item) - { - base.Insert(index, AssertConventions(item)); - item.Parent = this; - } - - /// Gets or sets the element at the specified index. - /// The zero-based index of the element to get or set. - /// - /// is not a valid index in the . - /// The property is set and the is read-only. - /// The element at the specified index. - /// - public sealed override Tag this[int index] - { - get => base[index]; - set - { - base[index] = AssertConventions(value); - value.Parent = this; - } - } - - /// Removes all items from the . - /// The is read-only. - /// - public sealed override void Clear() - { - foreach (var item in this) - item.Parent = null; - base.Clear(); - } - - /// Removes the first occurrence of a specific object from the . - /// The object to remove from the . - /// The is read-only. - /// - /// if was successfully removed from the ; otherwise, . This method also returns if is not found in the original . - /// - public sealed override bool Remove(Tag item) - { - if (item is null || !base.Remove(item)) - return false; - - item.Parent = null; - return true; - } - - /// Removes the item at the specified index. - /// The zero-based index of the item to remove. - /// - /// is not a valid index in the . - /// The is read-only. - /// - public sealed override void RemoveAt(int index) - { - this[index].Parent = null; - base.RemoveAt(index); - } - - /// - /// Performs routine checks to ensure that the given complies with the NBT standard for this collection type. - /// - /// A instance to validate. - /// Returns the instance. - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected Tag AssertConventions([CanBeNull] Tag tag) - { - if (tag is null) - throw new ArgumentNullException(nameof(tag), Strings.ChildCannotBeNull); - - switch (NamedChildren) - { - case true when tag.Name is null: - throw new FormatException(Strings.ChildrenMustBeNamed); - case false when tag.Name != null: - throw new FormatException(Strings.ChildrenMustNotBeNamed); - } - - if (RequiredType.HasValue && RequiredType.Value != tag.Type) - throw new ArrayTypeMismatchException(Strings.ChildWrongType); - - return tag; - } - } -} \ No newline at end of file diff --git a/SharpNBT/Tags/TagType.cs b/SharpNBT/Tags/TagType.cs deleted file mode 100644 index 607e69e..0000000 --- a/SharpNBT/Tags/TagType.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Strongly-typed numerical constants that are prefixed to tags to denote their type. - /// - [PublicAPI][Serializable] - public enum TagType : byte - { - /// - /// Signifies the end of a . - /// - End = 0x00, - - /// - /// A single signed byte, - /// - Byte = 0x01, - - /// - /// A single signed 16-bit integer. - /// - Short = 0x02, - - /// - /// A single signed 32-bit integer. - /// - Int = 0x03, - - /// - /// A single signed 64-bit integer. - /// - Long = 0x04, - - /// - /// A single IEEE-754 single-precision floating point number. - /// - Float = 0x05, - - /// - /// A single IEEE-754 double-precision floating point number. - /// - Double = 0x06, - - /// - /// A length-prefixed array of bytes. - /// - ByteArray = 0x07, - - /// - /// A length-prefixed UTF-8 string. - /// - String = 0x08, - - /// - /// A list of nameless tags, all of the same type. - /// - List = 0x09, - - /// - /// A set of named tags. - /// - Compound = 0x0a, - - /// - /// A length-prefixed array of signed 32-bit integers. - /// - IntArray = 0x0b, - - /// - /// A length-prefixed array of signed 64-bit integers. - /// - LongArray = 0x0c - } -} \ No newline at end of file diff --git a/SharpNBT/VarInt.cs b/SharpNBT/VarInt.cs deleted file mode 100644 index 42eebd2..0000000 --- a/SharpNBT/VarInt.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.IO; -using JetBrains.Annotations; - -namespace SharpNBT -{ - /// - /// Provides static methods for reading and writing variable-length integers that are up to 5 bytes from both streams and buffers. - /// - [PublicAPI] - public static class VarInt - { - /// - /// Encodes the given to a variable-length integer up to 5 bytes long, and writes it to the . - /// - /// A instance to write the value to. - /// The value to encode and write. - /// Flag indicating if the value will be ZigZag encoded. - /// The number of bytes written to the . - public static int Write([NotNull] Stream stream, int value, bool zigzag = false) - { - var buffer = Encode(value, zigzag); - stream.Write(buffer, 0, buffer.Length); - return buffer.Length; - } - - /// - /// Reads up to 5 bytes from the given and returns the VarInt value as a 32-bit integer. - /// - /// A instance to read from. - /// Flag indicating if the value is ZigZag encoded. - /// The parsed value read from the . - public static int Read([NotNull] Stream stream, bool zigzag = false) - { - var value = VarIntUtil.Decode(stream, 32, out var dummy); - return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value); - } - - /// - /// Reads up to 5 bytes from the given and returns the VarInt value as a 32-bit integer. - /// - /// A instance to read from. - /// A variable to store the number of bytes read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The parsed value read from the . - public static int Read([NotNull] Stream stream, out int size, bool zigzag = false) - { - var value = VarIntUtil.Decode(stream, 32, out size); - return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value); - } - - /// - /// Encodes the given and returns an array of bytes that represent it. - /// - /// The value to encode. - /// Flag indicating if the value will be ZigZag encoded. - /// An array of bytes representing the as a variable length integer. - public static byte[] Encode(int value, bool zigzag = false) - { - if (zigzag) - return VarIntUtil.Encode(unchecked((ulong)VarIntUtil.EncodeZigZag(value, 32))); - return VarIntUtil.Encode(unchecked((uint)value)); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long. - /// - /// A buffer containing the data to be decoded. - /// The offset into the to begin reading. - /// The maximum number of bytes that should be read from the . - /// A variable to store the actual number of bytes read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static long Decode([NotNull] byte[] buffer, int offset, int count, out int size, bool zigzag = false) - { - return Decode(new ReadOnlySpan(buffer, offset, count), out size, zigzag); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long. - /// - /// A buffer containing the data to be decoded. - /// The offset into the to begin reading. - /// The maximum number of bytes that should be read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static long Decode([NotNull] byte[] buffer, int offset, int count, bool zigzag = false) - { - return Decode(new ReadOnlySpan(buffer, offset, count), out var dummy, zigzag); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long. - /// - /// A buffer containing the data to be decoded. - /// A variable to store the actual number of bytes read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static int Decode(ReadOnlySpan buffer, out int size, bool zigzag = false) - { - var value = VarIntUtil.Decode(buffer, 32, out size); - return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 5 bytes long. - /// - /// A buffer containing the data to be decoded. - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static int Decode(ReadOnlySpan buffer, bool zigzag = false) - { - var value = VarIntUtil.Decode(buffer, 32, out var dummy); - return zigzag ? (int) VarIntUtil.DecodeZigZag(value) : unchecked((int)value); - } - } -} \ No newline at end of file diff --git a/SharpNBT/VarIntUtil.cs b/SharpNBT/VarIntUtil.cs deleted file mode 100644 index d33e171..0000000 --- a/SharpNBT/VarIntUtil.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.IO; -using System.Runtime.CompilerServices; - -namespace SharpNBT -{ - internal static class VarIntUtil - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long EncodeZigZag(long value, int bitLength) - { - return (value << 1) ^ (value >> (bitLength - 1)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long DecodeZigZag(ulong value) - { - if ((value & 0x1) == 0x1) - { - return (-1 * ((long)(value >> 1) + 1)); - } - return (long)(value >> 1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Encode(uint value) - { - Span buffer = stackalloc byte[5]; - var pos = 0; - do - { - var byteVal = value & 0x7f; - value >>= 7; - if (value != 0) - byteVal |= 0x80; - buffer[pos++] = (byte) byteVal; - - } while (value != 0); - - return buffer[..pos].ToArray(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Encode(ulong value) - { - Span buffer = stackalloc byte[10]; - var pos = 0; - do - { - var byteVal = value & 0x7f; - value >>= 7; - if (value != 0) - byteVal |= 0x80; - buffer[pos++] = (byte) byteVal; - - } while (value != 0); - - return buffer[..pos].ToArray(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong Decode(ReadOnlySpan buffer, int bits, out int size) - { - var shift = 0; - ulong result = 0; - size = 0; - - foreach (ulong byteValue in buffer) - { - ulong tmp = byteValue & 0x7f; - result |= tmp << shift; - if (shift > bits) - throw new OverflowException(string.Format(Strings.VarIntTooMuchData, bits)); - size++; - if ((byteValue & 0x80) != 0x80) - return result; - - shift += 7; - } - throw new FormatException(Strings.VarIntCannotDecode); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong Decode(Stream stream, int bits, out int size) - { - var shift = 0; - ulong result = 0; - size = 0; - - while (true) - { - var byteValue = (ulong) stream.ReadByte(); - size++; - - ulong tmp = byteValue & 0x7f; - result |= tmp << shift; - if (shift > bits) - throw new OverflowException(string.Format(Strings.VarIntTooMuchData, bits)); - if ((byteValue & 0x80) != 0x80) - return result; - - shift += 7; - } - } - } -} \ No newline at end of file diff --git a/SharpNBT/VarLong.cs b/SharpNBT/VarLong.cs deleted file mode 100644 index bfd5866..0000000 --- a/SharpNBT/VarLong.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.IO; -using JetBrains.Annotations; - -namespace SharpNBT -{ - - /// - /// Provides static methods for reading and writing variable-length integers that are up to 10 bytes from both streams and buffers. - /// - [PublicAPI] - public static class VarLong - { - /// - /// Encodes the given to a variable-length integer up to 10 bytes long, and writes it to the . - /// - /// A instance to write the value to. - /// The value to encode and write. - /// Flag indicating if the value will be ZigZag encoded. - /// The number of bytes written to the . - public static int Write([NotNull] Stream stream, long value, bool zigzag = false) - { - var buffer = Encode(value, zigzag); - stream.Write(buffer, 0, buffer.Length); - return buffer.Length; - } - - /// - /// Reads up to 10 bytes from the given and returns the VarLong value as a 64-bit integer. - /// - /// A instance to read from. - /// Flag indicating if the value is ZigZag encoded. - /// The parsed value read from the . - public static long Read([NotNull] Stream stream, bool zigzag = false) - { - var value = VarIntUtil.Decode(stream, 64, out var dummy); - return zigzag ? VarIntUtil.DecodeZigZag(value) : unchecked((long) value); - } - - /// - /// Reads up to 10 bytes from the given and returns the VarLong value as a 64-bit integer. - /// - /// A instance to read from. - /// A variable to store the number of bytes read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The parsed value read from the . - public static long Read([NotNull] Stream stream, out int size, bool zigzag = false) - { - var value = VarIntUtil.Decode(stream, 64, out size); - return zigzag ? VarIntUtil.DecodeZigZag(value) : unchecked((long) value); - } - - /// - /// Encodes the given and returns an array of bytes that represent it. - /// - /// The value to encode. - /// Flag indicating if the value will be ZigZag encoded. - /// An array of bytes representing the as a variable length integer. - public static byte[] Encode(long value, bool zigzag = false) - { - if (zigzag) - return VarIntUtil.Encode(unchecked((ulong)VarIntUtil.EncodeZigZag(value, 64))); - return VarIntUtil.Encode(unchecked((ulong)value)); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 10 bytes long. - /// - /// A buffer containing the data to be decoded. - /// The offset into the to begin reading. - /// The maximum number of bytes that should be read from the . - /// A variable to store the actual number of bytes read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static long Decode([NotNull] byte[] buffer, int offset, int count, out int size, bool zigzag = false) - { - return Decode(new ReadOnlySpan(buffer, offset, count), out size, zigzag); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 10 bytes long. - /// - /// A buffer containing the data to be decoded. - /// The offset into the to begin reading. - /// The maximum number of bytes that should be read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static long Decode([NotNull] byte[] buffer, int offset, int count, bool zigzag = false) - { - return Decode(new ReadOnlySpan(buffer, offset, count), out var dummy, zigzag); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 10 bytes long. - /// - /// A buffer containing the data to be decoded. - /// A variable to store the actual number of bytes read from the . - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static long Decode(ReadOnlySpan buffer, out int size, bool zigzag = false) - { - var value = VarIntUtil.Decode(buffer, 64, out size); - return zigzag ? VarIntUtil.DecodeZigZag(value) : unchecked((long)value); - } - - /// - /// Decodes a buffer of bytes that represent a variable-length integer up to 10 bytes long. - /// - /// A buffer containing the data to be decoded. - /// Flag indicating if the value is ZigZag encoded. - /// The decoded value. - public static long Decode(ReadOnlySpan buffer, bool zigzag = false) - { - var value = VarIntUtil.Decode(buffer, 64, out var dummy); - return zigzag ? VarIntUtil.DecodeZigZag(value) : unchecked((long)value); - } - } - -} \ No newline at end of file diff --git a/SharpNBT/ZLib/Adler32.cs b/SharpNBT/ZLib/Adler32.cs deleted file mode 100644 index f119ade..0000000 --- a/SharpNBT/ZLib/Adler32.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using JetBrains.Annotations; - -namespace SharpNBT.ZLib -{ - /// - /// An Adler-32 checksum implementation for ZLib streams. - /// - /// - [PublicAPI] - public sealed class Adler32 - { - private uint a = 1; - private uint b; - private const int BASE = 65521; - private const int MAX = 5550; - private int pending; - - /// - /// Update the checksum value with the specified . - /// - /// A single value to calculate into the checksum. - public void Update(byte data) - { - if (pending >= MAX) - UpdateModulus(); - a += data; - b += a; - pending++; - } - - /// - /// Update the checksum value with the specified . - /// - /// A buffer containing the values to calculate into the checksum. - public void Update(byte[] data) => Update(new ReadOnlySpan(data, 0, data.Length)); - - /// - /// Update the checksum value with the specified . - /// - /// A buffer containing the values to calculate into the checksum. - public void Update(ReadOnlySpan data) - { - unchecked - { - var nextCompute = MAX - pending; - for (var i = 0; i < data.Length; i++) - { - if (i == nextCompute) - { - UpdateModulus(); - nextCompute = i + MAX; - } - a += data[i]; - b += a; - pending++; - } - } - } - - /// - /// Update the checksum value with the specified . - /// - /// A buffer containing the values to calculate into the checksum. - /// An offset into the to begin adding from. - /// The number of bytes in to calculate. - public void Update(byte[] data, int offset, int length) => Update(new ReadOnlySpan(data, offset, length)); - - /// - /// Reset the checksum back to the initial state. - /// - public void Reset() - { - a = 1; - b = 0; - pending = 0; - } - - /// - /// Gets the current calculated checksum value as a signed 32-bit integer. - /// - public int Value - { - get - { - if (pending > 0) - UpdateModulus(); - return unchecked((int)((b << 16) | a)); - } - } - - /// - /// Gets the current calculated checksum value as the original unsigned 32-bit integer value. - /// - [CLSCompliant(false)] - public uint UnsignedValue - { - get - { - if (pending > 0) - UpdateModulus(); - return (b << 16) | a; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UpdateModulus() - { - a %= BASE; - b %= BASE; - pending = 0; - } - } -} \ No newline at end of file diff --git a/SharpNBT/ZLib/ZLibHeader.cs b/SharpNBT/ZLib/ZLibHeader.cs deleted file mode 100644 index 288fa6b..0000000 --- a/SharpNBT/ZLib/ZLibHeader.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.IO.Compression; -using JetBrains.Annotations; - -namespace SharpNBT.ZLib -{ - /// - /// Provides methods for the creation of a ZLib header as outlined by RFC-1950. - /// - /// - public sealed class ZLibHeader - { - private byte compressionMethod; - private byte compressionInfo; - private byte fCheck; - private byte fLevel; - private byte fDict; - - /// - /// Gets a flag indicating if this represents a valid and supported ZLib format. - /// - public bool IsSupported { get; private set; } - - /// - /// Creates a new instance of the class using the specified compression strategy. - /// - /// The desired level of compression. - public ZLibHeader(CompressionLevel compressionLevel = CompressionLevel.Fastest) - { - const byte FASTER = 0; - const byte DEFAULT = 2; - const byte OPTIMAL = 3; - - compressionMethod = 8; // Deflate algorithm - compressionInfo = 7; // Window size - fDict = 0; // false - - fLevel = compressionLevel switch - { - CompressionLevel.NoCompression => FASTER, - CompressionLevel.Fastest => DEFAULT, - CompressionLevel.Optimal => OPTIMAL, - _ => throw new ArgumentOutOfRangeException(nameof(compressionLevel)) - }; - } - - private void RefreshFCheck() - { - var flg = (byte) (Convert.ToByte(fLevel) << 1); - flg |= Convert.ToByte(fDict); - - fCheck = Convert.ToByte(31 - Convert.ToByte((CMF * 256 + flg) % 31)); - if (fCheck > 31) - throw new ArgumentOutOfRangeException(nameof(fCheck), Strings.ZLibValueGreater31); - } - - /// - /// Gets the computed "compression method and flags" (CMF) value of the header. - /// - // ReSharper disable once InconsistentNaming - private byte CMF => (byte)((compressionInfo << 4) | compressionMethod); - - /// - /// Gets the computed "flags" (FLG) value of the header. - /// - // ReSharper disable once InconsistentNaming - private byte FLG => (byte)((fLevel << 6) | (fDict << 5) | fCheck); - - /// - /// Computes and returns the CMF and FLG magic numbers associated with a ZLib header. - /// - /// A two element byte array containing the CMF and FLG values. - [NotNull] - public byte[] Encode() - { - var result = new byte[2]; - RefreshFCheck(); - - result[0] = CMF; - result[1] = FLG; - - return result; - } - - /// - /// Calculates and returns a new instance from the specified CMF and FLG magic bytes read from a ZLib header. - /// - /// The first byte of a ZLib header. - /// The second byte of a ZLib header. - /// The decoded instance. - [NotNull] - public static ZLibHeader Decode(int cmf, int flg) - { - var result = new ZLibHeader(); - cmf = cmf & 0x0FF; - flg = flg & 0x0FF; - - result.compressionInfo = Convert.ToByte((cmf & 0xF0) >> 4); - if (result.compressionInfo > 15) - throw new ArgumentOutOfRangeException(nameof(result.compressionInfo), Strings.ZLibValueGreater15); - - result.compressionMethod = Convert.ToByte(cmf & 0x0F); - if (result.compressionInfo > 15) - throw new ArgumentOutOfRangeException(nameof(result.compressionMethod), Strings.ZLibValueGreater15); - - result.fCheck = Convert.ToByte(flg & 0x1F); - result.fDict = Convert.ToByte((flg & 0x20) >> 5); - result.fLevel = Convert.ToByte((flg & 0xC0) >> 6); - - result.IsSupported = (result.compressionMethod == 8) && (result.compressionInfo == 7) && (((cmf * 256 + flg) % 31 == 0)) && (result.fDict == 0); - - return result; - } - } -} diff --git a/SharpNBT/ZLib/ZLibStream.cs b/SharpNBT/ZLib/ZLibStream.cs deleted file mode 100644 index 692e5c3..0000000 --- a/SharpNBT/ZLib/ZLibStream.cs +++ /dev/null @@ -1,410 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Threading; -using System.Threading.Tasks; -using JetBrains.Annotations; - -namespace SharpNBT.ZLib -{ - /// - /// ZLib stream implementation for reading/writing. - /// - /// Generally speaking, the ZLib format is merely a DEFLATE stream, prefixed with a header, and performs a cyclic redundancy check to ensure data integrity - /// by storing an Adler-32 checksum after the compressed payload. - /// - [PublicAPI] - public class ZLibStream : Stream - { - /// - /// The internal DEFLATE stream used for compression/decompression. - /// - protected readonly DeflateStream DeflateStream; - - /// - /// The base stream the ZlibStream is wrapping. - /// - protected readonly Stream BaseStream; - - private readonly CompressionMode compressionMode; - private readonly bool leaveOpen; - private readonly Adler32 adler32 = new Adler32(); - private bool isClosed; - private byte[] checksum; - - /// - /// Initializes a new instance of the class using the specified compression and . - /// - /// A instance to be compressed. - /// The level of compression to use. - public ZLibStream([NotNull] Stream stream, CompressionLevel level) : this(stream, level, false) - { - } - - /// - /// Initializes a new instance of the class using the specified compression and . - /// - /// A instance to be compressed or uncompressed. - /// The type of compression to use. - public ZLibStream([NotNull] Stream stream, CompressionMode mode) : this(stream, mode, false) - { - } - - /// - /// Initializes a new instance of the class using the specified compression and , - /// and optionally leaves the stream open. - /// - /// A instance to be compressed. - /// The level of compression to use. - /// Indicates if the should be left open after this is closed. - public ZLibStream([NotNull] Stream stream, CompressionLevel level, bool leaveOpen) - { - compressionMode = CompressionMode.Compress; - this.leaveOpen = leaveOpen; - BaseStream = stream; - DeflateStream = CreateStream(level); - } - - /// - /// Initializes a new instance of the class using the specified compression and , - /// and optionally leaves the stream open. - /// - /// A instance to be compressed or uncompressed. - /// The type of compression to use. - /// Indicates if the should be left open after this is closed. - public ZLibStream([NotNull] Stream stream, CompressionMode mode, bool leaveOpen) - { - compressionMode = mode; - this.leaveOpen = leaveOpen; - BaseStream = stream; - DeflateStream = CreateStream(CompressionLevel.Fastest); - } - - /// Gets a value indicating whether the current stream supports reading. - /// - /// if the stream supports reading; otherwise, . - public override bool CanRead => compressionMode == CompressionMode.Decompress && !isClosed; - - /// Gets a value indicating whether the current stream supports writing. - /// - /// if the stream supports writing; otherwise, . - public override bool CanWrite => compressionMode == CompressionMode.Compress && !isClosed; - - /// Gets a value indicating whether the current stream supports seeking. - /// - /// if the stream supports seeking; otherwise, . - public override bool CanSeek => false; - - /// Gets the length in bytes of the stream. - /// A long value representing the length of the stream in bytes. - /// This property is not supported and will always throw an exception. - /// Methods were called after the stream was closed. - public override long Length => throw new NotSupportedException("Stream does not support this function."); - - /// Gets or sets the position within the current stream. - /// The current position within the stream. - /// An I/O error occurs. - /// This property is not supported and will always throw an exception. - /// Methods were called after the stream was closed. - public override long Position - { - get => throw new NotSupportedException("Stream does not support getting/setting position."); - set => throw new NotSupportedException("Stream does not support getting/setting position."); - } - - /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. - /// The unsigned byte cast to an , or -1 if at the end of the stream. - /// The stream does not support reading. - /// Methods were called after the stream was closed. - public override int ReadByte() - { - var n = DeflateStream.ReadByte(); - if (n == -1) // EOF - ReadCrc(); - else - adler32.Update(Convert.ToByte(n)); - - return n; - } - - /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// A region of memory. When this method returns, the contents of this region are replaced by the bytes read from the current source. - /// The total number of bytes read into the buffer. This can be less than the number of bytes allocated in the buffer if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. - public override int Read(Span buffer) - { - var read = DeflateStream.Read(buffer); - if (read < 1 && buffer.Length > 0) - ReadCrc(); - else - adler32.Update(buffer[..read]); - - return read; - } - - /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. - /// The sum of and is larger than the buffer length. - /// - /// is . - /// - /// or is negative. - /// An I/O error occurs. - /// The stream does not support reading. - /// Methods were called after the stream was closed. - public override int Read(byte[] buffer, int offset, int count) => Read(new Span(buffer, offset, count)); - - /// Asynchronously reads a sequence of bytes from the current stream, advances the position within the stream by the number of bytes read, and monitors cancellation requests. - /// The region of memory to write the data into. - /// The token to monitor for cancellation requests. The default value is . - /// A task that represents the asynchronous read operation. The value of its property contains the total number of bytes read into the buffer. The result value can be less than the number of bytes allocated in the buffer if that many bytes are not currently available, or it can be 0 (zero) if the end of the stream has been reached. - public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - var read = await DeflateStream.ReadAsync(buffer, cancellationToken); - adler32.Update(buffer.Slice(0, read).Span); - return read; - } - - /// Asynchronously reads a sequence of bytes from the current stream, advances the position within the stream by the number of bytes read, and monitors cancellation requests. - /// The buffer to write the data into. - /// The byte offset in at which to begin writing data from the stream. - /// The maximum number of bytes to read. - /// The token to monitor for cancellation requests. The default value is . - /// A task that represents the asynchronous read operation. The value of the task parameter contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached. - /// - /// is . - /// - /// or is negative. - /// The sum of and is larger than the buffer length. - /// The stream does not support reading. - /// The stream has been disposed. - /// The stream is currently in use by a previous read operation. - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - var read = await DeflateStream.ReadAsync(buffer, offset, count, cancellationToken); - adler32.Update(new ReadOnlySpan(buffer, offset, read)); - return read; - } - - /// Writes a byte to the current position in the stream and advances the position within the stream by one byte. - /// The byte to write to the stream. - /// An I/O error occurs. - /// The stream does not support writing, or the stream is already closed. - /// Methods were called after the stream was closed. - public override void WriteByte(byte value) - { - DeflateStream.WriteByte(value); - adler32.Update(value); - } - - /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// An array of bytes. This method copies bytes from to the current stream. - /// The zero-based byte offset in at which to begin copying bytes to the current stream. - /// The number of bytes to be written to the current stream. - /// The sum of and is greater than the buffer length. - /// - /// is . - /// - /// or is negative. - /// An I/O error occurred, such as the specified file cannot be found. - /// The stream does not support writing. - /// - /// was called after the stream was closed. - public override void Write(byte[] buffer, int offset, int count) - { - DeflateStream.Write(buffer, offset, count); - adler32.Update(buffer, offset, count); - } - - /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// A region of memory. This method copies the contents of this region to the current stream. - public override void Write(ReadOnlySpan buffer) - { - DeflateStream.Write(buffer); - adler32.Update(buffer); - } - - /// Asynchronously writes a sequence of bytes to the current stream, advances the current position within this stream by the number of bytes written, and monitors cancellation requests. - /// The buffer to write data from. - /// The zero-based byte offset in from which to begin copying bytes to the stream. - /// The maximum number of bytes to write. - /// The token to monitor for cancellation requests. The default value is . - /// A task that represents the asynchronous write operation. - /// - /// is . - /// - /// or is negative. - /// The sum of and is larger than the buffer length. - /// The stream does not support writing. - /// The stream has been disposed. - /// The stream is currently in use by a previous write operation. - public override async Task WriteAsync([NotNull] byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await DeflateStream.WriteAsync(buffer, offset, count, cancellationToken); - adler32.Update(new ReadOnlySpan(buffer, offset, count)); - } - - /// Asynchronously writes a sequence of bytes to the current stream, advances the current position within this stream by the number of bytes written, and monitors cancellation requests. - /// The region of memory to write data from. - /// The token to monitor for cancellation requests. The default value is . - /// A task that represents the asynchronous write operation. - public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - await DeflateStream.WriteAsync(buffer, cancellationToken); - adler32.Update(buffer.Span); - } - - /// - /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. - /// Instead of calling this method, ensure that the stream is properly disposed. - /// - public override void Close() - { - if (isClosed) - return; - - isClosed = true; - if (compressionMode == CompressionMode.Compress) - { - Flush(); - DeflateStream.Close(); - - checksum = BitConverter.GetBytes(adler32.Value); - if (BitConverter.IsLittleEndian) - Array.Reverse(checksum); - BaseStream.Write(checksum, 0, checksum.Length); - } - else - { - DeflateStream.Close(); - if (checksum == null) - ReadCrc(); - } - - if (!leaveOpen) - BaseStream.Close(); - } - - /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device. - /// An I/O error occurs. - public override void Flush() - { - DeflateStream?.Flush(); - BaseStream?.Flush(); - } - - /// Sets the position within the current stream. - /// A byte offset relative to the parameter. - /// A value of type indicating the reference point used to obtain the new position. - /// The new position within the current stream. - /// An I/O error occurs. - /// The stream does not support seeking, such as if the stream is constructed from a pipe or console output. - /// Methods were called after the stream was closed. - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - - /// Sets the length of the current stream. - /// The desired length of the current stream in bytes. - /// An I/O error occurs. - /// The stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output. - /// Methods were called after the stream was closed. - public override void SetLength(long value) => throw new NotSupportedException(); - - /// - /// Checks if the given is in ZLib format. - /// - /// A instance to query. - /// is is in a supported ZLib format, otherwise if not or an error occured. - public static bool IsSupported(Stream stream) - { - int cmf; - int flag; - - if (!stream.CanRead) - return false; - - if (stream.Position != 0) - { - var pos = stream.Position; - stream.Seek(0, SeekOrigin.Begin); - cmf = stream.ReadByte(); - flag = stream.ReadByte(); - stream.Seek(pos, SeekOrigin.Begin); - } - else - { - cmf = stream.ReadByte(); - flag = stream.ReadByte(); - } - - try - { - var header = ZLibHeader.Decode(cmf, flag); - return header.IsSupported; - } - catch - { - return false; - } - } - - /// - /// Reads the last 4 bytes of the stream where the CRC is stored. - /// - /// Thrown when the stream is cannot seek to the checksum location to read. - /// Thrown when the checksum comparison does not match. - private void ReadCrc() - { - checksum = new byte[4]; - BaseStream.Seek(-4, SeekOrigin.End); - if (BaseStream.Read(checksum, 0, 4) < 4) - throw new EndOfStreamException(); - - if (BitConverter.IsLittleEndian) - Array.Reverse(checksum); - - var crcAdler = adler32.Value; - var crcStream = BitConverter.ToInt32(checksum, 0); - - if (crcStream != crcAdler) - throw new InvalidDataException(Strings.CRCFail); - } - - /// - /// Initializes the underlying instance. - /// - private DeflateStream CreateStream(CompressionLevel compressionLevel) - { - switch (compressionMode) - { - case CompressionMode.Compress: - { - WriteHeader(compressionLevel); - return new DeflateStream(BaseStream, compressionLevel, true); - } - case CompressionMode.Decompress: - { - if (!IsSupported(BaseStream)) - throw new InvalidDataException(Strings.ZlibUnsupported); - - return new DeflateStream(BaseStream, CompressionMode.Decompress, true); - } - default: - throw new ArgumentOutOfRangeException(nameof(compressionMode)); - } - } - - /// - /// Writes the ZLib header to the stream. - /// - /// The compression level being used. - protected void WriteHeader(CompressionLevel compressionLevel) - { - var header = new ZLibHeader(compressionLevel); - var magicNumber = header.Encode(); - BaseStream.WriteByte(magicNumber[0]); - BaseStream.WriteByte(magicNumber[1]); - } - } -}