Implemented BufferedTagWriter class
This commit is contained in:
parent
2e15b58792
commit
7e30b7f898
11
README.md
11
README.md
|
@ -6,8 +6,8 @@ A CLS-compliant implementation of the Named Binary Tag (NBT) specifications (Jav
|
|||
|
||||
## Features
|
||||
|
||||
* **Java/Bedrock Support:** Supports all NBT protocols used by different versions of Minecraft, including: Java, Bedrock (file protocol), and Bedrock (network protocol), including full support for either GZip or ZLib compression.
|
||||
* **Ease-of-use:** An intuitive API design, following the style and conventions of the .NET runtime, with full Intellisense for every public member: Spend more time being productive and less time digging through documentation.
|
||||
* **Java/Bedrock Support:** Supports all NBT protocols used by different versions of Minecraft, including: Java, Bedrock (file protocol), and Bedrock (network protocol), including full support for either GZip/ZLib compression, big/little endian, and variable length integers with optional ZigZag encoding.
|
||||
* **Ease-of-use:** An intuitive API design, following the style and conventions of the .NET runtime, with full Intellisense for every member: Spend more time being productive and less time digging through documentation.
|
||||
* **Performance:** Leverages the power of modern C# language features, including `Span` with `stackalloc`, `MemoryMarshal`, etc. This allows for a type-safe way to reinterpret raw buffers without pointers or making unnecessary copies of buffers, a common pitfall with serialization in type-safe languages.
|
||||
* **Concurrency:** Includes standard async/await concurrency patterns for reading and writing.
|
||||
* **Cross-platform and cross-language support:** Fully CLR compliant and build against .NET Standard 2.1, allowing support for any CLR language (i.e. C#, Visual Basic, F#, etc.) for the following runtime versions or greater:
|
||||
|
@ -114,7 +114,10 @@ Pull requests are always welcome.
|
|||
|
||||
The project is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
||||
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Everyone interacting in the SharpNBT project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ForeverZer0/SharpNBT/blob/master/CODE_OF_CONDUCT.md).
|
||||
Everyone interacting in the SharpNBT project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ForeverZer0/SharpNBT/blob/master/CODE_OF_CONDUCT.md).
|
||||
|
||||
## Special Thanks
|
||||
|
||||
This project would not be possible without all the contributors to the https://wiki.vg/ and its maintainers, who have created an invaluable source of information for developers for everything related to the game of Minecraft.
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using SharpNBT.ZLib;
|
||||
|
||||
namespace SharpNBT
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a <see cref="TagWriter"/> object that writes to an internal buffer instead of a <see cref="Stream"/> 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.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class BufferedTagWriter : TagWriter
|
||||
{
|
||||
private readonly MemoryStream buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="BufferedTagWriter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="compression">Indicates the compression algorithm used to compress the file.</param>
|
||||
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
||||
/// <returns>A newly created <see cref="BufferedTagWriter"/> instance.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when an invalid compression type is specified.</exception>
|
||||
public static BufferedTagWriter Create(CompressionType compression, FormatOptions options)
|
||||
{
|
||||
// ReSharper disable once IntroduceOptionalParameters.Global
|
||||
return Create(compression, options, 4096);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="BufferedTagWriter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="compression">Indicates the compression algorithm used to compress the file.</param>
|
||||
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
||||
/// <param name="capacity">The initial capacity of the buffer.</param>
|
||||
/// <returns>A newly created <see cref="BufferedTagWriter"/> instance.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when an invalid compression type is specified.</exception>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes in the internal buffer.
|
||||
/// </summary>
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
BaseStream.Flush();
|
||||
return buffer.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the capacity of the internal buffer.
|
||||
/// </summary>
|
||||
/// <remarks>The capacity will expand automatically as-needed.</remarks>
|
||||
public long Capacity => buffer.Capacity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal buffer as an array of bytes containing the NBT data written so far.
|
||||
/// </summary>
|
||||
/// <returns>An array of bytes containing the NBT data.</returns>
|
||||
[Pure]
|
||||
public byte[] ToArray()
|
||||
{
|
||||
BaseStream.Flush();
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the internal buffer to the specified <paramref name="stream"/>;
|
||||
/// </summary>
|
||||
/// <param name="stream">A <see cref="Stream"/> instance to write to.</param>
|
||||
public void CopyTo([NotNull] Stream stream)
|
||||
{
|
||||
BaseStream.Flush();
|
||||
buffer.CopyTo(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously copies the internal buffer to the specified <paramref name="stream"/>;
|
||||
/// </summary>
|
||||
/// <param name="stream">A <see cref="Stream"/> instance to write to.</param>
|
||||
public async Task CopyToAsync([NotNull] Stream stream)
|
||||
{
|
||||
await BaseStream.FlushAsync();
|
||||
await buffer.CopyToAsync(stream);
|
||||
}
|
||||
|
||||
public static implicit operator ReadOnlySpan<byte>(BufferedTagWriter writer)
|
||||
{
|
||||
writer.BaseStream.Flush();
|
||||
return writer.buffer.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ using JetBrains.Annotations;
|
|||
|
||||
namespace SharpNBT
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods for reading NBT data from a stream.
|
||||
/// </summary>
|
||||
|
|
|
@ -215,6 +215,12 @@ namespace SharpNBT
|
|||
BaseStream.WriteByte((byte) TagType.End);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method to build and write a <see cref="TagBuilder"/> instance to the underlying stream.
|
||||
/// </summary>
|
||||
/// <param name="builder">A <see cref="TagBuilder"/> instance to write.</param>
|
||||
public virtual void WriteBuilder([NotNull] TagBuilder builder) => WriteCompound(builder.Create());
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in New Issue