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

Dict parsing

This commit is contained in:
2025-06-12 10:43:02 +02:00
parent 8bf5cfeffd
commit 7dc88d96e9
3 changed files with 111 additions and 27 deletions

View File

@ -4,14 +4,6 @@ import (
"encoding/binary"
)
type FmpChunk struct {
Type FmpChunkType
Length uint32
Key uint32 // If Type == FMP_CHUNK_SHORT_KEY_VALUE or FMP_CHUNK_LONG_KEY_VALUE
Index uint32 // Segment index, if Type == FMP_CHUNK_SEGMENTED_DATA
Value []byte
}
func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) {
// Simple data

View File

@ -18,24 +18,6 @@ const (
sectorHeaderSize = 20
)
type FmpFile struct {
VersionDate time.Time
CreatorName string
FileSize uint
NumSectors uint
Stream io.ReadSeeker
Sectors []*FmpSector
Chunks []*FmpChunk
}
type FmpSector struct {
Deleted bool
Level uint8
PrevSectorID uint32
NextSectorID uint32
Chunks []*FmpChunk
}
func OpenFile(path string) (*FmpFile, error) {
info, err := os.Stat(path)
if err != nil {
@ -48,7 +30,7 @@ func OpenFile(path string) (*FmpFile, error) {
}
defer stream.Close()
ctx := &FmpFile{Stream: stream}
ctx := &FmpFile{Stream: stream, Dictionary: &FmpDict{}}
if err := ctx.readHeader(); err != nil {
return nil, err
}
@ -57,6 +39,8 @@ func OpenFile(path string) (*FmpFile, error) {
ctx.NumSectors = ctx.FileSize / sectorSize
ctx.Sectors = make([]*FmpSector, ctx.NumSectors)
currentPath := make([]uint16, 0)
for i := uint(0); i < ctx.NumSectors; i++ {
sector, err := ctx.readSector()
if err == io.EOF {
@ -67,6 +51,43 @@ func OpenFile(path string) (*FmpFile, error) {
}
ctx.Sectors[i] = sector
ctx.Chunks = append(ctx.Chunks, sector.Chunks...)
for _, chunk := range sector.Chunks {
switch chunk.Type {
case FMP_CHUNK_PATH_PUSH:
currentPath = append(currentPath, uint16(chunk.Value[0]))
case FMP_CHUNK_PATH_POP:
if len(currentPath) > 0 {
currentPath = currentPath[:len(currentPath)-1]
}
case FMP_CHUNK_SIMPLE_DATA:
ctx.Dictionary.set(currentPath, chunk.Value)
case FMP_CHUNK_SEGMENTED_DATA:
// Todo: take index into account
ctx.Dictionary.set(
currentPath,
append(ctx.Dictionary.get(currentPath), chunk.Value...),
)
case FMP_CHUNK_SIMPLE_KEY_VALUE:
ctx.Dictionary.set(
append(currentPath, uint16(chunk.Key)),
chunk.Value,
)
case FMP_CHUNK_LONG_KEY_VALUE:
ctx.Dictionary.set(
append(currentPath, uint16(chunk.Key)), // todo: ??
chunk.Value,
)
case FMP_CHUNK_NOOP:
// noop
}
}
}
return ctx, nil

71
fmp/fmp_type.go Normal file
View File

@ -0,0 +1,71 @@
package fmp
import (
"io"
"time"
)
type FmpFile struct {
VersionDate time.Time
CreatorName string
FileSize uint
NumSectors uint
Stream io.ReadSeeker
Sectors []*FmpSector
Chunks []*FmpChunk
Dictionary *FmpDict
}
type FmpSector struct {
Deleted bool
Level uint8
PrevSectorID uint32
NextSectorID uint32
Chunks []*FmpChunk
}
type FmpChunk struct {
Type FmpChunkType
Length uint32
Key uint32 // If Type == FMP_CHUNK_SHORT_KEY_VALUE or FMP_CHUNK_LONG_KEY_VALUE
Index uint32 // Segment index, if Type == FMP_CHUNK_SEGMENTED_DATA
Value []byte
}
type FmpDict map[uint16]*FmpDictEntry
type FmpDictEntry struct {
Value []byte
Children *FmpDict
}
func (dict *FmpDict) get(path []uint16) []byte {
for i, key := range path {
_, ok := (*dict)[key]
if !ok {
(*dict)[key] = &FmpDictEntry{Children: &FmpDict{}}
}
if i == len(path)-1 {
return (*dict)[key].Value
} else {
dict = (*dict)[key].Children
}
}
return nil
}
func (dict *FmpDict) set(path []uint16, 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
}
}
}