eq2go/internal/packets/reader.go

255 lines
5.6 KiB
Go

package packets
import (
"encoding/binary"
"eq2emu/internal/common"
"eq2emu/internal/packets/parser"
"fmt"
"io"
"math"
)
// PacketReader reads packet data based on packet definitions
type PacketReader struct {
data []byte
pos int
}
// NewPacketReader creates a new packet reader
func NewPacketReader(data []byte) *PacketReader {
return &PacketReader{
data: data,
pos: 0,
}
}
// ParsePacketFields parses packet data using a packet definition
func ParsePacketFields(data []byte, packetName string, version uint32) (map[string]any, error) {
def, exists := GetPacket(packetName)
if !exists {
return nil, fmt.Errorf("packet definition '%s' not found", packetName)
}
reader := NewPacketReader(data)
return reader.parseStruct(def, version)
}
// parseStruct parses a struct according to packet definition
func (r *PacketReader) parseStruct(def *parser.PacketDef, version uint32) (map[string]any, error) {
result := make(map[string]any)
// Get field order for this version
order := r.getVersionOrder(def, version)
for _, fieldName := range order {
field, exists := def.Fields[fieldName]
if !exists {
continue
}
// For simplicity, skip conditional fields for now
if field.Condition != "" {
continue
}
fieldType := field.Type
if field.Type2 != 0 {
fieldType = field.Type2
}
value, err := r.readField(field, fieldType, fieldName, result)
if err != nil {
return nil, fmt.Errorf("error reading field '%s': %w", fieldName, err)
}
if value != nil {
result[fieldName] = value
}
}
return result, nil
}
// readField reads a single field from the packet data
func (r *PacketReader) readField(field parser.FieldDesc, fieldType common.EQ2DataType, fieldName string, context map[string]any) (any, error) {
switch fieldType {
case common.TypeInt8:
return r.readUint8()
case common.TypeInt16:
return r.readUint16()
case common.TypeInt32:
return r.readUint32()
case common.TypeInt64:
return r.readUint64()
case common.TypeSInt8:
return r.readInt8()
case common.TypeSInt16:
return r.readInt16()
case common.TypeSInt32:
return r.readInt32()
case common.TypeSInt64:
return r.readInt64()
case common.TypeString8:
return r.readEQ2String8()
case common.TypeString16:
return r.readEQ2String16()
case common.TypeString32:
return r.readEQ2String32()
case common.TypeFloat:
return r.readFloat32()
case common.TypeDouble:
return r.readFloat64()
case common.TypeChar:
if field.Length > 0 {
return r.readBytes(field.Length)
}
return nil, fmt.Errorf("char field '%s' has no length specified", fieldName)
default:
// For unsupported types, skip the field
return nil, nil
}
}
// Low-level read functions
func (r *PacketReader) readUint8() (uint8, error) {
if r.pos+1 > len(r.data) {
return 0, io.EOF
}
value := r.data[r.pos]
r.pos++
return value, nil
}
func (r *PacketReader) readInt8() (int8, error) {
value, err := r.readUint8()
return int8(value), err
}
func (r *PacketReader) readUint16() (uint16, error) {
if r.pos+2 > len(r.data) {
return 0, io.EOF
}
value := binary.LittleEndian.Uint16(r.data[r.pos:])
r.pos += 2
return value, nil
}
func (r *PacketReader) readInt16() (int16, error) {
value, err := r.readUint16()
return int16(value), err
}
func (r *PacketReader) readUint32() (uint32, error) {
if r.pos+4 > len(r.data) {
return 0, io.EOF
}
value := binary.LittleEndian.Uint32(r.data[r.pos:])
r.pos += 4
return value, nil
}
func (r *PacketReader) readInt32() (int32, error) {
value, err := r.readUint32()
return int32(value), err
}
func (r *PacketReader) readUint64() (uint64, error) {
if r.pos+8 > len(r.data) {
return 0, io.EOF
}
value := binary.LittleEndian.Uint64(r.data[r.pos:])
r.pos += 8
return value, nil
}
func (r *PacketReader) readInt64() (int64, error) {
value, err := r.readUint64()
return int64(value), err
}
func (r *PacketReader) readFloat32() (float32, error) {
if r.pos+4 > len(r.data) {
return 0, io.EOF
}
bits := binary.LittleEndian.Uint32(r.data[r.pos:])
r.pos += 4
return math.Float32frombits(bits), nil
}
func (r *PacketReader) readFloat64() (float64, error) {
if r.pos+8 > len(r.data) {
return 0, io.EOF
}
bits := binary.LittleEndian.Uint64(r.data[r.pos:])
r.pos += 8
return math.Float64frombits(bits), nil
}
func (r *PacketReader) readBytes(n int) ([]byte, error) {
if r.pos+n > len(r.data) {
return nil, io.EOF
}
data := make([]byte, n)
copy(data, r.data[r.pos:r.pos+n])
r.pos += n
return data, nil
}
func (r *PacketReader) readEQ2String8() (string, error) {
length, err := r.readUint8()
if err != nil {
return "", err
}
if length == 0 {
return "", nil
}
data, err := r.readBytes(int(length))
if err != nil {
return "", err
}
return string(data), nil
}
func (r *PacketReader) readEQ2String16() (string, error) {
length, err := r.readUint16()
if err != nil {
return "", err
}
if length == 0 {
return "", nil
}
data, err := r.readBytes(int(length))
if err != nil {
return "", err
}
return string(data), nil
}
func (r *PacketReader) readEQ2String32() (string, error) {
length, err := r.readUint32()
if err != nil {
return "", err
}
if length == 0 {
return "", nil
}
data, err := r.readBytes(int(length))
if err != nil {
return "", err
}
return string(data), nil
}
// getVersionOrder returns the field order for the specified version
func (r *PacketReader) getVersionOrder(def *parser.PacketDef, version uint32) []string {
var bestVersion uint32
for v := range def.Orders {
if v <= version && v > bestVersion {
bestVersion = v
}
}
if order, exists := def.Orders[bestVersion]; exists {
return order
}
return []string{}
}