From c08c429b99d0d52ccb2df8febaac52bf37d9272d Mon Sep 17 00:00:00 2001 From: Romein van Buren Date: Sun, 22 Jun 2025 20:08:53 +0200 Subject: [PATCH] Add NewSector function --- fmp/fmp_dict.go | 2 +- fmp/fmp_file.go | 49 ++++++++++++++++++++++++++++++++++++++++++++--- fmp/fmp_sector.go | 8 ++++---- fmp/fmp_test.go | 6 +++++- fmp/fmp_util.go | 15 +++++++++++++++ 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/fmp/fmp_dict.go b/fmp/fmp_dict.go index 8613c47..9318582 100644 --- a/fmp/fmp_dict.go +++ b/fmp/fmp_dict.go @@ -42,7 +42,7 @@ func (dict *FmpDict) GetChildren(path ...uint64) *FmpDict { return &FmpDict{} } -func (dict *FmpDict) SetValue(path []uint64, value []byte) { +func (dict *FmpDict) set(path []uint64, value []byte) { for i, key := range path { _, ok := (*dict)[key] if !ok { diff --git a/fmp/fmp_file.go b/fmp/fmp_file.go index dd8751d..7f33d70 100644 --- a/fmp/fmp_file.go +++ b/fmp/fmp_file.go @@ -32,7 +32,7 @@ type FmpFile struct { numSectors uint64 // Excludes the header sector currentSectorID uint64 - stream io.ReadSeeker + stream *os.File } func OpenFile(path string) (*FmpFile, error) { @@ -41,11 +41,10 @@ func OpenFile(path string) (*FmpFile, error) { return nil, err } - stream, err := os.Open(path) + stream, err := os.OpenFile(path, os.O_RDWR, 0) if err != nil { return nil, err } - defer stream.Close() ctx := &FmpFile{stream: stream, Dictionary: &FmpDict{}} if err := ctx.readHeader(); err != nil { @@ -90,6 +89,10 @@ func OpenFile(path string) (*FmpFile, error) { return ctx, nil } +func (ctx *FmpFile) Close() { + ctx.stream.Close() +} + func (ctx *FmpFile) readHeader() error { buf := make([]byte, headerSize) _, err := ctx.stream.Read(buf) @@ -208,3 +211,43 @@ func (ctx *FmpFile) readTables() { ctx.tables = tables } + +func (ctx *FmpFile) NewSector() (*FmpSector, error) { + id := uint64(len(ctx.Sectors)) + 1 + prevID := id - 2 + + ctx.Sectors[prevID].NextID = uint64(id) + _, err := ctx.stream.WriteAt(encodeUint(4, int(id)), int64((id-1)*sectorSize)+4) + + if err != nil { + return nil, err + } + + sector := &FmpSector{ + ID: uint64(id), + Deleted: false, + Level: 0, + PrevID: prevID, + NextID: 0, + Chunks: make([]*FmpChunk, 0), + } + + ctx.Sectors = append(ctx.Sectors, sector) + + sectorBuf := make([]byte, sectorSize) + sectorBuf[0] = 0 // deleted + sectorBuf[1] = 0 // level + writeToSlice(sectorBuf, 4, encodeUint(4, int(prevID))...) + writeToSlice(sectorBuf, 8, encodeUint(4, int(id))...) + + _, err = ctx.stream.WriteAt(sectorBuf, int64((id+1)*sectorSize)) + if err != nil { + return nil, err + } + return sector, nil +} + +func (ctx *FmpFile) setValue(path []uint64, value []byte) { + // ctx.Dictionary.set(path, value) + +} diff --git a/fmp/fmp_sector.go b/fmp/fmp_sector.go index 05a26c3..80aa260 100644 --- a/fmp/fmp_sector.go +++ b/fmp/fmp_sector.go @@ -79,23 +79,23 @@ func (sect *FmpSector) processChunks(dict *FmpDict) error { } case FmpChunkSimpleData: - dict.SetValue(currentPath, chunk.Value) + dict.set(currentPath, chunk.Value) case FmpChunkSegmentedData: // Todo: take index into account - dict.SetValue( + dict.set( currentPath, append(dict.GetValue(currentPath...), chunk.Value...), ) case FmpChunkSimpleKeyValue: - dict.SetValue( + dict.set( append(currentPath, uint64(chunk.Key)), chunk.Value, ) case FmpChunkLongKeyValue: - dict.SetValue( + dict.set( append(currentPath, uint64(chunk.Key)), // todo: ?? chunk.Value, ) diff --git a/fmp/fmp_test.go b/fmp/fmp_test.go index 57e96c9..53fc0fa 100644 --- a/fmp/fmp_test.go +++ b/fmp/fmp_test.go @@ -10,8 +10,10 @@ func TestOpenFile(t *testing.T) { if err != nil { t.Fatal(err) } + defer f.Close() + if f.FileSize != 229376 { - t.Errorf("expected file size to be 393216, got %d", f.FileSize) + t.Errorf("expected file size to be 229376, got %d", f.FileSize) } if f.numSectors != 55 { t.Errorf("expected number of sectors to be 55, got %d", f.numSectors) @@ -22,6 +24,7 @@ func TestOpenFile(t *testing.T) { if f.VersionDate.Format("2006-01-02") != "2025-01-11" { t.Errorf("expected version date to be '2025-01-11', got '%s'", f.VersionDate.Format("2006-01-02")) } + f.ToDebugFile("../private/output") } @@ -30,6 +33,7 @@ func TestTables(t *testing.T) { if err != nil { t.Fatal(err) } + defer f.Close() expectedNames := []string{"Untitled"} tableNames := []string{} diff --git a/fmp/fmp_util.go b/fmp/fmp_util.go index cbeda38..511acc3 100644 --- a/fmp/fmp_util.go +++ b/fmp/fmp_util.go @@ -24,3 +24,18 @@ func decodeString(payload []byte) string { } return result } + +func encodeUint(size uint, value int) []byte { + result := make([]byte, size) + for i := range size { + result[i] = byte(value & 0xFF) + value >>= 8 + } + return result +} + +func writeToSlice(slice []byte, start int, payload ...byte) { + for i := range payload { + slice[start+i] = payload[i] + } +}