From f364ed7edefb568d964254dee5e2c3ce77b906d2 Mon Sep 17 00:00:00 2001 From: Romein van Buren Date: Fri, 13 Jun 2025 19:54:17 +0200 Subject: [PATCH] Skip first sector --- fmp/fmp_file.go | 83 +++----------------------- fmp/{fmp_chunk.go => fmp_sector.go} | 92 ++++++++++++++++++++++++++++- fmp/fmp_type.go | 1 + 3 files changed, 99 insertions(+), 77 deletions(-) rename fmp/{fmp_chunk.go => fmp_sector.go} (72%) diff --git a/fmp/fmp_file.go b/fmp/fmp_file.go index 7f65522..e4344ac 100644 --- a/fmp/fmp_file.go +++ b/fmp/fmp_file.go @@ -2,7 +2,6 @@ package fmp import ( "bytes" - "fmt" "io" "os" "time" @@ -51,52 +50,11 @@ func OpenFile(path string) (*FmpFile, error) { if err != nil { return nil, err } + ctx.Sectors = append(ctx.Sectors, sector) - ctx.Chunks = append(ctx.Chunks, sector.Chunks...) - - for _, chunk := range sector.Chunks { - switch chunk.Type { - case FMP_CHUNK_PATH_PUSH: - currentPath = append(currentPath, uint64(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.getValue(currentPath), chunk.Value...), - ) - - case FMP_CHUNK_SIMPLE_KEY_VALUE: - ctx.Dictionary.set( - append(currentPath, uint64(chunk.Key)), - chunk.Value, - ) - - case FMP_CHUNK_LONG_KEY_VALUE: - ctx.Dictionary.set( - append(currentPath, uint64(chunk.Key)), // todo: ?? - chunk.Value, - ) - - case FMP_CHUNK_NOOP: - // noop - } - - if chunk.Delayed { - if len(currentPath) == 0 { - println("warning: delayed pop without path") - } else { - currentPath = currentPath[:len(currentPath)-1] - } - } + if sector.ID != 0 { + sector.processChunks(ctx.Dictionary, ¤tPath) + ctx.Chunks = append(ctx.Chunks, sector.Chunks...) } ctx.currentSectorID = sector.NextID @@ -154,14 +112,15 @@ func (ctx *FmpFile) readSector() (*FmpSector, error) { Level: uint8(buf[1]), PrevID: parseVarUint64(buf[4 : 4+4]), NextID: parseVarUint64(buf[8 : 8+4]), + Chunks: make([]*FmpChunk, 0), } if ctx.currentSectorID == 0 && sector.PrevID > 0 { return nil, ErrBadSectorHeader } - payload := make([]byte, sectorPayloadSize) - n, err = ctx.stream.Read(payload) + sector.Payload = make([]byte, sectorPayloadSize) + n, err = ctx.stream.Read(sector.Payload) if n != sectorPayloadSize { return nil, ErrRead @@ -169,33 +128,5 @@ func (ctx *FmpFile) readSector() (*FmpSector, error) { 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(" (type %v)\n", int(chunk.Type)) - } - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - if chunk == nil { - break - } - if chunk.Length == 0 { - panic("chunk length not set") - } - sector.Chunks = append(sector.Chunks, chunk) - payload = payload[min(chunk.Length, uint64(len(payload))):] - if len(payload) == 0 || (len(payload) == 1 && payload[0] == 0x00) { - break - } - } - return sector, nil } diff --git a/fmp/fmp_chunk.go b/fmp/fmp_sector.go similarity index 72% rename from fmp/fmp_chunk.go rename to fmp/fmp_sector.go index c94be12..d0cad60 100644 --- a/fmp/fmp_chunk.go +++ b/fmp/fmp_sector.go @@ -1,6 +1,96 @@ package fmp -func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) { +import ( + "fmt" + "io" +) + +func (sect *FmpSector) readChunks() error { + for { + pos := (sect.ID+2)*sectorSize - uint64(len(sect.Payload)) + + chunk, err := sect.readChunk(sect.Payload) + if chunk == nil { + fmt.Printf("0x%02x (pos %v, unknown)\n", sect.Payload[0], pos) + } else { + fmt.Printf("0x%02x (pos %v, type %v)\n", sect.Payload[0], pos, int(chunk.Type)) + } + + if err == io.EOF { + println("break1") + break + } + if err != nil { + println(string(sect.Payload)) + println("break2") + return err + } + if chunk == nil { + println("break3") + break + } + if chunk.Length == 0 { + panic("chunk length not set") + } + + sect.Chunks = append(sect.Chunks, chunk) + sect.Payload = sect.Payload[min(chunk.Length, uint64(len(sect.Payload))):] + + if len(sect.Payload) == 0 || (len(sect.Payload) == 1 && sect.Payload[0] == 0x00) { + break + } + } + return nil +} + +func (sect *FmpSector) processChunks(dict *FmpDict, currentPath *[]uint64) { + for _, chunk := range sect.Chunks { + switch chunk.Type { + case FMP_CHUNK_PATH_PUSH: + *currentPath = append(*currentPath, uint64(chunk.Value[0])) + + case FMP_CHUNK_PATH_POP: + if len(*currentPath) > 0 { + *currentPath = (*currentPath)[:len(*currentPath)-1] + } + + case FMP_CHUNK_SIMPLE_DATA: + dict.set(*currentPath, chunk.Value) + + case FMP_CHUNK_SEGMENTED_DATA: + // Todo: take index into account + dict.set( + *currentPath, + append(dict.getValue(*currentPath), chunk.Value...), + ) + + case FMP_CHUNK_SIMPLE_KEY_VALUE: + dict.set( + append(*currentPath, uint64(chunk.Key)), + chunk.Value, + ) + + case FMP_CHUNK_LONG_KEY_VALUE: + dict.set( + append(*currentPath, uint64(chunk.Key)), // todo: ?? + chunk.Value, + ) + + case FMP_CHUNK_NOOP: + // noop + } + + if chunk.Delayed { + if len(*currentPath) == 0 { + println("warning: delayed pop without path") + } else { + *currentPath = (*currentPath)[:len(*currentPath)-1] + } + } + } +} + +func (sect *FmpSector) readChunk(payload []byte) (*FmpChunk, error) { // https://github.com/evanmiller/fmptools/blob/02eb770e59e0866dab213d80e5f7d88e17648031/HACKING // https://github.com/Rasmus20B/fmplib/blob/66245e5269275724bacfe1437fb1f73bc587a2f3/src/fmp_format/chunk.rs#L57-L60 diff --git a/fmp/fmp_type.go b/fmp/fmp_type.go index 9bfee28..a4d6fc1 100644 --- a/fmp/fmp_type.go +++ b/fmp/fmp_type.go @@ -27,6 +27,7 @@ type FmpSector struct { NextID uint64 Prev *FmpSector Next *FmpSector + Payload []byte Chunks []*FmpChunk }