264 lines
5.2 KiB
Go
264 lines
5.2 KiB
Go
package packets
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"unsafe"
|
|
)
|
|
|
|
// PacketReader for efficient packet parsing
|
|
type PacketReader struct {
|
|
data []byte
|
|
offset int
|
|
}
|
|
|
|
func NewPacketReader(data []byte) *PacketReader {
|
|
return &PacketReader{
|
|
data: data,
|
|
offset: 0,
|
|
}
|
|
}
|
|
|
|
func (r *PacketReader) Remaining() int {
|
|
return len(r.data) - r.offset
|
|
}
|
|
|
|
func (r *PacketReader) Position() int {
|
|
return r.offset
|
|
}
|
|
|
|
func (r *PacketReader) Seek(pos int) error {
|
|
if pos < 0 || pos > len(r.data) {
|
|
return fmt.Errorf("seek position out of bounds")
|
|
}
|
|
r.offset = pos
|
|
return nil
|
|
}
|
|
|
|
func (r *PacketReader) Skip(n int) error {
|
|
if r.offset+n > len(r.data) {
|
|
return io.ErrUnexpectedEOF
|
|
}
|
|
r.offset += n
|
|
return nil
|
|
}
|
|
|
|
// Read raw bytes
|
|
func (r *PacketReader) ReadBytes(n int) ([]byte, error) {
|
|
if r.offset+n > len(r.data) {
|
|
return nil, io.ErrUnexpectedEOF
|
|
}
|
|
result := make([]byte, n)
|
|
copy(result, r.data[r.offset:r.offset+n])
|
|
r.offset += n
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadBytesRef(n int) ([]byte, error) {
|
|
if r.offset+n > len(r.data) {
|
|
return nil, io.ErrUnexpectedEOF
|
|
}
|
|
result := r.data[r.offset : r.offset+n]
|
|
r.offset += n
|
|
return result, nil
|
|
}
|
|
|
|
// Read integers
|
|
func (r *PacketReader) ReadUint8() (uint8, error) {
|
|
if r.offset >= len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
result := r.data[r.offset]
|
|
r.offset++
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadInt8() (int8, error) {
|
|
val, err := r.ReadUint8()
|
|
return int8(val), err
|
|
}
|
|
|
|
func (r *PacketReader) ReadUint16() (uint16, error) {
|
|
if r.offset+2 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
result := binary.LittleEndian.Uint16(r.data[r.offset:])
|
|
r.offset += 2
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadInt16() (int16, error) {
|
|
val, err := r.ReadUint16()
|
|
return int16(val), err
|
|
}
|
|
|
|
func (r *PacketReader) ReadUint32() (uint32, error) {
|
|
if r.offset+4 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
result := binary.LittleEndian.Uint32(r.data[r.offset:])
|
|
r.offset += 4
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadInt32() (int32, error) {
|
|
val, err := r.ReadUint32()
|
|
return int32(val), err
|
|
}
|
|
|
|
func (r *PacketReader) ReadUint64() (uint64, error) {
|
|
if r.offset+8 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
result := binary.LittleEndian.Uint64(r.data[r.offset:])
|
|
r.offset += 8
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadInt64() (int64, error) {
|
|
val, err := r.ReadUint64()
|
|
return int64(val), err
|
|
}
|
|
|
|
func (r *PacketReader) ReadFloat32() (float32, error) {
|
|
if r.offset+4 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
bits := binary.LittleEndian.Uint32(r.data[r.offset:])
|
|
result := *(*float32)(unsafe.Pointer(&bits))
|
|
r.offset += 4
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadFloat64() (float64, error) {
|
|
if r.offset+8 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
bits := binary.LittleEndian.Uint64(r.data[r.offset:])
|
|
result := *(*float64)(unsafe.Pointer(&bits))
|
|
r.offset += 8
|
|
return result, nil
|
|
}
|
|
|
|
// Read strings
|
|
func (r *PacketReader) ReadString() (string, error) {
|
|
length, err := r.ReadUint16()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if r.offset+int(length) > len(r.data) {
|
|
return "", io.ErrUnexpectedEOF
|
|
}
|
|
|
|
result := string(r.data[r.offset : r.offset+int(length)])
|
|
r.offset += int(length)
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadStringFixed(length int) (string, error) {
|
|
if r.offset+length > len(r.data) {
|
|
return "", io.ErrUnexpectedEOF
|
|
}
|
|
|
|
// Find null terminator
|
|
end := r.offset + length
|
|
for i := r.offset; i < end; i++ {
|
|
if r.data[i] == 0 {
|
|
end = i
|
|
break
|
|
}
|
|
}
|
|
|
|
result := string(r.data[r.offset:end])
|
|
r.offset += length
|
|
return result, nil
|
|
}
|
|
|
|
func (r *PacketReader) ReadCString() (string, error) {
|
|
start := r.offset
|
|
for r.offset < len(r.data) && r.data[r.offset] != 0 {
|
|
r.offset++
|
|
}
|
|
|
|
if r.offset >= len(r.data) {
|
|
return "", io.ErrUnexpectedEOF
|
|
}
|
|
|
|
result := string(r.data[start:r.offset])
|
|
r.offset++ // Skip null terminator
|
|
return result, nil
|
|
}
|
|
|
|
// EQ2-specific reads
|
|
func (r *PacketReader) ReadEQ2String() (string, error) {
|
|
// EQ2 strings are prefixed with length as uint16
|
|
return r.ReadString()
|
|
}
|
|
|
|
func (r *PacketReader) ReadPackedInt() (uint32, error) {
|
|
// EQ2 packed integer format
|
|
val, err := r.ReadUint8()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if val < 0xFF {
|
|
return uint32(val), nil
|
|
}
|
|
|
|
// Extended format
|
|
val2, err := r.ReadUint16()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if val2 < 0xFFFF {
|
|
return uint32(val2), nil
|
|
}
|
|
|
|
// Full 32-bit
|
|
return r.ReadUint32()
|
|
}
|
|
|
|
func (r *PacketReader) ReadBool() (bool, error) {
|
|
val, err := r.ReadUint8()
|
|
return val != 0, err
|
|
}
|
|
|
|
// Peek without advancing
|
|
func (r *PacketReader) PeekUint8() (uint8, error) {
|
|
if r.offset >= len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
return r.data[r.offset], nil
|
|
}
|
|
|
|
func (r *PacketReader) PeekUint16() (uint16, error) {
|
|
if r.offset+2 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
return binary.LittleEndian.Uint16(r.data[r.offset:]), nil
|
|
}
|
|
|
|
func (r *PacketReader) PeekUint32() (uint32, error) {
|
|
if r.offset+4 > len(r.data) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
return binary.LittleEndian.Uint32(r.data[r.offset:]), nil
|
|
}
|
|
|
|
// Buffer management
|
|
func (r *PacketReader) Reset(data []byte) {
|
|
r.data = data
|
|
r.offset = 0
|
|
}
|
|
|
|
func (r *PacketReader) Clone() *PacketReader {
|
|
return &PacketReader{
|
|
data: r.data,
|
|
offset: r.offset,
|
|
}
|
|
}
|