215 lines
5.0 KiB
Go
215 lines
5.0 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
)
|
|
|
|
// readArray handles array parsing with full substruct support
|
|
func (p *Parser) readArray(field reflect.Value, fieldTag *FieldTag) error {
|
|
var arraySize int
|
|
if fieldTag.ArraySizeVar != "" {
|
|
arraySize = p.getDynamicLength(fieldTag.ArraySizeVar)
|
|
} else {
|
|
size, err := p.readUint32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
arraySize = int(size)
|
|
}
|
|
|
|
if arraySize == 0 {
|
|
return nil
|
|
}
|
|
|
|
if field.Kind() == reflect.Slice {
|
|
elemType := field.Type().Elem()
|
|
slice := reflect.MakeSlice(field.Type(), arraySize, arraySize)
|
|
|
|
p.arrayStack = append(p.arrayStack, ArrayContext{
|
|
elementType: elemType,
|
|
totalSize: arraySize,
|
|
sizeVariable: fieldTag.ArraySizeVar,
|
|
})
|
|
|
|
for i := 0; i < arraySize; i++ {
|
|
p.arrayStack[len(p.arrayStack)-1].currentIndex = i
|
|
elem := slice.Index(i)
|
|
|
|
if elemType.Kind() == reflect.Struct {
|
|
if err := p.parseStructElement(elem, elemType); err != nil {
|
|
p.arrayStack = p.arrayStack[:len(p.arrayStack)-1]
|
|
return fmt.Errorf("array element %d: %w", i, err)
|
|
}
|
|
} else {
|
|
if err := p.readPrimitiveArrayElement(elem, elemType); err != nil {
|
|
p.arrayStack = p.arrayStack[:len(p.arrayStack)-1]
|
|
return fmt.Errorf("array element %d: %w", i, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
p.arrayStack = p.arrayStack[:len(p.arrayStack)-1]
|
|
field.Set(slice)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// readSubstruct handles substruct parsing
|
|
func (p *Parser) readSubstruct(field reflect.Value, length int) error {
|
|
if field.Kind() == reflect.Slice {
|
|
elemType := field.Type().Elem()
|
|
slice := reflect.MakeSlice(field.Type(), length, length)
|
|
|
|
for i := range length {
|
|
elem := slice.Index(i)
|
|
if err := p.parseStructElement(elem, elemType); err != nil {
|
|
return fmt.Errorf("substruct element %d: %w", i, err)
|
|
}
|
|
}
|
|
|
|
field.Set(slice)
|
|
return nil
|
|
} else if field.Kind() == reflect.Struct {
|
|
return p.parseStructElement(field, field.Type())
|
|
} else if field.Kind() == reflect.Ptr && field.Type().Elem().Kind() == reflect.Struct {
|
|
structType := field.Type().Elem()
|
|
newStruct := reflect.New(structType)
|
|
if err := p.parseStructElement(newStruct.Elem(), structType); err != nil {
|
|
return err
|
|
}
|
|
field.Set(newStruct)
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("substruct field must be struct, slice of structs, or pointer to struct")
|
|
}
|
|
|
|
// parseStructElement parses a single struct element
|
|
func (p *Parser) parseStructElement(elem reflect.Value, elemType reflect.Type) error {
|
|
oldStruct := p.currentStruct
|
|
oldCache := p.fieldCache
|
|
|
|
p.currentStruct = elem
|
|
p.fieldCache = make(map[string]any)
|
|
p.structStack = append(p.structStack, elem)
|
|
|
|
for i := range elem.NumField() {
|
|
field := elem.Field(i)
|
|
fieldType := elemType.Field(i)
|
|
|
|
if !field.CanSet() {
|
|
continue
|
|
}
|
|
|
|
tag := fieldType.Tag.Get("eq2")
|
|
if tag == "" || tag == "-" {
|
|
continue
|
|
}
|
|
|
|
if err := p.parseField(field, tag); err != nil {
|
|
p.structStack = p.structStack[:len(p.structStack)-1]
|
|
p.currentStruct = oldStruct
|
|
p.fieldCache = oldCache
|
|
return fmt.Errorf("field %s: %w", fieldType.Name, err)
|
|
}
|
|
|
|
if field.CanInterface() {
|
|
p.fieldCache[fieldType.Name] = field.Interface()
|
|
}
|
|
}
|
|
|
|
p.structStack = p.structStack[:len(p.structStack)-1]
|
|
p.currentStruct = oldStruct
|
|
p.fieldCache = oldCache
|
|
|
|
return nil
|
|
}
|
|
|
|
// readPrimitiveArrayElement reads primitive array elements
|
|
func (p *Parser) readPrimitiveArrayElement(elem reflect.Value, elemType reflect.Type) error {
|
|
switch elemType.Kind() {
|
|
case reflect.Uint8:
|
|
val, err := p.readUint8()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetUint(uint64(val))
|
|
case reflect.Uint16:
|
|
val, err := p.readUint16()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetUint(uint64(val))
|
|
case reflect.Uint32:
|
|
val, err := p.readUint32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetUint(uint64(val))
|
|
case reflect.Uint64:
|
|
val, err := p.readUint64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetUint(val)
|
|
case reflect.Int8:
|
|
val, err := p.readUint8()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetInt(int64(int8(val)))
|
|
case reflect.Int16:
|
|
val, err := p.readUint16()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetInt(int64(int16(val)))
|
|
case reflect.Int32:
|
|
val, err := p.readUint32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetInt(int64(int32(val)))
|
|
case reflect.Int64:
|
|
val, err := p.readUint64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetInt(int64(val))
|
|
case reflect.Float32:
|
|
val, err := p.readFloat32()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetFloat(float64(val))
|
|
case reflect.Float64:
|
|
val, err := p.readFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
elem.SetFloat(val)
|
|
default:
|
|
return fmt.Errorf("unsupported primitive array element type: %v", elemType.Kind())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetCurrentArrayIndex returns current array index for nested parsing
|
|
func (p *Parser) GetCurrentArrayIndex() int {
|
|
if len(p.arrayStack) > 0 {
|
|
return p.arrayStack[len(p.arrayStack)-1].currentIndex
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// GetCurrentArraySize returns current array size
|
|
func (p *Parser) GetCurrentArraySize() int {
|
|
if len(p.arrayStack) > 0 {
|
|
return p.arrayStack[len(p.arrayStack)-1].totalSize
|
|
}
|
|
return 0
|
|
}
|