Supercell.GUT/Supercell.GUT.Titan/Encoding/Streamed/ByteStream.cs
BreadDEV ad23f95319 [v0.0.1] very early state server
only basic messages, wip.
2024-03-04 20:19:32 +07:00

302 lines
No EOL
6.7 KiB
C#

using Supercell.GUT.Titan.Math;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using TextEncoding = System.Text.Encoding;
namespace Supercell.GUT.Titan.Encoding.Streamed;
public class ByteStream : ChecksumEncoder
{
public byte[] Buffer { get; set; }
private int _bitIndex;
private int _length;
public int Offset { get; set; }
public int Length => _length > 0 ? _length : Offset;
public ByteStream(byte[] buffer, int length)
{
Buffer = buffer;
_length = length;
}
public ByteStream(int capacity)
{
Buffer = new byte[capacity];
}
public ByteStream()
{
Buffer = new byte[10];
}
public void SetByteArray(byte[] buffer, int length)
{
Buffer = buffer;
_length = length;
}
public bool ReadBoolean()
{
if (_bitIndex == 0)
++Offset;
bool value = (Buffer[Offset - 1] & 1 << _bitIndex) != 0;
_bitIndex = _bitIndex + 1 & 7;
return value;
}
public byte ReadByte()
{
_bitIndex = 0;
return Buffer[Offset++];
}
public short ReadShort()
{
_bitIndex = 0;
short ret = BinaryPrimitives.ReadInt16BigEndian(Buffer.AsSpan()[Offset..]);
Offset += 2;
return ret;
}
public int ReadInt()
{
_bitIndex = 0;
int ret = BinaryPrimitives.ReadInt32BigEndian(Buffer.AsSpan()[Offset..]);
Offset += 4;
return ret;
}
public int ReadVInt()
{
_bitIndex = 0;
int value = 0;
byte byteValue = Buffer[Offset++];
if ((byteValue & 0x40) != 0)
{
value |= byteValue & 0x3F;
if ((byteValue & 0x80) != 0)
{
value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 6;
if ((byteValue & 0x80) != 0)
{
value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 13;
if ((byteValue & 0x80) != 0)
{
value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 20;
if ((byteValue & 0x80) != 0)
{
value |= ((_ = Buffer[Offset++]) & 0x7F) << 27;
return (int)(value | 0x80000000);
}
return (int)(value | 0xF8000000);
}
return (int)(value | 0xFFF00000);
}
return (int)(value | 0xFFFFE000);
}
return (int)(value | 0xFFFFFFC0);
}
value |= byteValue & 0x3F;
if ((byteValue & 0x80) != 0)
{
value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 6;
if ((byteValue & 0x80) != 0)
{
value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 13;
if ((byteValue & 0x80) != 0)
{
value |= ((byteValue = Buffer[Offset++]) & 0x7F) << 20;
if ((byteValue & 0x80) != 0)
{
value |= ((_ = Buffer[Offset++]) & 0x7F) << 27;
}
}
}
}
return value;
}
public LogicLong ReadLong()
{
LogicLong ll = new();
ll.Decode(this);
return ll;
}
public string? ReadString()
{
int length = ReadInt();
if (length is < 0 or > 900000)
return null;
else if (length == 0)
return string.Empty;
string ret = TextEncoding.UTF8.GetString(Buffer, Offset, length);
Offset += length;
return ret;
}
public string ReadStringReference()
{
int length = ReadInt();
if (length is <= 0 or > 900000) return string.Empty;
string ret = TextEncoding.UTF8.GetString(Buffer, Offset, length);
Offset += length;
return ret;
}
public byte[] ReadBytes(int length)
{
_bitIndex = 0;
byte[] ret = Buffer.Skip(Offset).Take(length).ToArray();
Offset += length;
return ret;
}
public override ChecksumEncoder WriteBoolean(bool value)
{
base.WriteBoolean(value);
if (_bitIndex == 0)
{
EnsureCapacity(1);
Buffer[Offset++] = 0;
}
Buffer[Offset - 1] |= (byte)(value ? 1 : 0);
_bitIndex = _bitIndex + 1 & 7;
return this;
}
public override ChecksumEncoder WriteByte(byte value)
{
base.WriteByte(value);
EnsureCapacity(1);
Buffer[Offset++] = value;
return this;
}
public override ChecksumEncoder WriteShort(short value)
{
base.WriteShort(value);
EnsureCapacity(2);
BinaryPrimitives.WriteInt16BigEndian(Buffer.AsSpan()[Offset..], value);
Offset += 2;
return this;
}
public override ChecksumEncoder WriteInt(int value)
{
base.WriteInt(value);
EnsureCapacity(4);
WriteIntToByteArray(value);
return this;
}
public override ChecksumEncoder WriteString(string? value)
{
base.WriteString(value);
if (value == null)
{
WriteIntToByteArray(-1);
return this;
}
int size = TextEncoding.UTF8.GetByteCount(value);
WriteIntToByteArray(size);
EnsureCapacity(size);
TextEncoding.UTF8.GetBytes(value, Buffer.AsSpan()[Offset..]);
Offset += size;
return this;
}
public override ChecksumEncoder WriteBytes(ReadOnlySpan<byte> value)
{
base.WriteBytes(value);
WriteIntToByteArray(value.Length);
EnsureCapacity(value.Length);
value.CopyTo(Buffer.AsSpan()[Offset..]);
Offset += value.Length;
return this;
}
public override bool IsCheckSumOnlyMode => false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteIntToByteArray(int value)
{
EnsureCapacity(4);
BinaryPrimitives.WriteInt32BigEndian(Buffer.AsSpan()[Offset..], value);
Offset += 4;
}
public void EnsureCapacity(int capacity)
{
_bitIndex = 0;
int bufferLength = Buffer.Length;
if (Offset + capacity > bufferLength)
{
byte[] tmpBuffer = new byte[Buffer.Length + capacity + 100];
System.Buffer.BlockCopy(Buffer, 0, tmpBuffer, 0, bufferLength);
Buffer = tmpBuffer;
}
}
public bool IsAtEnd()
{
return Offset >= Buffer.Length;
}
public void ResetOffset()
{
this.Offset = 0;
}
public void Destruct()
{
;
}
}