diff --git a/fmp/fmp_chunk.go b/fmp/fmp_chunk.go index c70832f..84c99cf 100644 --- a/fmp/fmp_chunk.go +++ b/fmp/fmp_chunk.go @@ -232,16 +232,3 @@ func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { return nil, nil } - -func parseVarUint32(payload []byte) uint32 { - var length uint32 - n := len(payload) - if n > 4 { - n = 4 // clamp to max uint32 - } - for i := range n { - length <<= 8 - length |= uint32(payload[i]) - } - return length -} diff --git a/fmp/fmp_file.go b/fmp/fmp_file.go index ea2af53..3bca990 100644 --- a/fmp/fmp_file.go +++ b/fmp/fmp_file.go @@ -69,7 +69,7 @@ func OpenFile(path string) (*FmpFile, error) { // Todo: take index into account ctx.Dictionary.set( currentPath, - append(ctx.Dictionary.get(currentPath), chunk.Value...), + append(ctx.Dictionary.getValue(currentPath), chunk.Value...), ) case FMP_CHUNK_SIMPLE_KEY_VALUE: diff --git a/fmp/fmp_table.go b/fmp/fmp_table.go new file mode 100644 index 0000000..60592ff --- /dev/null +++ b/fmp/fmp_table.go @@ -0,0 +1,12 @@ +package fmp + +func (ctx *FmpFile) Tables() []*FmpTable { + tables := make([]*FmpTable, 0) + metaDict := ctx.Dictionary.get([]uint16{4, 1, 7}) + for _, meta := range *metaDict.Children { + name := decodeByteSeq(meta.Children.get([]uint16{16}).Value) + table := &FmpTable{Name: name} + tables = append(tables, table) + } + return tables +} diff --git a/fmp/fmp_test.go b/fmp/fmp_test.go index 21f7642..42f9a75 100644 --- a/fmp/fmp_test.go +++ b/fmp/fmp_test.go @@ -19,6 +19,24 @@ func TestOpenFile(t *testing.T) { if f.VersionDate.Format("2006-01-02") != "2025-01-11" { t.Errorf("expected version date to be '2025-01-11', got '%s'", f.VersionDate.Format("2006-01-02")) } - f.ToDebugFile("../private/output") } + +func TestTables(t *testing.T) { + f, err := OpenFile("../files/Untitled.fmp12") + if err != nil { + t.Fatal(err) + } + tables := f.Tables() + + if len(tables) != 1 || tables[0].Name != "Untitled" { + tablesString := "" + for i, table := range tables { + tablesString += table.Name + if i < len(tables)-1 { + tablesString += ", " + } + } + t.Errorf("expected tables to be 'Untitled', got '%s'", tablesString) + } +} diff --git a/fmp/fmp_type.go b/fmp/fmp_type.go index 9436643..d015c51 100644 --- a/fmp/fmp_type.go +++ b/fmp/fmp_type.go @@ -39,7 +39,11 @@ type FmpDictEntry struct { Children *FmpDict } -func (dict *FmpDict) get(path []uint16) []byte { +type FmpTable struct { + Name string +} + +func (dict *FmpDict) get(path []uint16) *FmpDictEntry { for i, key := range path { _, ok := (*dict)[key] if !ok { @@ -47,7 +51,7 @@ func (dict *FmpDict) get(path []uint16) []byte { } if i == len(path)-1 { - return (*dict)[key].Value + return (*dict)[key] } else { dict = (*dict)[key].Children } @@ -55,6 +59,14 @@ func (dict *FmpDict) get(path []uint16) []byte { return nil } +func (dict *FmpDict) getValue(path []uint16) []byte { + ent := dict.get(path) + if ent != nil { + return ent.Value + } + return nil +} + func (dict *FmpDict) set(path []uint16, value []byte) { for i, key := range path { _, ok := (*dict)[key] diff --git a/fmp/fmp_util.go b/fmp/fmp_util.go new file mode 100644 index 0000000..59ca347 --- /dev/null +++ b/fmp/fmp_util.go @@ -0,0 +1,22 @@ +package fmp + +func parseVarUint32(payload []byte) uint32 { + var length uint32 + n := len(payload) + if n > 4 { + n = 4 // clamp to max uint32 + } + for i := range n { + length <<= 8 + length |= uint32(payload[i]) + } + return length +} + +func decodeByteSeq(payload []byte) string { + result := "" + for i := range payload { + result += string(payload[i] ^ 0x5A) + } + return result +}