package codex import ( "fmt" "gopkg.in/yaml.v3" "os" ) type Codex interface { init(cfg map[string]interface{}) ID() string Decode(data []byte, pos int, value interface{}) (int, error) Encode(data []byte, pos int, value interface{}) (int, error) } type CodexStruct struct { id string fields []Codex } func LoadCodex(fileName string) Codex { data, err := os.ReadFile(fileName) if err != nil { panic(fmt.Sprintf("Error read config %s: %s", fileName, err)) } m := make(map[string]interface{}) err = yaml.Unmarshal(data, &m) return parseType(m) } func parseType(cfg map[string]interface{}) Codex { var c Codex if ctype, ok := cfg["type"].(string); ok { switch ctype { case "struct": c = &CodexStruct{} case "string": c = &CodexString{} case "bitmap": c = &CodexBitmap{} case "llvar": c = &CodexLVar{PacketLength: 2} case "lllvar": c = &CodexLVar{PacketLength: 3} default: panic(fmt.Sprintf("Unknown type [%s]", ctype)) } } else if cfg["type"] == nil { c = &CodexString{} } else { panic(fmt.Sprintf("Invalid Codex.Type %+v", cfg)) } c.init(cfg) return c } func (c *CodexStruct) init(cfg map[string]interface{}) { if v, ok := cfg["id"].(string); ok { c.id = v } else { panic(fmt.Sprintf("Invalid CodexStruct.ID %+v", cfg)) } if v, ok := cfg["fields"].([]interface{}); ok { c.fields = make([]Codex, len(v)) for i,f := range v { if fm, ok := f.(map[string]interface{}); ok { c.fields[i] = parseType(fm) } else { panic(fmt.Sprintf("Invalid field %d %+v", i, f)) } } } else { panic(fmt.Sprintf("Invalid CodexStruct.Fields %+v", cfg)) } } func (c *CodexStruct) ID() string { return c.id } func (c *CodexStruct) Decode(data []byte, pos int, value interface{}) (int, error) { ppos := pos var err error for _, f := range c.fields { ppos, err = f.Decode(data, ppos, value) if err != nil { return pos, err } } return ppos, nil } func (c *CodexStruct) Encode(data []byte, pos int, value interface{}) (int, error) { ppos := pos var err error for _, f := range c.fields { ppos, err = f.Encode(data, ppos, value) if err != nil { return pos, err } } return ppos, nil }