|
@@ -0,0 +1,93 @@
|
|
|
+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)
|
|
|
+}
|
|
|
+
|
|
|
+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
|
|
|
+}
|
|
|
+
|