mirror of
https://github.com/garraflavatra/go-fmp.git
synced 2025-06-28 12:35:12 +00:00
Dict parsing
This commit is contained in:
@ -4,14 +4,6 @@ import (
|
|||||||
"encoding/binary"
|
"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) {
|
func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) {
|
||||||
|
|
||||||
// Simple data
|
// Simple data
|
||||||
|
@ -18,24 +18,6 @@ const (
|
|||||||
sectorHeaderSize = 20
|
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) {
|
func OpenFile(path string) (*FmpFile, error) {
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -48,7 +30,7 @@ func OpenFile(path string) (*FmpFile, error) {
|
|||||||
}
|
}
|
||||||
defer stream.Close()
|
defer stream.Close()
|
||||||
|
|
||||||
ctx := &FmpFile{Stream: stream}
|
ctx := &FmpFile{Stream: stream, Dictionary: &FmpDict{}}
|
||||||
if err := ctx.readHeader(); err != nil {
|
if err := ctx.readHeader(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -57,6 +39,8 @@ func OpenFile(path string) (*FmpFile, error) {
|
|||||||
ctx.NumSectors = ctx.FileSize / sectorSize
|
ctx.NumSectors = ctx.FileSize / sectorSize
|
||||||
ctx.Sectors = make([]*FmpSector, ctx.NumSectors)
|
ctx.Sectors = make([]*FmpSector, ctx.NumSectors)
|
||||||
|
|
||||||
|
currentPath := make([]uint16, 0)
|
||||||
|
|
||||||
for i := uint(0); i < ctx.NumSectors; i++ {
|
for i := uint(0); i < ctx.NumSectors; i++ {
|
||||||
sector, err := ctx.readSector()
|
sector, err := ctx.readSector()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@ -67,6 +51,43 @@ func OpenFile(path string) (*FmpFile, error) {
|
|||||||
}
|
}
|
||||||
ctx.Sectors[i] = sector
|
ctx.Sectors[i] = sector
|
||||||
ctx.Chunks = append(ctx.Chunks, sector.Chunks...)
|
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
|
return ctx, nil
|
||||||
|
71
fmp/fmp_type.go
Normal file
71
fmp/fmp_type.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user