108 lines
3.5 KiB
C#
108 lines
3.5 KiB
C#
using System;
|
|
using System.Text;
|
|
|
|
namespace XWorld.Framework.Protocol
|
|
{
|
|
// 与 PacketWriter 对偶;任何越界/畸形长度抛 FormatException(容错入口统一)
|
|
public sealed class PacketReader
|
|
{
|
|
private readonly byte[] _buf;
|
|
private int _pos;
|
|
|
|
public PacketReader(byte[] data)
|
|
{
|
|
_buf = data ?? Array.Empty<byte>();
|
|
_pos = 0;
|
|
}
|
|
|
|
public int Position => _pos;
|
|
public bool HasMore => _pos < _buf.Length;
|
|
|
|
public byte ReadByte()
|
|
{
|
|
if (_pos >= _buf.Length) throw new FormatException("PacketReader: read past end");
|
|
return _buf[_pos++];
|
|
}
|
|
|
|
public bool ReadBool() => ReadByte() != 0;
|
|
|
|
public ushort ReadUInt16()
|
|
{
|
|
byte lo = ReadByte();
|
|
byte hi = ReadByte();
|
|
return (ushort)(lo | (hi << 8));
|
|
}
|
|
|
|
public uint ReadVarUInt()
|
|
{
|
|
uint result = 0;
|
|
int shift = 0;
|
|
while (true)
|
|
{
|
|
if (shift > 28) throw new FormatException("PacketReader: varuint too long");
|
|
byte b = ReadByte();
|
|
// 第 5 字节(shift==28)只有低 4 位有效,超出即为越界 varuint
|
|
if (shift == 28 && (b & 0x70) != 0)
|
|
throw new FormatException("PacketReader: varuint overflow");
|
|
result |= (uint)(b & 0x7F) << shift;
|
|
if ((b & 0x80) == 0) break;
|
|
shift += 7;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public int ReadVarInt()
|
|
{
|
|
uint zig = ReadVarUInt();
|
|
return (int)(zig >> 1) ^ -(int)(zig & 1); // zigzag decode
|
|
}
|
|
|
|
public long ReadVarLong()
|
|
{
|
|
ulong result = 0;
|
|
int shift = 0;
|
|
while (true)
|
|
{
|
|
if (shift > 63) throw new FormatException("PacketReader: varlong too long");
|
|
byte b = ReadByte();
|
|
// 第 10 字节(shift==63)只有最低 1 位有效,超出即为越界 varlong
|
|
if (shift == 63 && (b & 0x7E) != 0)
|
|
throw new FormatException("PacketReader: varlong overflow");
|
|
result |= (ulong)(b & 0x7F) << shift;
|
|
if ((b & 0x80) == 0) break;
|
|
shift += 7;
|
|
}
|
|
return (long)(result >> 1) ^ -(long)(result & 1);
|
|
}
|
|
|
|
public float ReadSingle()
|
|
{
|
|
byte[] b = new byte[4];
|
|
b[0] = ReadByte(); b[1] = ReadByte(); b[2] = ReadByte(); b[3] = ReadByte();
|
|
if (!BitConverter.IsLittleEndian) Array.Reverse(b);
|
|
return BitConverter.ToSingle(b, 0);
|
|
}
|
|
|
|
public byte[] ReadBytes()
|
|
{
|
|
uint len = ReadVarUInt();
|
|
if (len == 0) return Array.Empty<byte>();
|
|
if (_pos + len > _buf.Length) throw new FormatException("PacketReader: bytes length exceeds buffer");
|
|
byte[] outv = new byte[len];
|
|
Array.Copy(_buf, _pos, outv, 0, (int)len);
|
|
_pos += (int)len;
|
|
return outv;
|
|
}
|
|
|
|
public string ReadString()
|
|
{
|
|
uint len = ReadVarUInt();
|
|
if (len == 0) return string.Empty;
|
|
if (_pos + len > _buf.Length) throw new FormatException("PacketReader: string length exceeds buffer");
|
|
string s = Encoding.UTF8.GetString(_buf, _pos, (int)len);
|
|
_pos += (int)len;
|
|
return s;
|
|
}
|
|
}
|
|
}
|