111 lines
2.6 KiB
C#
111 lines
2.6 KiB
C#
using System.Buffers.Binary;
|
|||
|
|
using System.Text;
|
||
|
|
|
||
|
|
namespace Ananta.SDK.Serialization;
|
||
|
|
|
||
|
|
public sealed class UxReader
|
||
|
|
{
|
||
|
|
private readonly byte[] _data;
|
||
|
|
private int _pos;
|
||
|
|
|
||
|
|
public UxReader(byte[] data) => _data = data;
|
||
|
|
public int Position => _pos;
|
||
|
|
public int Remaining => _data.Length - _pos;
|
||
|
|
|
||
|
|
public byte U8() => _data[_pos++];
|
||
|
|
public bool Bool() => U8() != 0;
|
||
|
|
|
||
|
|
public short I16()
|
||
|
|
{
|
||
|
|
var v = BinaryPrimitives.ReadInt16LittleEndian(_data.AsSpan(_pos, 2));
|
||
|
|
_pos += 2;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public ushort U16()
|
||
|
|
{
|
||
|
|
var v = BinaryPrimitives.ReadUInt16LittleEndian(_data.AsSpan(_pos, 2));
|
||
|
|
_pos += 2;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public int I32()
|
||
|
|
{
|
||
|
|
var v = BinaryPrimitives.ReadInt32LittleEndian(_data.AsSpan(_pos, 4));
|
||
|
|
_pos += 4;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public uint U32()
|
||
|
|
{
|
||
|
|
var v = BinaryPrimitives.ReadUInt32LittleEndian(_data.AsSpan(_pos, 4));
|
||
|
|
_pos += 4;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public long I64()
|
||
|
|
{
|
||
|
|
var v = BinaryPrimitives.ReadInt64LittleEndian(_data.AsSpan(_pos, 8));
|
||
|
|
_pos += 8;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public ulong U64()
|
||
|
|
{
|
||
|
|
var v = BinaryPrimitives.ReadUInt64LittleEndian(_data.AsSpan(_pos, 8));
|
||
|
|
_pos += 8;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public float F32()
|
||
|
|
{
|
||
|
|
var v = BitConverter.ToSingle(_data, _pos);
|
||
|
|
_pos += 4;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public double F64()
|
||
|
|
{
|
||
|
|
var v = BitConverter.ToDouble(_data, _pos);
|
||
|
|
_pos += 8;
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
public int Int7() => Math.Max(0, ReadVarInt() - 1);
|
||
|
|
|
||
|
|
public string UxString() => UxStringNullable() ?? string.Empty;
|
||
|
|
|
||
|
|
public string? UxStringNullable()
|
||
|
|
{
|
||
|
|
var lenPlus = ReadVarInt();
|
||
|
|
if (lenPlus == 0) return null;
|
||
|
|
var len = Math.Max(0, lenPlus - 1);
|
||
|
|
if (len > Remaining) throw new InvalidDataException($"UX string length {len} exceeds remaining {Remaining} bytes.");
|
||
|
|
var s = Encoding.UTF8.GetString(_data, _pos, len);
|
||
|
|
_pos += len;
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
public byte[] Bytes(int count)
|
||
|
|
{
|
||
|
|
if (count < 0 || count > Remaining)
|
||
|
|
throw new InvalidDataException($"UX buffer length {count} exceeds remaining {Remaining} bytes.");
|
||
|
|
var result = _data.AsSpan(_pos, count).ToArray();
|
||
|
|
_pos += count;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
private int ReadVarInt()
|
||
|
|
{
|
||
|
|
var shift = 0;
|
||
|
|
var result = 0;
|
||
|
|
while (_pos < _data.Length)
|
||
|
|
{
|
||
|
|
var b = _data[_pos++];
|
||
|
|
result |= (b & 0x7F) << shift;
|
||
|
|
if ((b & 0x80) == 0) break;
|
||
|
|
shift += 7;
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|