mirror of
https://github.com/garraflavatra/go-fmp.git
synced 2025-06-27 20:15:11 +00:00
Restructure, add script step constants
This commit is contained in:
269
fmp/fmp_const.go
269
fmp/fmp_const.go
@ -1,7 +1,9 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
type FmpError string
|
|
||||||
type FmpChunkType uint8
|
type FmpChunkType uint8
|
||||||
|
type FmpCollation uint8
|
||||||
|
type FmpScriptStepType uint8
|
||||||
|
type FmpError string
|
||||||
|
|
||||||
func (e FmpError) Error() string { return string(e) }
|
func (e FmpError) Error() string { return string(e) }
|
||||||
|
|
||||||
@ -16,42 +18,237 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FMP_CHUNK_SIMPLE_DATA FmpChunkType = iota
|
FmpChunkSimpleData FmpChunkType = iota
|
||||||
FMP_CHUNK_SEGMENTED_DATA
|
FmpChunkSegmentedData FmpChunkType = iota
|
||||||
FMP_CHUNK_SIMPLE_KEY_VALUE
|
FmpChunkSimpleKeyValue FmpChunkType = iota
|
||||||
FMP_CHUNK_LONG_KEY_VALUE
|
FmpChunkLongKeyValue FmpChunkType = iota
|
||||||
FMP_CHUNK_PATH_PUSH
|
FmpChunkPathPush FmpChunkType = iota
|
||||||
FMP_CHUNK_PATH_PUSH_LONG
|
FmpChunkPathPushLong FmpChunkType = iota
|
||||||
FMP_CHUNK_PATH_POP
|
FmpChunkPathPop FmpChunkType = iota
|
||||||
FMP_CHUNK_NOOP
|
FmpChunkNoop FmpChunkType = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FMP_COLLATION_ENGLISH = 0x00
|
FmpCollationEnglish FmpCollation = 0x00
|
||||||
FMP_COLLATION_FRENCH = 0x01
|
FmpCollationFrench FmpCollation = 0x01
|
||||||
FMP_COLLATION_GERMAN = 0x03
|
FmpCollationGerman FmpCollation = 0x03
|
||||||
FMP_COLLATION_ITALIAN = 0x04
|
FmpCollationItalian FmpCollation = 0x04
|
||||||
FMP_COLLATION_DUTCH = 0x05
|
FmpCollationDutch FmpCollation = 0x05
|
||||||
FMP_COLLATION_SWEDISH = 0x07
|
FmpCollationSwedish FmpCollation = 0x07
|
||||||
FMP_COLLATION_SPANISH = 0x08
|
FmpCollationSpanish FmpCollation = 0x08
|
||||||
FMP_COLLATION_DANISH = 0x09
|
FmpCollationDanish FmpCollation = 0x09
|
||||||
FMP_COLLATION_PORTUGUESE = 0x0A
|
FmpCollationPortuguese FmpCollation = 0x0A
|
||||||
FMP_COLLATION_NORWEGIAN = 0x0C
|
FmpCollationNorwegian FmpCollation = 0x0C
|
||||||
FMP_COLLATION_FINNISH = 0x11
|
FmpCollationFinnish FmpCollation = 0x11
|
||||||
FMP_COLLATION_GREEK = 0x14
|
FmpCollationGreek FmpCollation = 0x14
|
||||||
FMP_COLLATION_ICELANDIC = 0x15
|
FmpCollationIcelandic FmpCollation = 0x15
|
||||||
FMP_COLLATION_TURKISH = 0x18
|
FmpCollationTurkish FmpCollation = 0x18
|
||||||
FMP_COLLATION_ROMANIAN = 0x27
|
FmpCollationRomanian FmpCollation = 0x27
|
||||||
FMP_COLLATION_POLISH = 0x2a
|
FmpCollationPolish FmpCollation = 0x2a
|
||||||
FMP_COLLATION_HUNGARIAN = 0x2b
|
FmpCollationHungarian FmpCollation = 0x2b
|
||||||
FMP_COLLATION_RUSSIAN = 0x31
|
FmpCollationRussian FmpCollation = 0x31
|
||||||
FMP_COLLATION_CZECH = 0x38
|
FmpCollationCzech FmpCollation = 0x38
|
||||||
FMP_COLLATION_UKRAINIAN = 0x3e
|
FmpCollationUkrainian FmpCollation = 0x3e
|
||||||
FMP_COLLATION_CROATIAN = 0x42
|
FmpCollationCroatian FmpCollation = 0x42
|
||||||
FMP_COLLATION_CATALAN = 0x49
|
FmpCollationCatalan FmpCollation = 0x49
|
||||||
FMP_COLLATION_FINNISH_ALT = 0x62
|
FmpCollationFinnishAlt FmpCollation = 0x62
|
||||||
FMP_COLLATION_SWEDISH_ALT = 0x63
|
FmpCollationSwedishAlt FmpCollation = 0x63
|
||||||
FMP_COLLATION_GERMAN_ALT = 0x64
|
FmpCollationGermanAlt FmpCollation = 0x64
|
||||||
FMP_COLLATION_SPANISH_ALT = 0x65
|
FmpCollationSpanishAlt FmpCollation = 0x65
|
||||||
FMP_COLLATION_ASCII = 0x66
|
FmpCollationAscii FmpCollation = 0x66
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FmpScriptPerformScript FmpScriptStepType = 1
|
||||||
|
FmpScriptSaveACopyAsXml FmpScriptStepType = 3
|
||||||
|
FmpScriptGoToNextField FmpScriptStepType = 4
|
||||||
|
FmpScriptGoToPreviousField FmpScriptStepType = 5
|
||||||
|
FmpScriptGoToLayout FmpScriptStepType = 6
|
||||||
|
FmpScriptNewRecordRequest FmpScriptStepType = 7
|
||||||
|
FmpScriptDuplicateRecordRequest FmpScriptStepType = 8
|
||||||
|
FmpScriptDeleteRecordRequest FmpScriptStepType = 9
|
||||||
|
FmpScriptDeleteAllRecords FmpScriptStepType = 10
|
||||||
|
FmpScriptInsertFromIndex FmpScriptStepType = 11
|
||||||
|
FmpScriptInsertFromLastVisited FmpScriptStepType = 12
|
||||||
|
FmpScriptInsertCurrentDate FmpScriptStepType = 13
|
||||||
|
FmpScriptInsertCurrentTime FmpScriptStepType = 14
|
||||||
|
FmpScriptGoToRecordRequestPage FmpScriptStepType = 16
|
||||||
|
FmpScriptGoToField FmpScriptStepType = 17
|
||||||
|
FmpScriptCheckSelection FmpScriptStepType = 18
|
||||||
|
FmpScriptCheckRecord FmpScriptStepType = 19
|
||||||
|
FmpScriptCheckFoundSet FmpScriptStepType = 20
|
||||||
|
FmpScriptUnsortRecords FmpScriptStepType = 21
|
||||||
|
FmpScriptEnterFindMode FmpScriptStepType = 22
|
||||||
|
FmpScriptShowAllRecords FmpScriptStepType = 23
|
||||||
|
FmpScriptModifyLastFind FmpScriptStepType = 24
|
||||||
|
FmpScriptOmitRecord FmpScriptStepType = 25
|
||||||
|
FmpScriptOmitMultipleRecords FmpScriptStepType = 26
|
||||||
|
FmpScriptShowOmmitedOnly FmpScriptStepType = 27
|
||||||
|
FmpScriptPerformFind FmpScriptStepType = 28
|
||||||
|
FmpScriptShowHideToolbars FmpScriptStepType = 29
|
||||||
|
FmpScriptViewAs FmpScriptStepType = 30
|
||||||
|
FmpScriptAdjustWindow FmpScriptStepType = 31
|
||||||
|
FmpScriptOpenHelp FmpScriptStepType = 32
|
||||||
|
FmpScriptOpenFile FmpScriptStepType = 33
|
||||||
|
FmpScriptCloseFile FmpScriptStepType = 34
|
||||||
|
FmpScriptImportRecords FmpScriptStepType = 35
|
||||||
|
FmpScriptExportRecords FmpScriptStepType = 36
|
||||||
|
FmpScriptSaveACopyAs FmpScriptStepType = 37
|
||||||
|
FmpScriptOpenManageDatabase FmpScriptStepType = 38
|
||||||
|
FmpScriptSortRecords FmpScriptStepType = 39
|
||||||
|
FmpScriptRelookupFieldContents FmpScriptStepType = 40
|
||||||
|
FmpScriptEnterPreviewMode FmpScriptStepType = 41
|
||||||
|
FmpScriptPrintSetup FmpScriptStepType = 42
|
||||||
|
FmpScriptPrint FmpScriptStepType = 43
|
||||||
|
FmpScriptExitApplication FmpScriptStepType = 44
|
||||||
|
FmpScriptUndoRedo FmpScriptStepType = 45
|
||||||
|
FmpScriptCut FmpScriptStepType = 46
|
||||||
|
FmpScriptCopy FmpScriptStepType = 47
|
||||||
|
FmpScriptPaste FmpScriptStepType = 48
|
||||||
|
FmpScriptClear FmpScriptStepType = 49
|
||||||
|
FmpScriptSelectAll FmpScriptStepType = 50
|
||||||
|
FmpScriptRevertRecordRequest FmpScriptStepType = 51
|
||||||
|
FmpScriptEnterBrowserMode FmpScriptStepType = 55
|
||||||
|
FmpScriptInsertPicture FmpScriptStepType = 56
|
||||||
|
FmpScriptSendEvent FmpScriptStepType = 57
|
||||||
|
FmpScriptInsertCurrentUserName FmpScriptStepType = 60
|
||||||
|
FmpScriptInsertText FmpScriptStepType = 61
|
||||||
|
FmpScriptPauseResumeScript FmpScriptStepType = 62
|
||||||
|
FmpScriptSendMail FmpScriptStepType = 63
|
||||||
|
FmpScriptSendDdeExecute FmpScriptStepType = 64
|
||||||
|
FmpScriptDialPhone FmpScriptStepType = 65
|
||||||
|
FmpScriptSpeak FmpScriptStepType = 66
|
||||||
|
FmpScriptPerformApplescript FmpScriptStepType = 67
|
||||||
|
FmpScriptIf FmpScriptStepType = 68
|
||||||
|
FmpScriptElse FmpScriptStepType = 69
|
||||||
|
FmpScriptEndIf FmpScriptStepType = 70
|
||||||
|
FmpScriptLoop FmpScriptStepType = 71
|
||||||
|
FmpScriptExitLoopIf FmpScriptStepType = 72
|
||||||
|
FmpScriptEndLoop FmpScriptStepType = 73
|
||||||
|
FmpScriptGoToRelatedRecord FmpScriptStepType = 74
|
||||||
|
FmpScriptCommitRecordsRequests FmpScriptStepType = 75
|
||||||
|
FmpScriptSetField FmpScriptStepType = 76
|
||||||
|
FmpScriptInsertCalculatedResult FmpScriptStepType = 77
|
||||||
|
FmpScriptFreezeWindow FmpScriptStepType = 79
|
||||||
|
FmpScriptRefreshWindow FmpScriptStepType = 80
|
||||||
|
FmpScriptScrollWindow FmpScriptStepType = 81
|
||||||
|
FmpScriptNewFile FmpScriptStepType = 82
|
||||||
|
FmpScriptChangePassword FmpScriptStepType = 83
|
||||||
|
FmpScriptSetMultiUser FmpScriptStepType = 84
|
||||||
|
FmpScriptAllowUserAbort FmpScriptStepType = 85
|
||||||
|
FmpScriptSetErrorCapture FmpScriptStepType = 86
|
||||||
|
FmpScriptShowCustomDialog FmpScriptStepType = 87
|
||||||
|
FmpScriptOpenScriptWorkspace FmpScriptStepType = 88
|
||||||
|
FmpScriptBlankLineComment FmpScriptStepType = 89
|
||||||
|
FmpScriptHaltScript FmpScriptStepType = 90
|
||||||
|
FmpScriptReplaceFieldContents FmpScriptStepType = 91
|
||||||
|
FmpScriptShowHideTextRuler FmpScriptStepType = 92
|
||||||
|
FmpScriptBeep FmpScriptStepType = 93
|
||||||
|
FmpScriptSetUseSystemFormats FmpScriptStepType = 94
|
||||||
|
FmpScriptRecoverFile FmpScriptStepType = 95
|
||||||
|
FmpScriptSaveACopyAsAddOnPackage FmpScriptStepType = 96
|
||||||
|
FmpScriptSetZoomLevel FmpScriptStepType = 97
|
||||||
|
FmpScriptCopyAllRecordsRequests FmpScriptStepType = 98
|
||||||
|
FmpScriptGoToPortalRow FmpScriptStepType = 99
|
||||||
|
FmpScriptCopyRecordRequest FmpScriptStepType = 101
|
||||||
|
FmpScriptFluchCacheToDisk FmpScriptStepType = 102
|
||||||
|
FmpScriptExitScript FmpScriptStepType = 103
|
||||||
|
FmpScriptDeletePortalRow FmpScriptStepType = 104
|
||||||
|
FmpScriptOpenPreferences FmpScriptStepType = 105
|
||||||
|
FmpScriptCorrectWord FmpScriptStepType = 106
|
||||||
|
FmpScriptSpellingOptions FmpScriptStepType = 107
|
||||||
|
FmpScriptSelectDictionaries FmpScriptStepType = 108
|
||||||
|
FmpScriptEditUserDictionary FmpScriptStepType = 109
|
||||||
|
FmpScriptOpenUrl FmpScriptStepType = 111
|
||||||
|
FmpScriptOpenManageValueLists FmpScriptStepType = 112
|
||||||
|
FmpScriptOpenSharing FmpScriptStepType = 113
|
||||||
|
FmpScriptOpenFileOptions FmpScriptStepType = 114
|
||||||
|
FmpScriptAllowFormattingBar FmpScriptStepType = 115
|
||||||
|
FmpScriptSetNextSerialValue FmpScriptStepType = 116
|
||||||
|
FmpScriptExecuteSql FmpScriptStepType = 117
|
||||||
|
FmpScriptOpenHosts FmpScriptStepType = 118
|
||||||
|
FmpScriptMoveResizeWindow FmpScriptStepType = 119
|
||||||
|
FmpScriptArrangeAllWindows FmpScriptStepType = 120
|
||||||
|
FmpScriptCloseWindow FmpScriptStepType = 121
|
||||||
|
FmpScriptNewWindow FmpScriptStepType = 122
|
||||||
|
FmpScriptSelectWindow FmpScriptStepType = 123
|
||||||
|
FmpScriptSetWindowTitle FmpScriptStepType = 124
|
||||||
|
FmpScriptElseIf FmpScriptStepType = 125
|
||||||
|
FmpScriptConstrainFoundSet FmpScriptStepType = 126
|
||||||
|
FmpScriptExtendFoundSet FmpScriptStepType = 127
|
||||||
|
FmpScriptPerformFindReplace FmpScriptStepType = 128
|
||||||
|
FmpScriptOpenFindReplace FmpScriptStepType = 129
|
||||||
|
FmpScriptSetSelection FmpScriptStepType = 130
|
||||||
|
FmpScriptInsertFile FmpScriptStepType = 131
|
||||||
|
FmpScriptExportFieldContents FmpScriptStepType = 132
|
||||||
|
FmpScriptOpenRecordRequest FmpScriptStepType = 133
|
||||||
|
FmpScriptAddAccount FmpScriptStepType = 134
|
||||||
|
FmpScriptDeleteAccount FmpScriptStepType = 135
|
||||||
|
FmpScriptResetAccountPassword FmpScriptStepType = 136
|
||||||
|
FmpScriptEnableAccount FmpScriptStepType = 137
|
||||||
|
FmpScriptRelogin FmpScriptStepType = 138
|
||||||
|
FmpScriptConvertFile FmpScriptStepType = 139
|
||||||
|
FmpScriptOpenManageDataSources FmpScriptStepType = 140
|
||||||
|
FmpScriptSetVariable FmpScriptStepType = 141
|
||||||
|
FmpScriptInstallMenuSet FmpScriptStepType = 142
|
||||||
|
FmpScriptSaveRecordsAsExcel FmpScriptStepType = 143
|
||||||
|
FmpScriptSaveRecordsAsPdf FmpScriptStepType = 144
|
||||||
|
FmpScriptGoToObject FmpScriptStepType = 145
|
||||||
|
FmpScriptSetWebViewer FmpScriptStepType = 146
|
||||||
|
FmpScriptSetFieldByName FmpScriptStepType = 147
|
||||||
|
FmpScriptInstallOntimerScript FmpScriptStepType = 148
|
||||||
|
FmpScriptOpenEditSavedFinds FmpScriptStepType = 149
|
||||||
|
FmpScriptPerformQuickFind FmpScriptStepType = 150
|
||||||
|
FmpScriptOpenManageLayouts FmpScriptStepType = 151
|
||||||
|
FmpScriptSaveRecordsAsSnapshotLink FmpScriptStepType = 152
|
||||||
|
FmpScriptSortRecordsByField FmpScriptStepType = 154
|
||||||
|
FmpScriptFindMatchingRecords FmpScriptStepType = 155
|
||||||
|
FmpScriptManageContainers FmpScriptStepType = 156
|
||||||
|
FmpScriptInstallPluginFile FmpScriptStepType = 157
|
||||||
|
FmpScriptInsertPdf FmpScriptStepType = 158
|
||||||
|
FmpScriptInsertAudioVideo FmpScriptStepType = 159
|
||||||
|
FmpScriptInsertFromUrl FmpScriptStepType = 160
|
||||||
|
FmpScriptInsertFromDevice FmpScriptStepType = 161
|
||||||
|
FmpScriptPerformScriptOnServer FmpScriptStepType = 164
|
||||||
|
FmpScriptOpenManageThemes FmpScriptStepType = 165
|
||||||
|
FmpScriptShowHideMenubar FmpScriptStepType = 166
|
||||||
|
FmpScriptRefreshObject FmpScriptStepType = 167
|
||||||
|
FmpScriptSetLayoutObjectAnimation FmpScriptStepType = 168
|
||||||
|
FmpScriptClosePopover FmpScriptStepType = 169
|
||||||
|
FmpScriptOpenUploadToHost FmpScriptStepType = 172
|
||||||
|
FmpScriptEnableTouchKeyboard FmpScriptStepType = 174
|
||||||
|
FmpScriptPerformJavascriptInWebViewer FmpScriptStepType = 175
|
||||||
|
FmpScriptCommentedOut FmpScriptStepType = 176
|
||||||
|
FmpScriptAvplayerPlay FmpScriptStepType = 177
|
||||||
|
FmpScriptAvplayerSetPlaybackState FmpScriptStepType = 178
|
||||||
|
FmpScriptAvplayerSetOptions FmpScriptStepType = 179
|
||||||
|
FmpScriptRefreshPortal FmpScriptStepType = 180
|
||||||
|
FmpScriptGetFolderPath FmpScriptStepType = 181
|
||||||
|
FmpScriptTruncateTable FmpScriptStepType = 182
|
||||||
|
FmpScriptOpenFavorites FmpScriptStepType = 183
|
||||||
|
FmpScriptConfigureRegionMonitorScript FmpScriptStepType = 185
|
||||||
|
FmpScriptConfigureLocalNotification FmpScriptStepType = 187
|
||||||
|
FmpScriptGetFileExists FmpScriptStepType = 188
|
||||||
|
FmpScriptGetFileSize FmpScriptStepType = 189
|
||||||
|
FmpScriptCreateDataFile FmpScriptStepType = 190
|
||||||
|
FmpScriptOpenDataFile FmpScriptStepType = 191
|
||||||
|
FmpScriptWriteToDataFile FmpScriptStepType = 192
|
||||||
|
FmpScriptReadFromDataFile FmpScriptStepType = 193
|
||||||
|
FmpScriptGetDataFilePosition FmpScriptStepType = 194
|
||||||
|
FmpScriptSetDataFilePosition FmpScriptStepType = 195
|
||||||
|
FmpScriptCloseDataFile FmpScriptStepType = 196
|
||||||
|
FmpScriptDeleteFile FmpScriptStepType = 197
|
||||||
|
FmpScriptRenameFile FmpScriptStepType = 199
|
||||||
|
FmpScriptSetErrorLogging FmpScriptStepType = 200
|
||||||
|
FmpScriptConfigureNfcReading FmpScriptStepType = 201
|
||||||
|
FmpScriptConfigureMachineLearningModel FmpScriptStepType = 202
|
||||||
|
FmpScriptExecuteFilemakerDataApi FmpScriptStepType = 203
|
||||||
|
FmpScriptOpenTransaction FmpScriptStepType = 205
|
||||||
|
FmpScriptCommitTransaction FmpScriptStepType = 206
|
||||||
|
FmpScriptRevertTransaction FmpScriptStepType = 207
|
||||||
|
FmpScriptSetSessionIdentifier FmpScriptStepType = 208
|
||||||
|
FmpScriptSetDictionary FmpScriptStepType = 209
|
||||||
|
FmpScriptPerformScriptOnServerWithCallback FmpScriptStepType = 210
|
||||||
|
FmpScriptTriggerClarisConnectFlow FmpScriptStepType = 211
|
||||||
|
FmpScriptAssert FmpScriptStepType = 255
|
||||||
)
|
)
|
||||||
|
@ -9,6 +9,20 @@ func debug(str string, args ...interface{}) {
|
|||||||
// fmt.Printf(str+"\n", args...)
|
// fmt.Printf(str+"\n", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dump(data []byte) {
|
||||||
|
for _, b := range data {
|
||||||
|
fmt.Printf("%02x ", b)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpPath(path []uint64) {
|
||||||
|
for _, p := range path {
|
||||||
|
fmt.Printf("%v. ", p)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FmpFile) ToDebugFile(fname string) {
|
func (f *FmpFile) ToDebugFile(fname string) {
|
||||||
f_sectors, err := os.Create(fname + ".sectors")
|
f_sectors, err := os.Create(fname + ".sectors")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -20,6 +20,20 @@ const (
|
|||||||
hbamSize = len(hbamSequence)
|
hbamSize = len(hbamSequence)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FmpFile struct {
|
||||||
|
VersionDate time.Time
|
||||||
|
CreatorName string
|
||||||
|
FileSize uint
|
||||||
|
Sectors []*FmpSector
|
||||||
|
Chunks []*FmpChunk
|
||||||
|
Dictionary *FmpDict
|
||||||
|
|
||||||
|
numSectors uint64 // Excludes the header sector
|
||||||
|
currentSectorID uint64
|
||||||
|
|
||||||
|
stream io.ReadSeeker
|
||||||
|
}
|
||||||
|
|
||||||
func OpenFile(path string) (*FmpFile, error) {
|
func OpenFile(path string) (*FmpFile, error) {
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
import (
|
type FmpSector struct {
|
||||||
"encoding/hex"
|
ID uint64
|
||||||
"fmt"
|
Level uint8
|
||||||
"io"
|
Deleted bool
|
||||||
)
|
PrevID uint64
|
||||||
|
NextID uint64
|
||||||
|
Prev *FmpSector
|
||||||
|
Next *FmpSector
|
||||||
|
Payload []byte
|
||||||
|
Chunks []*FmpChunk
|
||||||
|
}
|
||||||
|
|
||||||
|
type FmpChunk struct {
|
||||||
|
Type FmpChunkType
|
||||||
|
Length uint64
|
||||||
|
Key uint64 // If Type == FMP_CHUNK_SHORT_KEY_VALUE or FMP_CHUNK_LONG_KEY_VALUE
|
||||||
|
Index uint64 // Segment index, if Type == FMP_CHUNK_SEGMENTED_DATA
|
||||||
|
Value []byte
|
||||||
|
}
|
||||||
|
|
||||||
func (sect *FmpSector) readChunks() error {
|
func (sect *FmpSector) readChunks() error {
|
||||||
if len(sect.Chunks) > 0 {
|
if len(sect.Chunks) > 0 {
|
||||||
@ -24,12 +38,9 @@ func (sect *FmpSector) readChunks() error {
|
|||||||
debug("0x%02x (pos %v, type %v)\n", sect.Payload[0], pos, int(chunk.Type))
|
debug("0x%02x (pos %v, type %v)\n", sect.Payload[0], pos, int(chunk.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug("chunk error at sector %d", sect.ID)
|
debug("chunk error at sector %d", sect.ID)
|
||||||
debug(hex.EncodeToString(sect.Payload))
|
dump(sect.Payload)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
@ -58,43 +69,38 @@ func (sect *FmpSector) processChunks(dict *FmpDict) error {
|
|||||||
currentPath := make([]uint64, 0)
|
currentPath := make([]uint64, 0)
|
||||||
for _, chunk := range sect.Chunks {
|
for _, chunk := range sect.Chunks {
|
||||||
switch chunk.Type {
|
switch chunk.Type {
|
||||||
case FMP_CHUNK_PATH_PUSH, FMP_CHUNK_PATH_PUSH_LONG:
|
case FmpChunkPathPush, FmpChunkPathPushLong:
|
||||||
currentPath = append(currentPath, parseVarUint64(chunk.Value))
|
currentPath = append(currentPath, parseVarUint64(chunk.Value))
|
||||||
|
dumpPath(currentPath)
|
||||||
|
|
||||||
s := ""
|
case FmpChunkPathPop:
|
||||||
for _, ent := range currentPath {
|
|
||||||
s += fmt.Sprintf("%v. ", ent)
|
|
||||||
}
|
|
||||||
debug("path: %s", s)
|
|
||||||
|
|
||||||
case FMP_CHUNK_PATH_POP:
|
|
||||||
if len(currentPath) > 0 {
|
if len(currentPath) > 0 {
|
||||||
currentPath = (currentPath)[:len(currentPath)-1]
|
currentPath = (currentPath)[:len(currentPath)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
case FMP_CHUNK_SIMPLE_DATA:
|
case FmpChunkSimpleData:
|
||||||
dict.SetValue(currentPath, chunk.Value)
|
dict.SetValue(currentPath, chunk.Value)
|
||||||
|
|
||||||
case FMP_CHUNK_SEGMENTED_DATA:
|
case FmpChunkSegmentedData:
|
||||||
// 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 FMP_CHUNK_SIMPLE_KEY_VALUE:
|
case FmpChunkSimpleKeyValue:
|
||||||
dict.SetValue(
|
dict.SetValue(
|
||||||
append(currentPath, uint64(chunk.Key)),
|
append(currentPath, uint64(chunk.Key)),
|
||||||
chunk.Value,
|
chunk.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
case FMP_CHUNK_LONG_KEY_VALUE:
|
case FmpChunkLongKeyValue:
|
||||||
dict.SetValue(
|
dict.SetValue(
|
||||||
append(currentPath, uint64(chunk.Key)), // todo: ??
|
append(currentPath, uint64(chunk.Key)), // todo: ??
|
||||||
chunk.Value,
|
chunk.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
case FMP_CHUNK_NOOP:
|
case FmpChunkNoop:
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,55 +118,55 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
switch chunkCode {
|
switch chunkCode {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
chunk.Length = 2
|
chunk.Length = 2
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x01, 0x02, 0x03, 0x04, 0x05:
|
case 0x01, 0x02, 0x03, 0x04, 0x05:
|
||||||
chunk.Length = 2 + 2*uint64(chunkCode-0x01) + addIf(chunkCode == 0x01, 1)
|
chunk.Length = 2 + 2*uint64(chunkCode-0x01) + addIf(chunkCode == 0x01, 1)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FmpChunkSimpleKeyValue
|
||||||
chunk.Key = uint64(payload[1])
|
chunk.Key = uint64(payload[1])
|
||||||
chunk.Value = payload[2:chunk.Length]
|
chunk.Value = payload[2:chunk.Length]
|
||||||
|
|
||||||
case 0x06:
|
case 0x06:
|
||||||
chunk.Length = 3 + uint64(payload[2])
|
chunk.Length = 3 + uint64(payload[2])
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FmpChunkSimpleKeyValue
|
||||||
chunk.Key = uint64(payload[1])
|
chunk.Key = uint64(payload[1])
|
||||||
chunk.Value = payload[3:chunk.Length]
|
chunk.Value = payload[3:chunk.Length]
|
||||||
|
|
||||||
case 0x07:
|
case 0x07:
|
||||||
valueLength := parseVarUint64(payload[2 : 2+2])
|
valueLength := parseVarUint64(payload[2 : 2+2])
|
||||||
chunk.Length = min(4+valueLength, uint64(len(payload)))
|
chunk.Length = min(4+valueLength, uint64(len(payload)))
|
||||||
chunk.Type = FMP_CHUNK_SEGMENTED_DATA
|
chunk.Type = FmpChunkSegmentedData
|
||||||
chunk.Index = uint64(payload[1])
|
chunk.Index = uint64(payload[1])
|
||||||
chunk.Value = payload[4:chunk.Length]
|
chunk.Value = payload[4:chunk.Length]
|
||||||
|
|
||||||
case 0x08:
|
case 0x08:
|
||||||
chunk.Length = 3
|
chunk.Length = 3
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x09:
|
case 0x09:
|
||||||
chunk.Length = 4
|
chunk.Length = 4
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FmpChunkSimpleKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
||||||
chunk.Value = payload[3:chunk.Length]
|
chunk.Value = payload[3:chunk.Length]
|
||||||
|
|
||||||
case 0x0A, 0x0B, 0x0C, 0x0D:
|
case 0x0A, 0x0B, 0x0C, 0x0D:
|
||||||
chunk.Length = 3 + 2*uint64(chunkCode-0x09)
|
chunk.Length = 3 + 2*uint64(chunkCode-0x09)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FmpChunkSimpleKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
||||||
chunk.Value = payload[3:chunk.Length]
|
chunk.Value = payload[3:chunk.Length]
|
||||||
|
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
if payload[1] == 0xFF {
|
if payload[1] == 0xFF {
|
||||||
chunk.Length = 7
|
chunk.Length = 7
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[2:chunk.Length]
|
chunk.Value = payload[2:chunk.Length]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.Length = 4 + uint64(payload[3])
|
chunk.Length = 4 + uint64(payload[3])
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FmpChunkSimpleKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
||||||
chunk.Value = payload[4:chunk.Length]
|
chunk.Value = payload[4:chunk.Length]
|
||||||
|
|
||||||
@ -170,43 +176,43 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
if chunk.Length > 5+valueLength {
|
if chunk.Length > 5+valueLength {
|
||||||
return nil, ErrBadChunk
|
return nil, ErrBadChunk
|
||||||
}
|
}
|
||||||
chunk.Type = FMP_CHUNK_SEGMENTED_DATA
|
chunk.Type = FmpChunkSegmentedData
|
||||||
chunk.Index = parseVarUint64(payload[1 : 1+2])
|
chunk.Index = parseVarUint64(payload[1 : 1+2])
|
||||||
chunk.Value = payload[5:chunk.Length]
|
chunk.Value = payload[5:chunk.Length]
|
||||||
|
|
||||||
case 0x10, 0x11:
|
case 0x10, 0x11:
|
||||||
chunk.Length = 4 + addIf(chunkCode == 0x11, 1)
|
chunk.Length = 4 + addIf(chunkCode == 0x11, 1)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x12, 0x13, 0x14, 0x15:
|
case 0x12, 0x13, 0x14, 0x15:
|
||||||
chunk.Length = 4 + 2*(uint64(chunkCode)-0x11)
|
chunk.Length = 4 + 2*(uint64(chunkCode)-0x11)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x16:
|
case 0x16:
|
||||||
chunk.Length = 5 + uint64(payload[4])
|
chunk.Length = 5 + uint64(payload[4])
|
||||||
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
chunk.Type = FmpChunkLongKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[1 : 1+3])
|
chunk.Key = parseVarUint64(payload[1 : 1+3])
|
||||||
chunk.Value = payload[5:chunk.Length]
|
chunk.Value = payload[5:chunk.Length]
|
||||||
|
|
||||||
case 0x17:
|
case 0x17:
|
||||||
chunk.Length = 6 + parseVarUint64(payload[4:4+2])
|
chunk.Length = 6 + parseVarUint64(payload[4:4+2])
|
||||||
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
chunk.Type = FmpChunkLongKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[1 : 1+3])
|
chunk.Key = parseVarUint64(payload[1 : 1+3])
|
||||||
chunk.Value = payload[6:chunk.Length]
|
chunk.Value = payload[6:chunk.Length]
|
||||||
|
|
||||||
case 0x19, 0x1A, 0x1B, 0x1C, 0x1D:
|
case 0x19, 0x1A, 0x1B, 0x1C, 0x1D:
|
||||||
valueLength := uint64(payload[1])
|
valueLength := uint64(payload[1])
|
||||||
chunk.Length = 2 + valueLength + 2*uint64(chunkCode-0x19) + addIf(chunkCode == 0x19, 1)
|
chunk.Length = 2 + valueLength + 2*uint64(chunkCode-0x19) + addIf(chunkCode == 0x19, 1)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[2 : 2+valueLength]
|
chunk.Value = payload[2 : 2+valueLength]
|
||||||
|
|
||||||
case 0x1E:
|
case 0x1E:
|
||||||
keyLength := uint64(payload[1])
|
keyLength := uint64(payload[1])
|
||||||
valueLength := uint64(payload[2+keyLength])
|
valueLength := uint64(payload[2+keyLength])
|
||||||
chunk.Length = 2 + keyLength + 1 + valueLength
|
chunk.Length = 2 + keyLength + 1 + valueLength
|
||||||
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
chunk.Type = FmpChunkLongKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[2 : 2+keyLength])
|
chunk.Key = parseVarUint64(payload[2 : 2+keyLength])
|
||||||
chunk.Value = payload[2+keyLength+1 : chunk.Length]
|
chunk.Value = payload[2+keyLength+1 : chunk.Length]
|
||||||
|
|
||||||
@ -214,44 +220,44 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
keyLength := uint64(payload[1])
|
keyLength := uint64(payload[1])
|
||||||
valueLength := parseVarUint64(payload[2+keyLength : 2+keyLength+2+1])
|
valueLength := parseVarUint64(payload[2+keyLength : 2+keyLength+2+1])
|
||||||
chunk.Length = 2 + keyLength + 2 + valueLength
|
chunk.Length = 2 + keyLength + 2 + valueLength
|
||||||
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
chunk.Type = FmpChunkLongKeyValue
|
||||||
chunk.Key = parseVarUint64(payload[2 : 2+keyLength])
|
chunk.Key = parseVarUint64(payload[2 : 2+keyLength])
|
||||||
chunk.Value = payload[2+keyLength+2 : chunk.Length]
|
chunk.Value = payload[2+keyLength+2 : chunk.Length]
|
||||||
|
|
||||||
case 0x20, 0xE0:
|
case 0x20, 0xE0:
|
||||||
if payload[1] == 0xFE {
|
if payload[1] == 0xFE {
|
||||||
chunk.Length = 10
|
chunk.Length = 10
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH
|
chunk.Type = FmpChunkPathPush
|
||||||
chunk.Value = payload[2:chunk.Length]
|
chunk.Value = payload[2:chunk.Length]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.Length = 2
|
chunk.Length = 2
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH
|
chunk.Type = FmpChunkPathPush
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x23:
|
case 0x23:
|
||||||
chunk.Length = 2 + uint64(payload[1])
|
chunk.Length = 2 + uint64(payload[1])
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FmpChunkSimpleData
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x28, 0x30:
|
case 0x28, 0x30:
|
||||||
chunk.Length = 3 + addIf(chunkCode == 0x30, 1)
|
chunk.Length = 3 + addIf(chunkCode == 0x30, 1)
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH
|
chunk.Type = FmpChunkPathPush
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x38:
|
case 0x38:
|
||||||
valueLength := uint64(payload[1])
|
valueLength := uint64(payload[1])
|
||||||
chunk.Length = 2 + valueLength
|
chunk.Length = 2 + valueLength
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH_LONG
|
chunk.Type = FmpChunkPathPushLong
|
||||||
chunk.Value = payload[2:chunk.Length]
|
chunk.Value = payload[2:chunk.Length]
|
||||||
|
|
||||||
case 0x3D, 0x40:
|
case 0x3D, 0x40:
|
||||||
chunk.Type = FMP_CHUNK_PATH_POP
|
chunk.Type = FmpChunkPathPop
|
||||||
chunk.Length = 1
|
chunk.Length = 1
|
||||||
|
|
||||||
case 0x80:
|
case 0x80:
|
||||||
chunk.Type = FMP_CHUNK_NOOP
|
chunk.Type = FmpChunkNoop
|
||||||
chunk.Length = 1
|
chunk.Length = 1
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -260,10 +266,3 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
|
|
||||||
return chunk, nil
|
return chunk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addIf(cond bool, val uint64) uint64 {
|
|
||||||
if cond {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
|
type FmpTable struct {
|
||||||
|
ID uint64
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
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([]uint64{3, 16, 5})
|
||||||
|
@ -1,22 +1,6 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"slices"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func slicesHaveSameElements[Type comparable](a, b []Type) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, av := range a {
|
|
||||||
found := slices.Contains(b, av)
|
|
||||||
if !found {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpenFile(t *testing.T) {
|
func TestOpenFile(t *testing.T) {
|
||||||
f, err := OpenFile("../files/Untitled.fmp12")
|
f, err := OpenFile("../files/Untitled.fmp12")
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
package fmp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FmpFile struct {
|
|
||||||
VersionDate time.Time
|
|
||||||
CreatorName string
|
|
||||||
FileSize uint
|
|
||||||
Sectors []*FmpSector
|
|
||||||
Chunks []*FmpChunk
|
|
||||||
Dictionary *FmpDict
|
|
||||||
|
|
||||||
numSectors uint64 // Excludes the header sector
|
|
||||||
currentSectorID uint64
|
|
||||||
|
|
||||||
stream io.ReadSeeker
|
|
||||||
}
|
|
||||||
|
|
||||||
type FmpSector struct {
|
|
||||||
ID uint64
|
|
||||||
Level uint8
|
|
||||||
Deleted bool
|
|
||||||
PrevID uint64
|
|
||||||
NextID uint64
|
|
||||||
Prev *FmpSector
|
|
||||||
Next *FmpSector
|
|
||||||
Payload []byte
|
|
||||||
Chunks []*FmpChunk
|
|
||||||
}
|
|
||||||
|
|
||||||
type FmpChunk struct {
|
|
||||||
Type FmpChunkType
|
|
||||||
Length uint64
|
|
||||||
Key uint64 // If Type == FMP_CHUNK_SHORT_KEY_VALUE or FMP_CHUNK_LONG_KEY_VALUE
|
|
||||||
Index uint64 // Segment index, if Type == FMP_CHUNK_SEGMENTED_DATA
|
|
||||||
Value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type FmpDict map[uint64]*FmpDictEntry
|
|
||||||
|
|
||||||
type FmpDictEntry struct {
|
|
||||||
Value []byte
|
|
||||||
Children *FmpDict
|
|
||||||
}
|
|
||||||
|
|
||||||
type FmpTable struct {
|
|
||||||
ID uint64
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dict *FmpDict) GetEntry(path []uint64) *FmpDictEntry {
|
|
||||||
for i, key := range path {
|
|
||||||
_, ok := (*dict)[key]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == len(path)-1 {
|
|
||||||
return (*dict)[key]
|
|
||||||
} else {
|
|
||||||
dict = (*dict)[key].Children
|
|
||||||
if dict == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dict *FmpDict) GetValue(path []uint64) []byte {
|
|
||||||
ent := dict.GetEntry(path)
|
|
||||||
if ent != nil {
|
|
||||||
return ent.Value
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dict *FmpDict) SetValue(path []uint64, value []byte) {
|
|
||||||
for i, key := range path {
|
|
||||||
_, ok := (*dict)[key]
|
|
||||||
if !ok {
|
|
||||||
(*dict)[key] = &FmpDictEntry{Children: &FmpDict{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == len(path)-1 {
|
|
||||||
(*dict)[key].Value = value
|
|
||||||
} else {
|
|
||||||
dict = (*dict)[key].Children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,56 @@
|
|||||||
package fmp
|
package fmp
|
||||||
|
|
||||||
|
import "slices"
|
||||||
|
|
||||||
|
type FmpDict map[uint64]*FmpDictEntry
|
||||||
|
|
||||||
|
type FmpDictEntry struct {
|
||||||
|
Value []byte
|
||||||
|
Children *FmpDict
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dict *FmpDict) GetEntry(path []uint64) *FmpDictEntry {
|
||||||
|
for i, key := range path {
|
||||||
|
_, ok := (*dict)[key]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == len(path)-1 {
|
||||||
|
return (*dict)[key]
|
||||||
|
} else {
|
||||||
|
dict = (*dict)[key].Children
|
||||||
|
if dict == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dict *FmpDict) GetValue(path []uint64) []byte {
|
||||||
|
ent := dict.GetEntry(path)
|
||||||
|
if ent != nil {
|
||||||
|
return ent.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dict *FmpDict) SetValue(path []uint64, value []byte) {
|
||||||
|
for i, key := range path {
|
||||||
|
_, ok := (*dict)[key]
|
||||||
|
if !ok {
|
||||||
|
(*dict)[key] = &FmpDictEntry{Children: &FmpDict{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == len(path)-1 {
|
||||||
|
(*dict)[key].Value = value
|
||||||
|
} else {
|
||||||
|
dict = (*dict)[key].Children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func parseVarUint64(payload []byte) uint64 {
|
func parseVarUint64(payload []byte) uint64 {
|
||||||
var length uint64
|
var length uint64
|
||||||
n := min(len(payload), 8) // clamp to uint64
|
n := min(len(payload), 8) // clamp to uint64
|
||||||
@ -17,3 +68,23 @@ func decodeByteSeq(payload []byte) string {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addIf(cond bool, val uint64) uint64 {
|
||||||
|
if cond {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func slicesHaveSameElements[Type comparable](a, b []Type) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, av := range a {
|
||||||
|
found := slices.Contains(b, av)
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user