diff --git a/fmp/fmp_debug.go b/fmp/fmp_debug.go index 3eebd00..b01106e 100644 --- a/fmp/fmp_debug.go +++ b/fmp/fmp_debug.go @@ -6,6 +6,19 @@ import ( ) func (f *FmpFile) ToDebugFile(fname string) { + f_sectors, err := os.Create(fname + ".sectors") + if err != nil { + panic(err) + } + defer func() { + if err := f_sectors.Close(); err != nil { + panic(err) + } + }() + for _, sect := range f.Sectors { + fmt.Fprintf(f_sectors, "%s\n", sect.String()) + } + f_chunks, err := os.Create(fname + ".chunks") if err != nil { panic(err) @@ -31,8 +44,12 @@ func (f *FmpFile) ToDebugFile(fname string) { fmt.Fprint(f_dicts, f.Dictionary.String()) } +func (sect *FmpSector) String() string { + return fmt.Sprintf("", sect.ID, sect.Deleted, sect.Level, sect.PrevID, sect.NextID) +} + func (c *FmpChunk) String() string { - return fmt.Sprintf("<%v(%v)>", c.Type, c.Length) + return fmt.Sprintf("", c.Type, c.Length) } func (dict *FmpDict) string(parentPath string) string { diff --git a/fmp/fmp_file.go b/fmp/fmp_file.go index dfceb88..1db4053 100644 --- a/fmp/fmp_file.go +++ b/fmp/fmp_file.go @@ -2,7 +2,6 @@ package fmp import ( "bytes" - "encoding/hex" "fmt" "io" "os" @@ -10,13 +9,16 @@ import ( ) const ( + sectorSize = 4096 + sectorHeaderSize = 20 + sectorPayloadSize = sectorSize - sectorHeaderSize + magicSequence = "\x00\x01\x00\x00\x00\x02\x00\x01\x00\x05\x00\x02\x00\x02\xC0" hbamSequence = "HBAM7" - magicSize = len(magicSequence) - hbamSize = len(hbamSequence) - sectorSize = 4096 - sectorHeaderSize = 20 + headerSize = sectorSize + magicSize = len(magicSequence) + hbamSize = len(hbamSequence) ) func OpenFile(path string) (*FmpFile, error) { @@ -37,12 +39,11 @@ func OpenFile(path string) (*FmpFile, error) { } ctx.FileSize = uint(info.Size()) - ctx.numSectors = ctx.FileSize / sectorSize - ctx.Sectors = make([]*FmpSector, ctx.numSectors) - + ctx.numSectors = uint64((ctx.FileSize / sectorSize) - 1) + ctx.Sectors = make([]*FmpSector, 0) currentPath := make([]uint64, 0) - for i := uint(0); i < ctx.numSectors; i++ { + for { sector, err := ctx.readSector() if err == io.EOF { break @@ -50,7 +51,7 @@ func OpenFile(path string) (*FmpFile, error) { if err != nil { return nil, err } - ctx.Sectors[i] = sector + ctx.Sectors = append(ctx.Sectors, sector) ctx.Chunks = append(ctx.Chunks, sector.Chunks...) for _, chunk := range sector.Chunks { @@ -89,13 +90,22 @@ func OpenFile(path string) (*FmpFile, error) { // noop } } + + ctx.currentSectorID = sector.NextID + if sector.NextID == 0 { + break + } else if sector.NextID > ctx.numSectors { + return nil, ErrBadHeader + } else { + ctx.stream.Seek(int64(sector.NextID*sectorSize), 0) + } } return ctx, nil } func (ctx *FmpFile) readHeader() error { - buf := make([]byte, sectorSize) + buf := make([]byte, headerSize) _, err := ctx.stream.Read(buf) if err != nil { return err @@ -130,26 +140,30 @@ func (ctx *FmpFile) readSector() (*FmpSector, error) { } sector := &FmpSector{ - Deleted: buf[0] != 0, - Level: uint8(buf[1]), - PrevSectorID: parseVarUint64(buf[2:6]), - NextSectorID: parseVarUint64(buf[6:10]), + ID: ctx.currentSectorID, + Deleted: buf[0] > 0, + Level: uint8(buf[1]), + PrevID: parseVarUint64(buf[4 : 4+4]), + NextID: parseVarUint64(buf[8 : 8+4]), } - payload := make([]byte, sectorSize-sectorHeaderSize) + payload := make([]byte, sectorPayloadSize) n, err = ctx.stream.Read(payload) - if n != sectorSize-sectorHeaderSize { + + if n != sectorPayloadSize { return nil, ErrRead } if err != nil { return nil, ErrRead } + sector.Chunks = make([]*FmpChunk, 0) for { chunk, err := ctx.readChunk(payload) + fmt.Printf("0x%02X", payload[0]) if chunk != nil { - fmt.Printf("%s - (type%v)\n", hex.EncodeToString([]byte{payload[0]}), int(chunk.Type)) + fmt.Printf(" (type %v)\n", int(chunk.Type)) } if err == io.EOF { break diff --git a/fmp/fmp_test.go b/fmp/fmp_test.go index 6c28d5f..a4440c0 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 != 95 { + t.Errorf("expected number of sectors to be 95, 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 697854a..16c7d15 100644 --- a/fmp/fmp_type.go +++ b/fmp/fmp_type.go @@ -13,16 +13,21 @@ type FmpFile struct { Chunks []*FmpChunk Dictionary *FmpDict - numSectors uint - stream io.ReadSeeker + numSectors uint64 // Excludes the header sector + currentSectorID uint64 + + stream io.ReadSeeker } type FmpSector struct { - Deleted bool - Level uint8 - PrevSectorID uint64 - NextSectorID uint64 - Chunks []*FmpChunk + ID uint64 + Level uint8 + Deleted bool + PrevID uint64 + NextID uint64 + Prev *FmpSector + Next *FmpSector + Chunks []*FmpChunk } type FmpChunk struct {