mirror of
https://github.com/garraflavatra/go-fmp.git
synced 2025-06-28 04:25:11 +00:00
Compare commits
4 Commits
b44c90da30
...
bd871b6457
Author | SHA1 | Date | |
---|---|---|---|
bd871b6457 | |||
b94fa28ba9 | |||
d9ffc3e573 | |||
a7bde87c6f |
27
.github/workflows/ci.yml
vendored
Normal file
27
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '1.20'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./...
|
||||||
|
working-directory: fmp
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: go test -v ./...
|
||||||
|
working-directory: fmp
|
@ -21,6 +21,7 @@ const (
|
|||||||
FMP_CHUNK_SIMPLE_KEY_VALUE
|
FMP_CHUNK_SIMPLE_KEY_VALUE
|
||||||
FMP_CHUNK_LONG_KEY_VALUE
|
FMP_CHUNK_LONG_KEY_VALUE
|
||||||
FMP_CHUNK_PATH_PUSH
|
FMP_CHUNK_PATH_PUSH
|
||||||
|
FMP_CHUNK_PATH_PUSH_LONG
|
||||||
FMP_CHUNK_PATH_POP
|
FMP_CHUNK_PATH_POP
|
||||||
FMP_CHUNK_NOOP
|
FMP_CHUNK_NOOP
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func debug(str string, args ...interface{}) {
|
||||||
|
// fmt.Printf(str+"\n", args...)
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -40,7 +40,6 @@ func OpenFile(path string) (*FmpFile, error) {
|
|||||||
ctx.FileSize = uint(info.Size())
|
ctx.FileSize = uint(info.Size())
|
||||||
ctx.numSectors = uint64((ctx.FileSize / sectorSize) - 1)
|
ctx.numSectors = uint64((ctx.FileSize / sectorSize) - 1)
|
||||||
ctx.Sectors = make([]*FmpSector, 0)
|
ctx.Sectors = make([]*FmpSector, 0)
|
||||||
currentPath := make([]uint64, 0)
|
|
||||||
ctx.stream.Seek(2*sectorSize, io.SeekStart)
|
ctx.stream.Seek(2*sectorSize, io.SeekStart)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -55,7 +54,7 @@ func OpenFile(path string) (*FmpFile, error) {
|
|||||||
ctx.Sectors = append(ctx.Sectors, sector)
|
ctx.Sectors = append(ctx.Sectors, sector)
|
||||||
|
|
||||||
if sector.ID != 0 {
|
if sector.ID != 0 {
|
||||||
err = sector.processChunks(ctx.Dictionary, ¤tPath)
|
err = sector.processChunks(ctx.Dictionary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -100,7 +99,7 @@ func (ctx *FmpFile) readHeader() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *FmpFile) readSector() (*FmpSector, error) {
|
func (ctx *FmpFile) readSector() (*FmpSector, error) {
|
||||||
println("---------- Reading sector", ctx.currentSectorID)
|
debug("---------- Reading sector %d", ctx.currentSectorID)
|
||||||
buf := make([]byte, sectorHeaderSize)
|
buf := make([]byte, sectorHeaderSize)
|
||||||
n, err := ctx.stream.Read(buf)
|
n, err := ctx.stream.Read(buf)
|
||||||
|
|
||||||
|
@ -19,22 +19,20 @@ func (sect *FmpSector) readChunks() error {
|
|||||||
|
|
||||||
chunk, err := sect.readChunk(sect.Payload)
|
chunk, err := sect.readChunk(sect.Payload)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
fmt.Printf("0x%02x (pos %v, unknown)\n", sect.Payload[0], pos)
|
debug("0x%02x (pos %v, unknown)\n", sect.Payload[0], pos)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("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 {
|
if err == io.EOF {
|
||||||
println("break1")
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(hex.EncodeToString(sect.Payload))
|
debug("chunk error at sector %d", sect.ID)
|
||||||
println("break2")
|
debug(hex.EncodeToString(sect.Payload))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
println("break3")
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if chunk.Length == 0 {
|
if chunk.Length == 0 {
|
||||||
@ -51,55 +49,54 @@ func (sect *FmpSector) readChunks() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sect *FmpSector) processChunks(dict *FmpDict, currentPath *[]uint64) error {
|
func (sect *FmpSector) processChunks(dict *FmpDict) error {
|
||||||
err := sect.readChunks()
|
err := sect.readChunks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:
|
case FMP_CHUNK_PATH_PUSH, FMP_CHUNK_PATH_PUSH_LONG:
|
||||||
*currentPath = append(*currentPath, uint64(chunk.Value[0]))
|
currentPath = append(currentPath, parseVarUint64(chunk.Value))
|
||||||
|
|
||||||
|
s := ""
|
||||||
|
for _, ent := range currentPath {
|
||||||
|
s += fmt.Sprintf("%v. ", ent)
|
||||||
|
}
|
||||||
|
debug("path: %s", s)
|
||||||
|
|
||||||
case FMP_CHUNK_PATH_POP:
|
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 FMP_CHUNK_SIMPLE_DATA:
|
||||||
dict.set(*currentPath, chunk.Value)
|
dict.SetValue(currentPath, chunk.Value)
|
||||||
|
|
||||||
case FMP_CHUNK_SEGMENTED_DATA:
|
case FMP_CHUNK_SEGMENTED_DATA:
|
||||||
// Todo: take index into account
|
// Todo: take index into account
|
||||||
dict.set(
|
dict.SetValue(
|
||||||
*currentPath,
|
currentPath,
|
||||||
append(dict.getValue(*currentPath), chunk.Value...),
|
append(dict.GetValue(currentPath), chunk.Value...),
|
||||||
)
|
)
|
||||||
|
|
||||||
case FMP_CHUNK_SIMPLE_KEY_VALUE:
|
case FMP_CHUNK_SIMPLE_KEY_VALUE:
|
||||||
dict.set(
|
dict.SetValue(
|
||||||
append(*currentPath, uint64(chunk.Key)),
|
append(currentPath, uint64(chunk.Key)),
|
||||||
chunk.Value,
|
chunk.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
case FMP_CHUNK_LONG_KEY_VALUE:
|
case FMP_CHUNK_LONG_KEY_VALUE:
|
||||||
dict.set(
|
dict.SetValue(
|
||||||
append(*currentPath, uint64(chunk.Key)), // todo: ??
|
append(currentPath, uint64(chunk.Key)), // todo: ??
|
||||||
chunk.Value,
|
chunk.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
case FMP_CHUNK_NOOP:
|
case FMP_CHUNK_NOOP:
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunk.Delayed {
|
|
||||||
if len(*currentPath) == 0 {
|
|
||||||
println("warning: delayed pop without path")
|
|
||||||
} else {
|
|
||||||
*currentPath = (*currentPath)[:len(*currentPath)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -112,33 +109,20 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
chunk := &FmpChunk{}
|
chunk := &FmpChunk{}
|
||||||
chunkCode := payload[0]
|
chunkCode := payload[0]
|
||||||
|
|
||||||
if (chunkCode & 0xC0) == 0xC0 {
|
|
||||||
chunkCode &= 0x3F
|
|
||||||
chunk.Delayed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch chunkCode {
|
switch chunkCode {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
chunk.Length = 2
|
chunk.Length = 2
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x01:
|
case 0x01, 0x02, 0x03, 0x04, 0x05:
|
||||||
chunk.Length = 3
|
chunk.Length = 2 + 2*uint64(chunkCode-0x01) + addIf(chunkCode == 0x01, 1)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
||||||
chunk.Key = uint64(payload[1])
|
|
||||||
chunk.Value = payload[2:chunk.Length]
|
|
||||||
|
|
||||||
case 0x02, 0x03, 0x04, 0x05:
|
|
||||||
valueLength := uint64(2 * (chunkCode - 1))
|
|
||||||
chunk.Length = 2 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
||||||
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:
|
||||||
valueLength := uint64(payload[2])
|
chunk.Length = 3 + uint64(payload[2])
|
||||||
chunk.Length = 3 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
||||||
chunk.Key = uint64(payload[1])
|
chunk.Key = uint64(payload[1])
|
||||||
chunk.Value = payload[3:chunk.Length]
|
chunk.Value = payload[3:chunk.Length]
|
||||||
@ -162,20 +146,12 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
chunk.Value = payload[3:chunk.Length]
|
chunk.Value = payload[3:chunk.Length]
|
||||||
|
|
||||||
case 0x0A, 0x0B, 0x0C, 0x0D:
|
case 0x0A, 0x0B, 0x0C, 0x0D:
|
||||||
valueLength := uint64(2 * (chunkCode - 0x09))
|
chunk.Length = 3 + 2*uint64(chunkCode-0x09)
|
||||||
chunk.Length = 3 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
||||||
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] == 0xFE {
|
|
||||||
chunk.Length = 10
|
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
||||||
chunk.Value = payload[2:chunk.Length]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if payload[1] == 0xFF {
|
if payload[1] == 0xFF {
|
||||||
chunk.Length = 7
|
chunk.Length = 7
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
||||||
@ -183,55 +159,48 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
valueLength := uint64(payload[2])
|
chunk.Length = 4 + uint64(payload[3])
|
||||||
chunk.Length = 4 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
||||||
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]
|
||||||
|
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
valueLength := parseVarUint64(payload[3 : 3+2])
|
valueLength := parseVarUint64(payload[3 : 3+2])
|
||||||
chunk.Length = min(5+valueLength, uint64(len(payload)))
|
chunk.Length = uint64(len(payload))
|
||||||
|
if chunk.Length > 5+valueLength {
|
||||||
|
return nil, ErrBadChunk
|
||||||
|
}
|
||||||
chunk.Type = FMP_CHUNK_SEGMENTED_DATA
|
chunk.Type = FMP_CHUNK_SEGMENTED_DATA
|
||||||
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:
|
||||||
valueLength := 3 + (uint64(chunkCode) - 0x10)
|
chunk.Length = 4 + addIf(chunkCode == 0x11, 1)
|
||||||
chunk.Length = 1 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x12, 0x13, 0x14, 0x15:
|
case 0x12, 0x13, 0x14, 0x15:
|
||||||
valueLength := 1 + 2*(uint64(chunkCode)-0x10)
|
chunk.Length = 4 + 2*(uint64(chunkCode)-0x11)
|
||||||
chunk.Length = 1 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x16:
|
case 0x16:
|
||||||
valueLength := uint64(payload[4])
|
chunk.Length = 5 + uint64(payload[4])
|
||||||
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
||||||
chunk.Length = 5 + valueLength
|
|
||||||
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:
|
||||||
valueLength := parseVarUint64(payload[4 : 4+2])
|
chunk.Length = 6 + parseVarUint64(payload[4:4+2])
|
||||||
chunk.Length = 6 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
||||||
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:
|
case 0x19, 0x1A, 0x1B, 0x1C, 0x1D:
|
||||||
|
valueLength := uint64(payload[1])
|
||||||
|
chunk.Length = 2 + valueLength + 2*uint64(chunkCode-0x19) + addIf(chunkCode == 0x19, 1)
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
||||||
chunk.Length = 2
|
chunk.Value = payload[2 : 2+valueLength]
|
||||||
chunk.Value = payload[1:chunk.Length]
|
|
||||||
|
|
||||||
case 0x1A, 0x1B, 0x1C, 0x1D:
|
|
||||||
valueLength := 2 * uint64(chunkCode-0x19)
|
|
||||||
chunk.Length = 1 + valueLength
|
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
||||||
chunk.Value = payload[1:chunk.Length]
|
|
||||||
|
|
||||||
case 0x1E:
|
case 0x1E:
|
||||||
keyLength := uint64(payload[1])
|
keyLength := uint64(payload[1])
|
||||||
@ -242,18 +211,18 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
chunk.Value = payload[2+keyLength+1 : chunk.Length]
|
chunk.Value = payload[2+keyLength+1 : chunk.Length]
|
||||||
|
|
||||||
case 0x1F:
|
case 0x1F:
|
||||||
keyLength := uint64(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 = FMP_CHUNK_LONG_KEY_VALUE
|
||||||
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:
|
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 = FMP_CHUNK_PATH_PUSH
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[2:chunk.Length]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,24 +231,19 @@ func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) {
|
|||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x23:
|
case 0x23:
|
||||||
chunk.Length = 2
|
chunk.Length = 2 + uint64(payload[1])
|
||||||
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
||||||
chunk.Value = payload[1:chunk.Length]
|
chunk.Value = payload[1:chunk.Length]
|
||||||
|
|
||||||
case 0x28:
|
case 0x28, 0x30:
|
||||||
chunk.Length = 3
|
chunk.Length = 3 + addIf(chunkCode == 0x30, 1)
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
||||||
chunk.Value = payload[1:chunk.Length]
|
|
||||||
|
|
||||||
case 0x30:
|
|
||||||
chunk.Length = 4
|
|
||||||
chunk.Type = FMP_CHUNK_PATH_PUSH
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
||||||
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
|
chunk.Type = FMP_CHUNK_PATH_PUSH_LONG
|
||||||
chunk.Value = payload[2:chunk.Length]
|
chunk.Value = payload[2:chunk.Length]
|
||||||
|
|
||||||
case 0x3D, 0x40:
|
case 0x3D, 0x40:
|
||||||
@ -296,3 +260,10 @@ 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
|
||||||
|
}
|
||||||
|
@ -2,46 +2,16 @@ package fmp
|
|||||||
|
|
||||||
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})
|
||||||
|
|
||||||
for key, ent := range *ctx.Dictionary {
|
for path, tableEnt := range *ent.Children {
|
||||||
if key != 3 {
|
if path < 128 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
println("Found a 3")
|
name := decodeByteSeq(tableEnt.Children.GetValue([]uint64{16}))
|
||||||
|
table := &FmpTable{ID: path, Name: name}
|
||||||
for key, ent = range *ent.Children {
|
tables = append(tables, table)
|
||||||
if key != 16 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
println("Found a 3.16")
|
|
||||||
|
|
||||||
for key, ent = range *ent.Children {
|
|
||||||
if key != 5 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
println("Found a 3.16.5")
|
|
||||||
|
|
||||||
for tablePath := range *ent.Children {
|
|
||||||
if key >= 128 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found a table!
|
|
||||||
println("Found a table at 3.16.5.", tablePath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// metaDict := ctx.Dictionary.get([]uint64{4, 1, 7})
|
|
||||||
// if metaDict == nil {
|
|
||||||
// return tables
|
|
||||||
// }
|
|
||||||
// for _, meta := range *metaDict.Children {
|
|
||||||
// name := decodeByteSeq(meta.Children.get([]uint64{16}).Value)
|
|
||||||
// table := &FmpTable{Name: name}
|
|
||||||
// tables = append(tables, table)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return tables
|
return tables
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func TestTables(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tables := f.Tables()
|
tables := f.Tables()
|
||||||
|
|
||||||
if len(tables) != 1 || tables[0].Name != "Untitled" {
|
expected := "Untitled, WayDomains, WayProcesses"
|
||||||
tablesString := ""
|
tablesString := ""
|
||||||
for i, table := range tables {
|
for i, table := range tables {
|
||||||
tablesString += table.Name
|
tablesString += table.Name
|
||||||
@ -37,6 +37,8 @@ func TestTables(t *testing.T) {
|
|||||||
tablesString += ", "
|
tablesString += ", "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Errorf("expected tables to be 'Untitled', got '%s'", tablesString)
|
|
||||||
|
if tablesString != expected {
|
||||||
|
t.Errorf("expected tables to be '%s', got '%s'", expected, tablesString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ type FmpChunk struct {
|
|||||||
Key uint64 // If Type == FMP_CHUNK_SHORT_KEY_VALUE or FMP_CHUNK_LONG_KEY_VALUE
|
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
|
Index uint64 // Segment index, if Type == FMP_CHUNK_SEGMENTED_DATA
|
||||||
Value []byte
|
Value []byte
|
||||||
Delayed bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FmpDict map[uint64]*FmpDictEntry
|
type FmpDict map[uint64]*FmpDictEntry
|
||||||
@ -48,10 +47,11 @@ type FmpDictEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FmpTable struct {
|
type FmpTable struct {
|
||||||
|
ID uint64
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *FmpDict) get(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 {
|
||||||
@ -62,20 +62,23 @@ func (dict *FmpDict) get(path []uint64) *FmpDictEntry {
|
|||||||
return (*dict)[key]
|
return (*dict)[key]
|
||||||
} else {
|
} else {
|
||||||
dict = (*dict)[key].Children
|
dict = (*dict)[key].Children
|
||||||
|
if dict == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *FmpDict) getValue(path []uint64) []byte {
|
func (dict *FmpDict) GetValue(path []uint64) []byte {
|
||||||
ent := dict.get(path)
|
ent := dict.GetEntry(path)
|
||||||
if ent != nil {
|
if ent != nil {
|
||||||
return ent.Value
|
return ent.Value
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *FmpDict) set(path []uint64, value []byte) {
|
func (dict *FmpDict) SetValue(path []uint64, value []byte) {
|
||||||
for i, key := range path {
|
for i, key := range path {
|
||||||
_, ok := (*dict)[key]
|
_, ok := (*dict)[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
Reference in New Issue
Block a user