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(); _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(); 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; } } }