1
0
mirror of https://github.com/garraflavatra/go-fmp.git synced 2025-06-27 12:05:11 +00:00

Parse table columns

This commit is contained in:
2025-06-15 21:09:58 +02:00
parent f7fef208f8
commit cc10a1e7b4
5 changed files with 159 additions and 53 deletions

View File

@ -1,8 +1,5 @@
package fmp
type FmpChunkType uint8
type FmpCollation uint8
type FmpScriptStepType uint8
type FmpError string
func (e FmpError) Error() string { return string(e) }
@ -17,50 +14,94 @@ var (
ErrBadChunk = FmpError("bad chunk")
)
const (
FmpChunkSimpleData FmpChunkType = iota
FmpChunkSegmentedData FmpChunkType = iota
FmpChunkSimpleKeyValue FmpChunkType = iota
FmpChunkLongKeyValue FmpChunkType = iota
FmpChunkPathPush FmpChunkType = iota
FmpChunkPathPushLong FmpChunkType = iota
FmpChunkPathPop FmpChunkType = iota
FmpChunkNoop FmpChunkType = iota
)
type FmpChunkType uint8
const (
FmpCollationEnglish FmpCollation = 0x00
FmpCollationFrench FmpCollation = 0x01
FmpCollationGerman FmpCollation = 0x03
FmpCollationItalian FmpCollation = 0x04
FmpCollationDutch FmpCollation = 0x05
FmpCollationSwedish FmpCollation = 0x07
FmpCollationSpanish FmpCollation = 0x08
FmpCollationDanish FmpCollation = 0x09
FmpCollationPortuguese FmpCollation = 0x0A
FmpCollationNorwegian FmpCollation = 0x0C
FmpCollationFinnish FmpCollation = 0x11
FmpCollationGreek FmpCollation = 0x14
FmpCollationIcelandic FmpCollation = 0x15
FmpCollationTurkish FmpCollation = 0x18
FmpCollationRomanian FmpCollation = 0x27
FmpCollationPolish FmpCollation = 0x2a
FmpCollationHungarian FmpCollation = 0x2b
FmpCollationRussian FmpCollation = 0x31
FmpCollationCzech FmpCollation = 0x38
FmpCollationUkrainian FmpCollation = 0x3e
FmpCollationCroatian FmpCollation = 0x42
FmpCollationCatalan FmpCollation = 0x49
FmpCollationFinnishAlt FmpCollation = 0x62
FmpCollationSwedishAlt FmpCollation = 0x63
FmpCollationGermanAlt FmpCollation = 0x64
FmpCollationSpanishAlt FmpCollation = 0x65
FmpCollationAscii FmpCollation = 0x66
FmpChunkSimpleData FmpChunkType = iota
FmpChunkSegmentedData
FmpChunkSimpleKeyValue
FmpChunkLongKeyValue
FmpChunkPathPush
FmpChunkPathPushLong
FmpChunkPathPop
FmpChunkNoop
)
type FmpFieldType uint8
const (
FmpFieldSimple FmpFieldType = 1
FmpFieldCalculation FmpFieldType = 2
FmpFieldScript FmpFieldType = 3
)
type FmpFieldStorageType uint8
const (
FmpFieldStorageRegular FmpFieldStorageType = 0
FmpFieldStorageGlobal FmpFieldStorageType = 1
FmpFieldStorageCalculation FmpFieldStorageType = 8
FmpFieldStorageUnstoredCalculation FmpFieldStorageType = 10
)
type FmpDataType uint8
const (
FmpDataText FmpDataType = 1
FmpDataNumber FmpDataType = 2
FmpDataDate FmpDataType = 3
FmpDataTime FmpDataType = 4
FmpDataTS FmpDataType = 5
FmpDataContainer FmpDataType = 6
)
type FmpAutoEnterOption uint8
const (
FmpAutoEnterData FmpAutoEnterOption = iota
FmpAutoEnterSerialNumber
FmpAutoEnterCalculation
FmpAutoEnterCalculationReplacingExistingValue
FmpAutoEnterFromLastVisitedRecord
FmpAutoEnterCreateDate
FmpAutoEnterCreateTime
FmpAutoEnterCreateTS
FmpAutoEnterCreateName
FmpAutoEnterCreateAccountName
FmpAutoEnterModDate
FmpAutoEnterModTime
FmpAutoEnterModTS
FmpAutoEnterModName
FmpAutoEnterModAccountName
)
var autoEnterPresetMap = map[uint8]FmpAutoEnterOption{
0: FmpAutoEnterCreateDate,
1: FmpAutoEnterCreateTime,
2: FmpAutoEnterCreateTS,
3: FmpAutoEnterCreateName,
4: FmpAutoEnterCreateAccountName,
5: FmpAutoEnterModDate,
6: FmpAutoEnterModTime,
7: FmpAutoEnterModTS,
8: FmpAutoEnterModName,
9: FmpAutoEnterModAccountName,
}
var autoEnterOptionMap = map[uint8]FmpAutoEnterOption{
2: FmpAutoEnterSerialNumber,
4: FmpAutoEnterData,
8: FmpAutoEnterCalculation,
16: FmpAutoEnterFromLastVisitedRecord,
32: FmpAutoEnterCalculation,
136: FmpAutoEnterCalculationReplacingExistingValue,
}
type FmpScriptStepType uint64
const (
FmpScriptPerformScript FmpScriptStepType = 1
FmpScriptSaveACopyAsXml FmpScriptStepType = 3
FmpScriptSaveCopyAsXML FmpScriptStepType = 3
FmpScriptGoToNextField FmpScriptStepType = 4
FmpScriptGoToPreviousField FmpScriptStepType = 5
FmpScriptGoToLayout FmpScriptStepType = 6
@ -115,7 +156,7 @@ const (
FmpScriptInsertText FmpScriptStepType = 61
FmpScriptPauseResumeScript FmpScriptStepType = 62
FmpScriptSendMail FmpScriptStepType = 63
FmpScriptSendDdeExecute FmpScriptStepType = 64
FmpScriptSendDDEExecute FmpScriptStepType = 64
FmpScriptDialPhone FmpScriptStepType = 65
FmpScriptSpeak FmpScriptStepType = 66
FmpScriptPerformApplescript FmpScriptStepType = 67
@ -165,7 +206,7 @@ const (
FmpScriptOpenFileOptions FmpScriptStepType = 114
FmpScriptAllowFormattingBar FmpScriptStepType = 115
FmpScriptSetNextSerialValue FmpScriptStepType = 116
FmpScriptExecuteSql FmpScriptStepType = 117
FmpScriptExecuteSQL FmpScriptStepType = 117
FmpScriptOpenHosts FmpScriptStepType = 118
FmpScriptMoveResizeWindow FmpScriptStepType = 119
FmpScriptArrangeAllWindows FmpScriptStepType = 120
@ -242,7 +283,7 @@ const (
FmpScriptSetErrorLogging FmpScriptStepType = 200
FmpScriptConfigureNfcReading FmpScriptStepType = 201
FmpScriptConfigureMachineLearningModel FmpScriptStepType = 202
FmpScriptExecuteFilemakerDataApi FmpScriptStepType = 203
FmpScriptExecuteFileMakerDataAPI FmpScriptStepType = 203
FmpScriptOpenTransaction FmpScriptStepType = 205
FmpScriptCommitTransaction FmpScriptStepType = 206
FmpScriptRevertTransaction FmpScriptStepType = 207

View File

@ -85,7 +85,7 @@ func (sect *FmpSector) processChunks(dict *FmpDict) error {
// Todo: take index into account
dict.SetValue(
currentPath,
append(dict.GetValue(currentPath), chunk.Value...),
append(dict.GetValue(currentPath...), chunk.Value...),
)
case FmpChunkSimpleKeyValue:

View File

@ -1,21 +1,60 @@
package fmp
type FmpTable struct {
ID uint64
Name string
ID uint64
Name string
Columns []FmpColumn
}
type FmpColumn struct {
ID uint64
Name string
Type FmpFieldType
DataType FmpDataType
StorageType FmpFieldStorageType
AutoEnter FmpAutoEnterOption
Indexed bool
}
func (ctx *FmpFile) Tables() []*FmpTable {
tables := make([]*FmpTable, 0)
ent := ctx.Dictionary.GetEntry([]uint64{3, 16, 5})
ent := ctx.Dictionary.GetEntry(3, 16, 5)
for path, tableEnt := range *ent.Children {
if path < 128 {
continue
}
name := decodeByteSeq(tableEnt.Children.GetValue([]uint64{16}))
table := &FmpTable{ID: path, Name: name}
table := &FmpTable{
ID: path,
Name: decodeByteSeq(tableEnt.Children.GetValue(16)),
Columns: make([]FmpColumn, 0),
}
tables = append(tables, table)
colEnt := ctx.Dictionary.GetEntry(table.ID, 3, 5)
for colPath, colEnt := range *colEnt.Children {
name := decodeByteSeq(colEnt.Children.GetValue(16))
flags := colEnt.Children.GetValue(2)
column := FmpColumn{
ID: colPath,
Name: name,
Type: FmpFieldType(flags[0]),
DataType: FmpDataType(flags[1]),
StorageType: FmpFieldStorageType(flags[9]),
Indexed: flags[8] == 128,
}
if flags[11] == 1 {
column.AutoEnter = autoEnterPresetMap[flags[4]]
} else {
column.AutoEnter = autoEnterOptionMap[flags[11]]
}
table.Columns = append(table.Columns, column)
}
}
return tables

View File

@ -38,4 +38,30 @@ func TestTables(t *testing.T) {
if !slicesHaveSameElements(tableNames, expectedNames) {
t.Errorf("tables do not match")
}
var field FmpColumn
for _, table := range tables {
for _, column := range table.Columns {
if column.Name == "PrimaryKey" {
field = column
break
}
}
}
if field.Type != FmpFieldSimple {
t.Errorf("expected field type to be simple, but it is not")
}
if field.DataType != FmpDataText {
t.Errorf("expected field data type to be text, but it is not")
}
if field.StorageType != FmpFieldStorageRegular {
t.Errorf("expected field storage type to be regular, but it is not")
}
if !field.Indexed {
t.Errorf("expected field to be indexed, but it is not")
}
if field.AutoEnter != FmpAutoEnterCalculationReplacingExistingValue {
t.Errorf("expected field to have auto enter calculation replacing existing value, but it does not")
}
}

View File

@ -9,7 +9,7 @@ type FmpDictEntry struct {
Children *FmpDict
}
func (dict *FmpDict) GetEntry(path []uint64) *FmpDictEntry {
func (dict *FmpDict) GetEntry(path ...uint64) *FmpDictEntry {
for i, key := range path {
_, ok := (*dict)[key]
if !ok {
@ -28,8 +28,8 @@ func (dict *FmpDict) GetEntry(path []uint64) *FmpDictEntry {
return nil
}
func (dict *FmpDict) GetValue(path []uint64) []byte {
ent := dict.GetEntry(path)
func (dict *FmpDict) GetValue(path ...uint64) []byte {
ent := dict.GetEntry(path...)
if ent != nil {
return ent.Value
}