diff --git a/fmp/fmp_chunk.go b/fmp/fmp_chunk.go index eb19ba5..f9d9f03 100644 --- a/fmp/fmp_chunk.go +++ b/fmp/fmp_chunk.go @@ -26,27 +26,27 @@ func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { }, nil } if 0x10 <= payload[0] && payload[0] <= 0x11 { - length := 3 + (payload[0] - 0x10) + valueLength := 3 + (payload[0] - 0x10) return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_DATA, - Value: payload[1 : 1+length], - Length: 1 + uint64(length), + Value: payload[1 : 1+valueLength], + Length: 1 + uint64(valueLength), }, nil } if 0x12 <= payload[0] && payload[0] <= 0x15 { - length := 1 + 2*(payload[0]-0x10) + valueLength := 1 + 2*(payload[0]-0x10) return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_DATA, - Value: payload[1 : 1+length], - Length: 1 + uint64(length), + Value: payload[1 : 1+valueLength], + Length: 1 + uint64(valueLength), }, nil } if 0x1A <= payload[0] && payload[0] <= 0x1D { - length := 2 * (payload[0] - 0x19) + valueLength := 2 * (payload[0] - 0x19) return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_DATA, - Value: payload[1 : 1+length], - Length: 1 + uint64(length), + Value: payload[1 : 1+valueLength], + Length: 1 + uint64(valueLength), }, nil } @@ -61,68 +61,68 @@ func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { }, nil } if 0x02 <= payload[0] && payload[0] <= 0x05 { - length := 2 * (payload[0] - 1) + valueLength := 2 * (payload[0] - 1) return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_KEY_VALUE, Key: uint64(payload[1]), - Value: payload[2 : 2+length], - Length: 2 + uint64(length), + Value: payload[2 : 2+valueLength], + Length: 2 + uint64(valueLength), }, nil } if payload[0] == 0x06 { - length := payload[2] + valueLength := payload[2] return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_KEY_VALUE, Key: uint64(payload[1]), - Value: payload[3 : 3+length], // docs say offset 2? - Length: 3 + uint64(length), + Value: payload[2 : 2+valueLength], // docs say offset 2? + Length: 3 + uint64(valueLength), }, nil } if payload[0] == 0x09 { return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_KEY_VALUE, - Key: parseVarUint64(payload[1:3]), - Value: payload[3 : 3+1], // docs say offset 2? + Key: parseVarUint64(payload[1 : 1+2]), + Value: payload[3 : 3+1], Length: 4, }, nil } if 0x0A <= payload[0] && payload[0] <= 0x0D { - length := 2 * (payload[0] - 9) + valueLength := 2 * (payload[0] - 0x09) return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_KEY_VALUE, - Key: parseVarUint64(payload[1:3]), - Value: payload[3 : 3+length], // docs say offset 2? - Length: 2 + uint64(length), + Key: parseVarUint64(payload[1 : 1+2]), + Value: payload[3 : 3+valueLength], + Length: 2 + uint64(valueLength), }, nil } if payload[0] == 0x0E { - length := payload[2] + valueLength := payload[2] return &FmpChunk{ Type: FMP_CHUNK_SIMPLE_KEY_VALUE, - Key: parseVarUint64(payload[1:3]), - Value: payload[4 : 4+length], // docs say offset 2? - Length: 4 + uint64(length), + Key: parseVarUint64(payload[1 : 1+2]), + Value: payload[4 : 4+valueLength], + Length: 4 + uint64(valueLength), }, nil } // Long key-value if payload[0] == 0x16 { - length := payload[4] + valueLength := payload[4] return &FmpChunk{ Type: FMP_CHUNK_LONG_KEY_VALUE, Key: parseVarUint64(payload[1 : 1+3]), - Value: payload[5 : 5+length], - Length: 5 + uint64(length), + Value: payload[5 : 5+valueLength], + Length: 5 + uint64(valueLength), }, nil } if payload[0] == 0x17 { - length := parseVarUint64(payload[4 : 4+2]) + valueLength := parseVarUint64(payload[4 : 4+2]) return &FmpChunk{ Type: FMP_CHUNK_LONG_KEY_VALUE, - Key: parseVarUint64(payload[1 : 1+2]), - Value: payload[6 : 6+length], - Length: 6 + uint64(length), + Key: parseVarUint64(payload[1 : 1+3]), + Value: payload[6 : 6+valueLength], + Length: 6 + uint64(valueLength), }, nil } if payload[0] == 0x1E { @@ -132,7 +132,7 @@ func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { Type: FMP_CHUNK_LONG_KEY_VALUE, Key: parseVarUint64(payload[2 : 2+keyLength]), Value: payload[2+keyLength+1 : 2+keyLength+1+valueLength], - Length: 3 + uint64(keyLength) + uint64(valueLength), + Length: 2 + uint64(keyLength) + 1 + uint64(valueLength), }, nil } if payload[0] == 0x1F { @@ -149,23 +149,23 @@ func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { // Segmented data if payload[0] == 0x07 { - length := parseVarUint64(payload[2 : 2+2]) - payloadLimit := min(4+length, uint64(len(payload))) + valueLength := parseVarUint64(payload[2 : 2+2]) + payloadLimit := min(4+valueLength, uint64(len(payload))) return &FmpChunk{ Type: FMP_CHUNK_SEGMENTED_DATA, Index: uint64(payload[1]), Value: payload[4:payloadLimit], - Length: 4 + uint64(length), + Length: 4 + uint64(valueLength), }, nil } if payload[0] == 0x0F { - length := parseVarUint64(payload[3 : 3+2]) - payloadLimit := min(5+length, uint64(len(payload))) + valueLength := parseVarUint64(payload[3 : 3+2]) + payloadLimit := min(5+valueLength, uint64(len(payload))) return &FmpChunk{ Type: FMP_CHUNK_SEGMENTED_DATA, Index: parseVarUint64(payload[1 : 1+2]), Value: payload[5:payloadLimit], - Length: 5 + length, + Length: 5 + valueLength, }, nil } @@ -200,17 +200,17 @@ func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { }, nil } if payload[0] == 0x38 { - length := payload[1] + valueLength := payload[1] return &FmpChunk{ Type: FMP_CHUNK_PATH_PUSH, - Value: payload[2 : 2+length], - Length: 2 + uint64(length), + Value: payload[2 : 2+valueLength], + Length: 2 + uint64(valueLength), }, nil } // Path pop - if payload[0] == 0x3D && payload[1] == 0x40 { + if payload[0] == 0x3D || payload[0] == 0x40 { return &FmpChunk{ Type: FMP_CHUNK_PATH_POP, Length: 1, diff --git a/fmp/fmp_debug.go b/fmp/fmp_debug.go index 6e4846a..3eebd00 100644 --- a/fmp/fmp_debug.go +++ b/fmp/fmp_debug.go @@ -3,7 +3,6 @@ package fmp import ( "fmt" "os" - "strings" ) func (f *FmpFile) ToDebugFile(fname string) { @@ -36,11 +35,18 @@ func (c *FmpChunk) String() string { return fmt.Sprintf("<%v(%v)>", c.Type, c.Length) } -func (dict *FmpDict) String() string { +func (dict *FmpDict) string(parentPath string) string { s := "" for k, v := range *dict { - ns := strings.ReplaceAll(v.Children.String(), "\n", "\n\t") - s += fmt.Sprintf("%v: %v\n%v\n", k, string(v.Value), ns) + s += fmt.Sprintf("%v%v: %v\n", parentPath, k, string(v.Value)) + + if v.Children != nil { + s += v.Children.string(fmt.Sprintf("%v%v.", parentPath, k)) + } } return s } + +func (dict *FmpDict) String() string { + return dict.string("") +} diff --git a/fmp/fmp_file.go b/fmp/fmp_file.go index 70399d0..dfceb88 100644 --- a/fmp/fmp_file.go +++ b/fmp/fmp_file.go @@ -2,6 +2,8 @@ package fmp import ( "bytes" + "encoding/hex" + "fmt" "io" "os" "time" @@ -29,18 +31,18 @@ func OpenFile(path string) (*FmpFile, error) { } defer stream.Close() - ctx := &FmpFile{Stream: stream, Dictionary: &FmpDict{}} + ctx := &FmpFile{stream: stream, Dictionary: &FmpDict{}} if err := ctx.readHeader(); err != nil { return nil, err } ctx.FileSize = uint(info.Size()) - ctx.NumSectors = ctx.FileSize / sectorSize - ctx.Sectors = make([]*FmpSector, ctx.NumSectors) + ctx.numSectors = ctx.FileSize / sectorSize + ctx.Sectors = make([]*FmpSector, ctx.numSectors) currentPath := make([]uint64, 0) - for i := uint(0); i < ctx.NumSectors; i++ { + for i := uint(0); i < ctx.numSectors; i++ { sector, err := ctx.readSector() if err == io.EOF { break @@ -94,7 +96,7 @@ func OpenFile(path string) (*FmpFile, error) { func (ctx *FmpFile) readHeader() error { buf := make([]byte, sectorSize) - _, err := ctx.Stream.Read(buf) + _, err := ctx.stream.Read(buf) if err != nil { return err } @@ -118,7 +120,7 @@ func (ctx *FmpFile) readHeader() error { func (ctx *FmpFile) readSector() (*FmpSector, error) { buf := make([]byte, sectorHeaderSize) - n, err := ctx.Stream.Read(buf) + n, err := ctx.stream.Read(buf) if n == 0 { return nil, io.EOF @@ -135,7 +137,7 @@ func (ctx *FmpFile) readSector() (*FmpSector, error) { } payload := make([]byte, sectorSize-sectorHeaderSize) - n, err = ctx.Stream.Read(payload) + n, err = ctx.stream.Read(payload) if n != sectorSize-sectorHeaderSize { return nil, ErrRead } @@ -146,6 +148,9 @@ func (ctx *FmpFile) readSector() (*FmpSector, error) { for { chunk, err := ctx.readChunk(payload) + if chunk != nil { + fmt.Printf("%s - (type%v)\n", hex.EncodeToString([]byte{payload[0]}), int(chunk.Type)) + } if err == io.EOF { break } diff --git a/fmp/fmp_table.go b/fmp/fmp_table.go index 3d81cc0..85994f5 100644 --- a/fmp/fmp_table.go +++ b/fmp/fmp_table.go @@ -3,28 +3,31 @@ package fmp func (ctx *FmpFile) Tables() []*FmpTable { tables := make([]*FmpTable, 0) - for _, chunk := range ctx.Chunks { - if chunk.Key != 3 || chunk.Type != FMP_CHUNK_SIMPLE_KEY_VALUE { + for key, ent := range *ctx.Dictionary { + if key != 3 { continue } + println("Found a 3") - for _, chunk = range ctx.Chunks { - if chunk.Key != 16 { + for key, ent = range *ent.Children { + if key != 16 { continue } + println("Found a 3.16") - for _, chunk = range ctx.Chunks { - if chunk.Key != 5 { + for key, ent = range *ent.Children { + if key != 5 { continue } + println("Found a 3.16.5") - for tablePath, chunk := range ctx.Chunks { - if chunk.Key >= 128 { + for tablePath := range *ent.Children { + if key >= 128 { continue } // Found a table! - println("Found one at", tablePath) + println("Found a table at 3.16.5.", tablePath) } } } diff --git a/fmp/fmp_test.go b/fmp/fmp_test.go index 42f9a75..6c28d5f 100644 --- a/fmp/fmp_test.go +++ b/fmp/fmp_test.go @@ -10,8 +10,8 @@ func TestOpenFile(t *testing.T) { if f.FileSize != 393216 { t.Errorf("expected file size to be 393216, got %d", f.FileSize) } - if f.NumSectors != 96 { - t.Errorf("expected number of sectors to be 96, got %d", f.NumSectors) + if f.numSectors != 96 { + t.Errorf("expected number of sectors to be 96, got %d", f.numSectors) } if f.CreatorName != "Pro 12.0" { t.Errorf("expected application name to be 'Pro 12.0', got '%s'", f.CreatorName) diff --git a/fmp/fmp_type.go b/fmp/fmp_type.go index c9b4114..697854a 100644 --- a/fmp/fmp_type.go +++ b/fmp/fmp_type.go @@ -9,11 +9,12 @@ type FmpFile struct { VersionDate time.Time CreatorName string FileSize uint - NumSectors uint - Stream io.ReadSeeker Sectors []*FmpSector Chunks []*FmpChunk Dictionary *FmpDict + + numSectors uint + stream io.ReadSeeker } type FmpSector struct { diff --git a/fmp/fmp_util.go b/fmp/fmp_util.go index eafe231..e2225ad 100644 --- a/fmp/fmp_util.go +++ b/fmp/fmp_util.go @@ -2,10 +2,7 @@ package fmp func parseVarUint64(payload []byte) uint64 { var length uint64 - n := len(payload) - if n > 8 { - n = 8 // clamp to max uint64 - } + n := min(len(payload), 8) // clamp to uint64 for i := range n { length <<= 8 length |= uint64(payload[i])