1
0
EQ2Emu/internal/packets/reader.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,
}
}