3a890782b5
Port From (https://github.com/TrinityCore/TrinityCore/commit/53068a94e88991ae7196fb247df4b7ca2e47e554)
444 lines
11 KiB
C#
444 lines
11 KiB
C#
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
|
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Numerics;
|
|
using System.Text;
|
|
|
|
namespace Framework.IO
|
|
{
|
|
public class ByteBuffer : IDisposable
|
|
{
|
|
public ByteBuffer()
|
|
{
|
|
writeStream = new BinaryWriter(new MemoryStream());
|
|
}
|
|
|
|
public ByteBuffer(byte[] data)
|
|
{
|
|
readStream = new BinaryReader(new MemoryStream(data));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (writeStream != null)
|
|
writeStream.Dispose();
|
|
|
|
if (readStream != null)
|
|
readStream.Dispose();
|
|
}
|
|
|
|
#region Read Methods
|
|
public sbyte ReadInt8()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadSByte();
|
|
}
|
|
|
|
public short ReadInt16()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadInt16();
|
|
}
|
|
|
|
public int ReadInt32()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadInt32();
|
|
}
|
|
|
|
public long ReadInt64()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadInt64();
|
|
}
|
|
|
|
public byte ReadUInt8()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadByte();
|
|
}
|
|
|
|
public ushort ReadUInt16()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadUInt16();
|
|
}
|
|
|
|
public uint ReadUInt32()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadUInt32();
|
|
}
|
|
|
|
public ulong ReadUInt64()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadUInt64();
|
|
}
|
|
|
|
public float ReadFloat()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadSingle();
|
|
}
|
|
|
|
public double ReadDouble()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadDouble();
|
|
}
|
|
|
|
public string ReadCString()
|
|
{
|
|
ResetBitPos();
|
|
StringBuilder tmpString = new();
|
|
char tmpChar = readStream.ReadChar();
|
|
char tmpEndChar = Convert.ToChar(Encoding.UTF8.GetString(new byte[] { 0 }));
|
|
|
|
while (tmpChar != tmpEndChar)
|
|
{
|
|
tmpString.Append(tmpChar);
|
|
tmpChar = readStream.ReadChar();
|
|
}
|
|
|
|
return tmpString.ToString();
|
|
}
|
|
|
|
public string ReadString(uint length)
|
|
{
|
|
if (length == 0)
|
|
return "";
|
|
|
|
ResetBitPos();
|
|
return Encoding.UTF8.GetString(ReadBytes(length));
|
|
}
|
|
|
|
public bool ReadBool()
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadBoolean();
|
|
}
|
|
|
|
public byte[] ReadBytes(uint count)
|
|
{
|
|
ResetBitPos();
|
|
return readStream.ReadBytes((int)count);
|
|
}
|
|
|
|
public void Skip(int count)
|
|
{
|
|
ResetBitPos();
|
|
readStream.BaseStream.Position += count;
|
|
}
|
|
|
|
public uint ReadPackedTime()
|
|
{
|
|
return (uint)Time.GetUnixTimeFromPackedTime(ReadUInt32());
|
|
}
|
|
|
|
public Vector3 ReadVector3()
|
|
{
|
|
return new Vector3(ReadFloat(), ReadFloat(), ReadFloat());
|
|
}
|
|
|
|
//BitPacking
|
|
public byte ReadBit()
|
|
{
|
|
if (_bitPosition == 8)
|
|
{
|
|
BitValue = ReadUInt8();
|
|
_bitPosition = 0;
|
|
}
|
|
|
|
int returnValue = BitValue;
|
|
BitValue = (byte)(2 * returnValue);
|
|
++_bitPosition;
|
|
|
|
return (byte)(returnValue >> 7);
|
|
}
|
|
|
|
public bool HasBit()
|
|
{
|
|
if (_bitPosition == 8)
|
|
{
|
|
BitValue = ReadUInt8();
|
|
_bitPosition = 0;
|
|
}
|
|
|
|
int returnValue = BitValue;
|
|
BitValue = (byte)(2 * returnValue);
|
|
++_bitPosition;
|
|
|
|
return Convert.ToBoolean(returnValue >> 7);
|
|
}
|
|
|
|
public T ReadBits<T>(int bitCount)
|
|
{
|
|
int value = 0;
|
|
|
|
for (var i = bitCount - 1; i >= 0; --i)
|
|
if (HasBit())
|
|
value |= (1 << i);
|
|
|
|
return (T)Convert.ChangeType(value, typeof(T));
|
|
}
|
|
#endregion
|
|
|
|
#region Write Methods
|
|
public void WriteInt8(sbyte data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteInt16(short data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteInt32(int data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteInt64(long data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteUInt8(byte data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteUInt16(ushort data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteUInt32(uint data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteUInt64(ulong data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteFloat(float data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
public void WriteDouble(double data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a string to the packet with a null terminated (0)
|
|
/// </summary>
|
|
/// <param name="str"></param>
|
|
public void WriteCString(string str)
|
|
{
|
|
if (string.IsNullOrEmpty(str))
|
|
{
|
|
WriteUInt8(0);
|
|
return;
|
|
}
|
|
|
|
WriteString(str);
|
|
WriteUInt8(0);
|
|
}
|
|
|
|
public void WriteString(string str)
|
|
{
|
|
if (str.IsEmpty())
|
|
return;
|
|
|
|
byte[] sBytes = Encoding.UTF8.GetBytes(str);
|
|
WriteBytes(sBytes);
|
|
}
|
|
|
|
public void WriteBytes(byte[] data)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data, 0, data.Length);
|
|
}
|
|
|
|
public void WriteBytes(byte[] data, uint count)
|
|
{
|
|
FlushBits();
|
|
writeStream.Write(data, 0, (int)count);
|
|
}
|
|
|
|
public void WriteBytes(ByteBuffer buffer)
|
|
{
|
|
WriteBytes(buffer.GetData());
|
|
}
|
|
|
|
public void WriteVector4(Vector4 pos)
|
|
{
|
|
WriteFloat(pos.X);
|
|
WriteFloat(pos.Y);
|
|
WriteFloat(pos.Z);
|
|
WriteFloat(pos.W);
|
|
}
|
|
|
|
public void WriteVector3(Vector3 pos)
|
|
{
|
|
WriteFloat(pos.X);
|
|
WriteFloat(pos.Y);
|
|
WriteFloat(pos.Z);
|
|
}
|
|
|
|
public void WriteVector2(Vector2 pos)
|
|
{
|
|
WriteFloat(pos.X);
|
|
WriteFloat(pos.Y);
|
|
}
|
|
|
|
public void WritePackXYZ(Vector3 pos)
|
|
{
|
|
uint packed = 0;
|
|
packed |= ((uint)(pos.X / 0.25f) & 0x7FF);
|
|
packed |= ((uint)(pos.Y / 0.25f) & 0x7FF) << 11;
|
|
packed |= ((uint)(pos.Z / 0.25f) & 0x3FF) << 22;
|
|
WriteUInt32(packed);
|
|
}
|
|
|
|
public bool WriteBit(bool bit)
|
|
{
|
|
--_bitPosition;
|
|
|
|
if (bit)
|
|
BitValue |= (byte)(1 << _bitPosition);
|
|
|
|
if (_bitPosition == 0)
|
|
{
|
|
writeStream.Write(BitValue);
|
|
|
|
_bitPosition = 8;
|
|
BitValue = 0;
|
|
}
|
|
return bit;
|
|
}
|
|
|
|
public void WriteBits(object bit, int count)
|
|
{
|
|
for (int i = count - 1; i >= 0; --i)
|
|
WriteBit(((Convert.ToUInt32(bit) >> i) & 1) != 0);
|
|
}
|
|
|
|
public void WritePackedTime(long time)
|
|
{
|
|
WriteUInt32(Time.GetPackedTimeFromUnixTime(time));
|
|
}
|
|
|
|
public void WritePackedTime()
|
|
{
|
|
WriteUInt32(Time.GetPackedTimeFromDateTime(DateTime.Now));
|
|
}
|
|
|
|
public void Write<T>(T value)
|
|
{
|
|
switch (value)
|
|
{
|
|
case sbyte v: WriteInt8(v); break;
|
|
case short v: WriteInt16(v); break;
|
|
case int v: WriteInt32(v); break;
|
|
case long v: WriteInt64(v); break;
|
|
case byte v: WriteUInt8(v); break;
|
|
case ushort v: WriteUInt16(v); break;
|
|
case uint v: WriteUInt32(v); break;
|
|
case ulong v: WriteUInt64(v); break;
|
|
case float v: WriteFloat(v); break;
|
|
case double v: WriteDouble(v); break;
|
|
case string v: WriteString(v); break;
|
|
case bool v: WriteBit(v); break;
|
|
case byte[] v: WriteBytes(v); break;
|
|
case Vector3 v: WriteVector3(v); break;
|
|
default:
|
|
throw new InvalidOperationException($"Type {typeof(T)} is not supported for writing.");
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
public bool HasUnfinishedBitPack()
|
|
{
|
|
return _bitPosition != 8;
|
|
}
|
|
|
|
public void FlushBits()
|
|
{
|
|
if (_bitPosition == 8)
|
|
return;
|
|
|
|
writeStream.Write(BitValue);
|
|
BitValue = 0;
|
|
_bitPosition = 8;
|
|
}
|
|
|
|
public void ResetBitPos()
|
|
{
|
|
if (_bitPosition > 7)
|
|
return;
|
|
|
|
_bitPosition = 8;
|
|
BitValue = 0;
|
|
}
|
|
|
|
public byte[] GetData()
|
|
{
|
|
Stream stream = GetCurrentStream();
|
|
|
|
var data = new byte[stream.Length];
|
|
|
|
long pos = stream.Position;
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
for (int i = 0; i < data.Length; i++)
|
|
data[i] = (byte)stream.ReadByte();
|
|
|
|
stream.Seek(pos, SeekOrigin.Begin);
|
|
return data;
|
|
}
|
|
|
|
public uint GetSize()
|
|
{
|
|
return (uint)GetCurrentStream().Length;
|
|
}
|
|
|
|
public Stream GetCurrentStream()
|
|
{
|
|
if (writeStream != null)
|
|
return writeStream.BaseStream;
|
|
else
|
|
return readStream.BaseStream;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
_bitPosition = 8;
|
|
BitValue = 0;
|
|
writeStream = new BinaryWriter(new MemoryStream());
|
|
}
|
|
|
|
byte _bitPosition = 8;
|
|
byte BitValue;
|
|
BinaryWriter writeStream;
|
|
BinaryReader readStream;
|
|
}
|
|
}
|