1
0
mirror of https://github.com/garraflavatra/go-fmp.git synced 2025-06-27 20:15:11 +00:00

Skip first sector

This commit is contained in:
2025-06-13 19:54:17 +02:00
parent 17a3664e42
commit f364ed7ede
3 changed files with 99 additions and 77 deletions

View File

@ -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, &currentPath)
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
}

View File

@ -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

View File

@ -27,6 +27,7 @@ type FmpSector struct {
NextID uint64
Prev *FmpSector
Next *FmpSector
Payload []byte
Chunks []*FmpChunk
}