mirror of
https://github.com/garraflavatra/go-fmp.git
synced 2025-06-27 20:15:11 +00:00
Parse table columns
This commit is contained in:
129
fmp/fmp_const.go
129
fmp/fmp_const.go
@ -1,8 +1,5 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
type FmpChunkType uint8
|
|
||||||
type FmpCollation uint8
|
|
||||||
type FmpScriptStepType uint8
|
|
||||||
type FmpError string
|
type FmpError string
|
||||||
|
|
||||||
func (e FmpError) Error() string { return string(e) }
|
func (e FmpError) Error() string { return string(e) }
|
||||||
@ -17,50 +14,94 @@ var (
|
|||||||
ErrBadChunk = FmpError("bad chunk")
|
ErrBadChunk = FmpError("bad chunk")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type FmpChunkType uint8
|
||||||
FmpChunkSimpleData FmpChunkType = iota
|
|
||||||
FmpChunkSegmentedData FmpChunkType = iota
|
|
||||||
FmpChunkSimpleKeyValue FmpChunkType = iota
|
|
||||||
FmpChunkLongKeyValue FmpChunkType = iota
|
|
||||||
FmpChunkPathPush FmpChunkType = iota
|
|
||||||
FmpChunkPathPushLong FmpChunkType = iota
|
|
||||||
FmpChunkPathPop FmpChunkType = iota
|
|
||||||
FmpChunkNoop FmpChunkType = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FmpCollationEnglish FmpCollation = 0x00
|
FmpChunkSimpleData FmpChunkType = iota
|
||||||
FmpCollationFrench FmpCollation = 0x01
|
FmpChunkSegmentedData
|
||||||
FmpCollationGerman FmpCollation = 0x03
|
FmpChunkSimpleKeyValue
|
||||||
FmpCollationItalian FmpCollation = 0x04
|
FmpChunkLongKeyValue
|
||||||
FmpCollationDutch FmpCollation = 0x05
|
FmpChunkPathPush
|
||||||
FmpCollationSwedish FmpCollation = 0x07
|
FmpChunkPathPushLong
|
||||||
FmpCollationSpanish FmpCollation = 0x08
|
FmpChunkPathPop
|
||||||
FmpCollationDanish FmpCollation = 0x09
|
FmpChunkNoop
|
||||||
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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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 (
|
const (
|
||||||
FmpScriptPerformScript FmpScriptStepType = 1
|
FmpScriptPerformScript FmpScriptStepType = 1
|
||||||
FmpScriptSaveACopyAsXml FmpScriptStepType = 3
|
FmpScriptSaveCopyAsXML FmpScriptStepType = 3
|
||||||
FmpScriptGoToNextField FmpScriptStepType = 4
|
FmpScriptGoToNextField FmpScriptStepType = 4
|
||||||
FmpScriptGoToPreviousField FmpScriptStepType = 5
|
FmpScriptGoToPreviousField FmpScriptStepType = 5
|
||||||
FmpScriptGoToLayout FmpScriptStepType = 6
|
FmpScriptGoToLayout FmpScriptStepType = 6
|
||||||
@ -115,7 +156,7 @@ const (
|
|||||||
FmpScriptInsertText FmpScriptStepType = 61
|
FmpScriptInsertText FmpScriptStepType = 61
|
||||||
FmpScriptPauseResumeScript FmpScriptStepType = 62
|
FmpScriptPauseResumeScript FmpScriptStepType = 62
|
||||||
FmpScriptSendMail FmpScriptStepType = 63
|
FmpScriptSendMail FmpScriptStepType = 63
|
||||||
FmpScriptSendDdeExecute FmpScriptStepType = 64
|
FmpScriptSendDDEExecute FmpScriptStepType = 64
|
||||||
FmpScriptDialPhone FmpScriptStepType = 65
|
FmpScriptDialPhone FmpScriptStepType = 65
|
||||||
FmpScriptSpeak FmpScriptStepType = 66
|
FmpScriptSpeak FmpScriptStepType = 66
|
||||||
FmpScriptPerformApplescript FmpScriptStepType = 67
|
FmpScriptPerformApplescript FmpScriptStepType = 67
|
||||||
@ -165,7 +206,7 @@ const (
|
|||||||
FmpScriptOpenFileOptions FmpScriptStepType = 114
|
FmpScriptOpenFileOptions FmpScriptStepType = 114
|
||||||
FmpScriptAllowFormattingBar FmpScriptStepType = 115
|
FmpScriptAllowFormattingBar FmpScriptStepType = 115
|
||||||
FmpScriptSetNextSerialValue FmpScriptStepType = 116
|
FmpScriptSetNextSerialValue FmpScriptStepType = 116
|
||||||
FmpScriptExecuteSql FmpScriptStepType = 117
|
FmpScriptExecuteSQL FmpScriptStepType = 117
|
||||||
FmpScriptOpenHosts FmpScriptStepType = 118
|
FmpScriptOpenHosts FmpScriptStepType = 118
|
||||||
FmpScriptMoveResizeWindow FmpScriptStepType = 119
|
FmpScriptMoveResizeWindow FmpScriptStepType = 119
|
||||||
FmpScriptArrangeAllWindows FmpScriptStepType = 120
|
FmpScriptArrangeAllWindows FmpScriptStepType = 120
|
||||||
@ -242,7 +283,7 @@ const (
|
|||||||
FmpScriptSetErrorLogging FmpScriptStepType = 200
|
FmpScriptSetErrorLogging FmpScriptStepType = 200
|
||||||
FmpScriptConfigureNfcReading FmpScriptStepType = 201
|
FmpScriptConfigureNfcReading FmpScriptStepType = 201
|
||||||
FmpScriptConfigureMachineLearningModel FmpScriptStepType = 202
|
FmpScriptConfigureMachineLearningModel FmpScriptStepType = 202
|
||||||
FmpScriptExecuteFilemakerDataApi FmpScriptStepType = 203
|
FmpScriptExecuteFileMakerDataAPI FmpScriptStepType = 203
|
||||||
FmpScriptOpenTransaction FmpScriptStepType = 205
|
FmpScriptOpenTransaction FmpScriptStepType = 205
|
||||||
FmpScriptCommitTransaction FmpScriptStepType = 206
|
FmpScriptCommitTransaction FmpScriptStepType = 206
|
||||||
FmpScriptRevertTransaction FmpScriptStepType = 207
|
FmpScriptRevertTransaction FmpScriptStepType = 207
|
||||||
|
@ -85,7 +85,7 @@ func (sect *FmpSector) processChunks(dict *FmpDict) error {
|
|||||||
// Todo: take index into account
|
// Todo: take index into account
|
||||||
dict.SetValue(
|
dict.SetValue(
|
||||||
currentPath,
|
currentPath,
|
||||||
append(dict.GetValue(currentPath), chunk.Value...),
|
append(dict.GetValue(currentPath...), chunk.Value...),
|
||||||
)
|
)
|
||||||
|
|
||||||
case FmpChunkSimpleKeyValue:
|
case FmpChunkSimpleKeyValue:
|
||||||
|
@ -1,21 +1,60 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
type FmpTable struct {
|
type FmpTable struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
Name string
|
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 {
|
func (ctx *FmpFile) Tables() []*FmpTable {
|
||||||
tables := make([]*FmpTable, 0)
|
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 {
|
for path, tableEnt := range *ent.Children {
|
||||||
if path < 128 {
|
if path < 128 {
|
||||||
continue
|
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)
|
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
|
return tables
|
||||||
|
@ -38,4 +38,30 @@ func TestTables(t *testing.T) {
|
|||||||
if !slicesHaveSameElements(tableNames, expectedNames) {
|
if !slicesHaveSameElements(tableNames, expectedNames) {
|
||||||
t.Errorf("tables do not match")
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ type FmpDictEntry struct {
|
|||||||
Children *FmpDict
|
Children *FmpDict
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *FmpDict) GetEntry(path []uint64) *FmpDictEntry {
|
func (dict *FmpDict) GetEntry(path ...uint64) *FmpDictEntry {
|
||||||
for i, key := range path {
|
for i, key := range path {
|
||||||
_, ok := (*dict)[key]
|
_, ok := (*dict)[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -28,8 +28,8 @@ func (dict *FmpDict) GetEntry(path []uint64) *FmpDictEntry {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *FmpDict) GetValue(path []uint64) []byte {
|
func (dict *FmpDict) GetValue(path ...uint64) []byte {
|
||||||
ent := dict.GetEntry(path)
|
ent := dict.GetEntry(path...)
|
||||||
if ent != nil {
|
if ent != nil {
|
||||||
return ent.Value
|
return ent.Value
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user