/*************************************************************************** * SpanWriter.cs * ------------------- * begin : August 5, 2019 * copyright : (C) The ModernUO Team * email : hi@modernuo.com * * $Id$ * ***************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ using System; using System.Text; namespace Server.Buffers { /// /// Provides functionality for writing primitive binary data. /// public ref struct SpanWriter { private int m_Position; /// /// Underlying Span. /// public Span RawSpan { get; } /// /// Underlying Span up to the bytes written. /// public Span Span => RawSpan.Slice(0, WrittenCount); /// /// Gets the total length of the span. /// public int Length => RawSpan.Length; /// /// Total bytes written to the span. /// public int WrittenCount { get; private set; } /// /// Current position in the the span. /// public int Position { get => m_Position; set { m_Position = value; if (value > WrittenCount) WrittenCount = value; } } /// /// Instantiates a new SpanWriter instance. /// public SpanWriter(Span span) { RawSpan = span; m_Position = 0; WrittenCount = 0; } /// /// Writes a 1-byte boolean value to the span. /// public unsafe void Write(bool value) { RawSpan[Position++] = *(byte*)&value; } /// /// Writes a 1-byte unsigned integer value to the span. /// public void Write(byte value) { RawSpan[Position++] = value; } /// /// Writes a 1-byte signed integer value to the span. /// public void Write(sbyte value) { RawSpan[Position++] = (byte)value; } /// /// Writes a 2-byte signed integer value to the span. /// public void Write(short value) { Write((byte)(value >> 8)); Write((byte)value); } /// /// Writes a 2-byte unsigned integer value to the span. /// public void Write(ushort value) { Write((byte)(value >> 8)); Write((byte)value); } /// /// Writes a 4-byte signed integer value to the span. /// public void Write(int value) { Write((byte)(value >> 24)); Write((byte)(value >> 16)); Write((byte)(value >> 8)); Write((byte)value); } /// /// Writes a 4-byte unsigned integer value to the span. /// public void Write(uint value) { Write((byte)(value >> 24)); Write((byte)(value >> 16)); Write((byte)(value >> 8)); Write((byte)value); } /// /// Writes an 8-byte signed integer value to the span. /// public void Write(long value) { Write((byte)(value >> 56)); Write((byte)(value >> 48)); Write((byte)(value >> 40)); Write((byte)(value >> 32)); Write((byte)(value >> 24)); Write((byte)(value >> 16)); Write((byte)(value >> 8)); Write((byte)value); } /// /// Writes an 8-byte unsigned integer value to the span. /// public void Write(ulong value) { Write((byte)(value >> 56)); Write((byte)(value >> 48)); Write((byte)(value >> 40)); Write((byte)(value >> 32)); Write((byte)(value >> 24)); Write((byte)(value >> 16)); Write((byte)(value >> 8)); Write((byte)value); } /// /// Writes a sequence of bytes to the span. /// public void Write(ReadOnlySpan input) { int size = Math.Min(input.Length, Length - Position); input.Slice(0, size).CopyTo(RawSpan.Slice(Position)); Position += size; } /// /// Writes an ASCII-encoded string value to the span. /// public void WriteAscii(string value) { Position += Encoding.ASCII.GetBytes(value ?? "", RawSpan.Slice(Position)); } /// /// Writes a fixed-length ASCII-encoded string value to the span. /// public void WriteAsciiFixed(string value, int size, bool zero = false) { value ??= ""; int length = Math.Min(size, value.Length); Encoding.ASCII.GetBytes(value.AsSpan(0, length), RawSpan.Slice(Position)); if (zero) { Position += length; Fill(size - length); } else Position += size; } /// /// Writes a dynamic-length ASCII-encoded string value to the span, followed by a 1-byte null character. /// public void WriteAsciiNull(string value) { Position += Encoding.ASCII.GetBytes(value ?? "", RawSpan.Slice(Position)); Write((byte)0); } /// /// Writes a dynamic-length ASCII-encoded string value to the span, followed by a 1-byte null character. /// public void WriteAsciiNull(string value, int size) { value ??= ""; size = Math.Min(size, value.Length); Position += Encoding.ASCII.GetBytes(value.AsSpan(0, size), RawSpan.Slice(Position)); Write((byte)0); } /// /// Writes a dynamic-length little-endian unicode string value to the span. /// public void WriteLittleUni(string value) { Position += Encoding.Unicode.GetBytes(value ?? "", RawSpan.Slice(Position)); } /// /// Writes a dynamic-length little-endian unicode string value to the span, followed by a 2-byte null character. /// public void WriteLittleUniNull(string value) { WriteLittleUni(value); Write((ushort)0); } /// /// Writes a dynamic-length big-endian unicode string value to the span. /// public void WriteBigUni(string value) { Position += Encoding.BigEndianUnicode.GetBytes(value ?? "", RawSpan.Slice(Position)); } /// /// Writes a dynamic-length big-endian unicode string value to the span, followed by a 2-byte null character. /// public void WriteBigUniNull(string value, bool zero = false) { WriteBigUni(value); if (zero) Fill(2); else Position += 2; } /// /// Writes a dynamic-length utf-8 string value, followed by a 1-byte null character. /// public void WriteUTF8Null(string value) { Position += Encoding.UTF8.GetBytes(value ?? "", RawSpan.Slice(Position)) + 1; } /// /// Copies the span to the destination. /// public void CopyTo(Span destination) { RawSpan.CopyTo(destination); } /// /// Fills the buffer with zeroes up to count /// public void Fill(int count) { count = Math.Min(count, RawSpan.Length - Position); RawSpan.Slice(Position, count).Clear(); Position += count; } } }