376 lines
9.2 KiB
Go

package parser
import (
"reflect"
"strconv"
"strings"
)
// getDynamicLength gets length from another field with stack support and array index resolution
func (p *Parser) getDynamicLength(fieldName string) int {
// Handle %i patterns by replacing with current array index
if strings.Contains(fieldName, "%i") {
currentIndex := p.GetCurrentArrayIndex()
if currentIndex >= 0 {
fieldName = strings.ReplaceAll(fieldName, "%i", strconv.Itoa(currentIndex))
}
}
// Check field cache first
if cachedValue, exists := p.fieldCache[fieldName]; exists {
return p.valueToInt(cachedValue)
}
// Handle array index patterns like "header_info_mod_need_0"
if strings.Contains(fieldName, "_") {
if value, exists := p.resolveArrayIndexVariableForLength(fieldName); exists {
return p.valueToInt(value)
}
}
// Check current struct
if p.currentStruct.IsValid() {
if field := p.currentStruct.FieldByName(fieldName); field.IsValid() {
return p.valueToInt(field.Interface())
}
}
// Check struct stack for nested resolution
for i := len(p.structStack) - 1; i >= 0; i-- {
if field := p.structStack[i].FieldByName(fieldName); field.IsValid() {
return p.valueToInt(field.Interface())
}
}
return 0
}
// resolveArrayIndexVariableForLength handles array index variable resolution for length calculations
func (p *Parser) resolveArrayIndexVariableForLength(variable string) (any, bool) {
parts := strings.Split(variable, "_")
if len(parts) < 2 {
return nil, false
}
// Try to extract index from last part
lastPart := parts[len(parts)-1]
if index, err := strconv.Atoi(lastPart); err == nil {
// Reconstruct base variable name without index
baseVar := strings.Join(parts[:len(parts)-1], "_")
// Look for array/slice field with this base name
if cachedValue, exists := p.fieldCache[baseVar]; exists {
return p.getArrayElementSafe(cachedValue, index)
}
// Check current struct for array field
if p.currentStruct.IsValid() {
if field := p.currentStruct.FieldByName(baseVar); field.IsValid() {
return p.getArrayElementSafe(field.Interface(), index)
}
}
// Check struct stack
for i := len(p.structStack) - 1; i >= 0; i-- {
if field := p.structStack[i].FieldByName(baseVar); field.IsValid() {
return p.getArrayElementSafe(field.Interface(), index)
}
}
}
return nil, false
}
// getArrayElementSafe safely extracts element from array/slice with bounds checking
func (p *Parser) getArrayElementSafe(value any, index int) (any, bool) {
val := reflect.ValueOf(value)
switch val.Kind() {
case reflect.Slice, reflect.Array:
if index >= 0 && index < val.Len() {
return val.Index(index).Interface(), true
}
}
return nil, false
}
// convertValue converts string to appropriate type for comparison with enhanced string support
func (p *Parser) convertValue(valueStr string, reference any) (any, error) {
switch reference.(type) {
case uint8, int8:
if val, err := strconv.ParseInt(valueStr, 0, 8); err == nil {
return uint8(val), nil
}
case uint16, int16:
if val, err := strconv.ParseInt(valueStr, 0, 16); err == nil {
return uint16(val), nil
}
case uint32, int32:
if val, err := strconv.ParseInt(valueStr, 0, 32); err == nil {
return uint32(val), nil
}
case uint64, int64:
if val, err := strconv.ParseInt(valueStr, 0, 64); err == nil {
return uint64(val), nil
}
case float32:
if val, err := strconv.ParseFloat(valueStr, 32); err == nil {
return float32(val), nil
}
case float64:
if val, err := strconv.ParseFloat(valueStr, 64); err == nil {
return val, nil
}
case string:
return valueStr, nil
}
// Handle struct types with Data field (EQ2String types)
if reflect.TypeOf(reference).Kind() == reflect.Struct {
refVal := reflect.ValueOf(reference)
if dataField := refVal.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
return valueStr, nil
}
}
if val, err := strconv.ParseInt(valueStr, 0, 32); err == nil {
return int(val), nil
}
return valueStr, nil
}
// compareValues performs comparison between two values with enhanced string support
func (p *Parser) compareValues(a, b any, op string) bool {
// Handle string comparisons first
if p.isStringValue(a) && p.isStringValue(b) {
aStr := p.extractStringValue(a)
bStr := p.extractStringValue(b)
return p.compareStrings(aStr, bStr, op)
}
// Fall back to numeric comparison
aVal := p.valueToInt64(a)
bVal := p.valueToInt64(b)
switch op {
case "==":
return aVal == bVal
case "!=":
return aVal != bVal
case ">":
return aVal > bVal
case ">=":
return aVal >= bVal
case "<":
return aVal < bVal
case "<=":
return aVal <= bVal
case "&":
return (aVal & bVal) != 0
case "|":
return (aVal | bVal) != 0
}
return false
}
// isStringValue checks if a value is or contains a string
func (p *Parser) isStringValue(value any) bool {
switch value.(type) {
case string:
return true
default:
if reflect.TypeOf(value).Kind() == reflect.Struct {
val := reflect.ValueOf(value)
if dataField := val.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
return true
}
}
return false
}
}
// extractStringValue extracts string from value or struct Data field
func (p *Parser) extractStringValue(value any) string {
switch v := value.(type) {
case string:
return v
default:
if reflect.TypeOf(value).Kind() == reflect.Struct {
val := reflect.ValueOf(value)
if dataField := val.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
return dataField.String()
}
}
return ""
}
}
// compareStrings performs string comparison operations
func (p *Parser) compareStrings(a, b, op string) bool {
switch op {
case "==":
return a == b
case "!=":
return a != b
case ">":
return a > b
case ">=":
return a >= b
case "<":
return a < b
case "<=":
return a <= b
default:
return false
}
}
// valueToInt converts various types to int with enhanced type support
func (p *Parser) valueToInt(v any) int {
switch val := v.(type) {
case uint8:
return int(val)
case int8:
return int(val)
case uint16:
return int(val)
case int16:
return int(val)
case uint32:
return int(val)
case int32:
return int(val)
case uint64:
return int(val)
case int64:
return int(val)
case int:
return val
case bool:
if val {
return 1
}
return 0
default:
// Handle struct types that might have numeric fields
if reflect.TypeOf(v).Kind() == reflect.Struct {
refVal := reflect.ValueOf(v)
// Try common numeric field names
for _, fieldName := range []string{"Value", "Size", "Length", "Count"} {
if field := refVal.FieldByName(fieldName); field.IsValid() {
return p.valueToInt(field.Interface())
}
}
}
}
return 0
}
// valueToInt64 converts various types to int64 for comparison with enhanced support
func (p *Parser) valueToInt64(v any) int64 {
switch val := v.(type) {
case uint8:
return int64(val)
case int8:
return int64(val)
case uint16:
return int64(val)
case int16:
return int64(val)
case uint32:
return int64(val)
case int32:
return int64(val)
case uint64:
return int64(val)
case int64:
return val
case int:
return int64(val)
case float32:
return int64(val)
case float64:
return int64(val)
case bool:
if val {
return 1
}
return 0
default:
// Handle struct types that might have numeric fields
if reflect.TypeOf(v).Kind() == reflect.Struct {
refVal := reflect.ValueOf(v)
// Try common numeric field names
for _, fieldName := range []string{"Value", "Size", "Length", "Count"} {
if field := refVal.FieldByName(fieldName); field.IsValid() {
return p.valueToInt64(field.Interface())
}
}
}
}
return 0
}
// isTruthy checks if a value is truthy with enhanced type support
func (p *Parser) isTruthy(v any) bool {
switch val := v.(type) {
case bool:
return val
case uint8, int8, uint16, int16, uint32, int32, uint64, int64, int:
return p.valueToInt64(val) != 0
case string:
return val != ""
default:
// Handle struct types
if reflect.TypeOf(v).Kind() == reflect.Struct {
refVal := reflect.ValueOf(v)
// Check for Data field (string types)
if dataField := refVal.FieldByName("Data"); dataField.IsValid() && dataField.Kind() == reflect.String {
return dataField.String() != ""
}
// Check for numeric fields
for _, fieldName := range []string{"Value", "Size", "Length", "Count"} {
if field := refVal.FieldByName(fieldName); field.IsValid() {
return p.valueToInt64(field.Interface()) != 0
}
}
}
}
return false
}
// handleOversizedField handles fields that exceed their oversized value
func (p *Parser) handleOversizedField(field reflect.Value, oversizedByte byte, length int) error {
if field.Kind() == reflect.Slice {
slice := reflect.MakeSlice(field.Type(), 1, 1)
if slice.Len() > 0 {
elem := slice.Index(0)
if elem.CanSet() {
switch elem.Kind() {
case reflect.Uint8:
elem.SetUint(uint64(oversizedByte))
case reflect.Int8:
elem.SetInt(int64(int8(oversizedByte)))
default:
elem.SetUint(uint64(oversizedByte))
}
}
}
field.Set(slice)
} else {
switch field.Kind() {
case reflect.Uint8:
field.SetUint(uint64(oversizedByte))
case reflect.Int8:
field.SetInt(int64(int8(oversizedByte)))
default:
field.SetUint(uint64(oversizedByte))
}
}
return nil
}