1
0
mirror of https://github.com/garraflavatra/go-fmp.git synced 2025-06-28 04:25:11 +00:00

Row parsing

This commit is contained in:
2025-06-22 18:43:06 +02:00
parent 7359962d98
commit d22b209ca5
5 changed files with 53 additions and 15 deletions

View File

@ -3,6 +3,7 @@ package fmp
import (
"fmt"
"os"
"slices"
)
const debugging = false
@ -80,7 +81,15 @@ func (c *FmpChunk) String() string {
func (dict *FmpDict) string(parentPath string) string {
s := ""
for k, v := range *dict {
keys := make([]uint64, 0, len(*dict))
for k := range *dict {
keys = append(keys, k)
}
slices.Sort(keys)
for _, k := range keys {
v := (*dict)[k]
s += fmt.Sprintf("%v%v: %v\n", parentPath, k, string(v.Value))
if v.Children != nil {

View File

@ -3,11 +3,12 @@ package fmp
type FmpTable struct {
ID uint64
Name string
Columns []FmpColumn
Columns map[uint64]FmpColumn
Records map[uint64]FmpRecord
}
type FmpColumn struct {
ID uint64
Index uint64
Name string
Type FmpFieldType
DataType FmpDataType
@ -17,6 +18,11 @@ type FmpColumn struct {
Indexed bool
}
type FmpRecord struct {
Index uint64
Values map[uint64]string
}
func (ctx *FmpFile) Tables() []*FmpTable {
tables := make([]*FmpTable, 0)
ent := ctx.Dictionary.GetEntry(3, 16, 5)
@ -28,19 +34,19 @@ func (ctx *FmpFile) Tables() []*FmpTable {
table := &FmpTable{
ID: path,
Name: decodeByteSeq(tableEnt.Children.GetValue(16)),
Columns: make([]FmpColumn, 0),
Name: decodeFmpString(tableEnt.Children.GetValue(16)),
Columns: map[uint64]FmpColumn{},
Records: map[uint64]FmpRecord{},
}
tables = append(tables, table)
colEnt := ctx.Dictionary.GetEntry(table.ID, 3, 5)
for colPath, colEnt := range *colEnt.Children {
name := decodeByteSeq(colEnt.Children.GetValue(16))
for colPath, colEnt := range *ctx.Dictionary.GetChildren(table.ID, 3, 5) {
name := decodeFmpString(colEnt.Children.GetValue(16))
flags := colEnt.Children.GetValue(2)
column := FmpColumn{
ID: colPath,
Index: colPath,
Name: name,
Type: FmpFieldType(flags[0]),
DataType: FmpDataType(flags[1]),
@ -55,7 +61,16 @@ func (ctx *FmpFile) Tables() []*FmpTable {
column.AutoEnter = autoEnterOptionMap[flags[11]]
}
table.Columns = append(table.Columns, column)
table.Columns[column.Index] = column
}
for recPath, recEnt := range *ctx.Dictionary.GetChildren(table.ID, 5) {
record := FmpRecord{Index: recPath, Values: make(map[uint64]string)}
table.Records[record.Index] = record
for colIndex, value := range *recEnt.Children {
record.Values[colIndex] = decodeFmpString(value.Value)
}
}
}

View File

@ -7,11 +7,11 @@ func TestOpenFile(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if f.FileSize != 393216 {
if f.FileSize != 229376 {
t.Errorf("expected file size to be 393216, got %d", f.FileSize)
}
if f.numSectors != 95 {
t.Errorf("expected number of sectors to be 95, got %d", f.numSectors)
if f.numSectors != 55 {
t.Errorf("expected number of sectors to be 55, got %d", f.numSectors)
}
if f.CreatorName != "Pro 12.0" {
t.Errorf("expected application name to be 'Pro 12.0', got '%s'", f.CreatorName)
@ -29,7 +29,7 @@ func TestTables(t *testing.T) {
}
tables := f.Tables()
expectedNames := []string{"Untitled", "WayDomains", "WayProcesses"}
expectedNames := []string{"Untitled"}
tableNames := []string{}
for _, table := range tables {
tableNames = append(tableNames, table.Name)
@ -67,4 +67,10 @@ func TestTables(t *testing.T) {
if field.AutoEnter != FmpAutoEnterCalculationReplacingExistingValue {
t.Errorf("expected field to have auto enter calculation replacing existing value, but it does not")
}
if len(tables[0].Records) != 3 {
t.Errorf("expected table to have 3 records, but it has %d", len(tables[0].Records))
}
if tables[0].Records[1].Values[1] != "629FAA83-50D8-401F-A560-C8D45217D17B" {
t.Errorf("first record has an incorrect ID '%s'", tables[0].Records[0].Values[0])
}
}

View File

@ -36,6 +36,14 @@ func (dict *FmpDict) GetValue(path ...uint64) []byte {
return nil
}
func (dict *FmpDict) GetChildren(path ...uint64) *FmpDict {
ent := dict.GetEntry(path...)
if ent != nil {
return ent.Children
}
return &FmpDict{}
}
func (dict *FmpDict) SetValue(path []uint64, value []byte) {
for i, key := range path {
_, ok := (*dict)[key]
@ -61,7 +69,7 @@ func parseVarUint64(payload []byte) uint64 {
return length
}
func decodeByteSeq(payload []byte) string {
func decodeFmpString(payload []byte) string {
result := ""
for i := range payload {
result += string(payload[i] ^ 0x5A)