2025-06-11 21:52:52 +02:00
|
|
|
package fmp
|
|
|
|
|
|
|
|
func (ctx *FmpFile) readChunk(payload []byte) (*FmpChunk, error) {
|
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
// https://github.com/evanmiller/fmptools/blob/02eb770e59e0866dab213d80e5f7d88e17648031/HACKING
|
|
|
|
// https://github.com/Rasmus20B/fmplib/blob/66245e5269275724bacfe1437fb1f73bc587a2f3/src/fmp_format/chunk.rs#L57-L60
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk := &FmpChunk{}
|
2025-06-13 17:23:58 +02:00
|
|
|
chunkCode := payload[0]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 17:23:58 +02:00
|
|
|
if (chunkCode & 0xC0) == 0xC0 {
|
|
|
|
chunkCode &= 0x3F
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Delayed = true
|
2025-06-11 21:52:52 +02:00
|
|
|
}
|
2025-06-13 14:44:32 +02:00
|
|
|
|
2025-06-13 17:23:58 +02:00
|
|
|
switch chunkCode {
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x00:
|
|
|
|
chunk.Length = 2
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x01:
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 3
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
|
|
chunk.Key = uint64(payload[1])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[2:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x02, 0x03, 0x04, 0x05:
|
2025-06-13 17:23:58 +02:00
|
|
|
valueLength := uint64(2 * (chunkCode - 1))
|
|
|
|
chunk.Length = 2 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
|
|
chunk.Key = uint64(payload[1])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[2:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x06:
|
2025-06-13 16:28:44 +02:00
|
|
|
valueLength := uint64(payload[2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 3 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
|
|
chunk.Key = uint64(payload[1])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[3:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x07:
|
|
|
|
valueLength := parseVarUint64(payload[2 : 2+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = min(4+valueLength, uint64(len(payload)))
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SEGMENTED_DATA
|
|
|
|
chunk.Index = uint64(payload[1])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[4:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x08:
|
|
|
|
chunk.Length = 3
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x09:
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 4
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
|
|
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[3:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x0A, 0x0B, 0x0C, 0x0D:
|
2025-06-13 17:23:58 +02:00
|
|
|
valueLength := uint64(2 * (chunkCode - 0x09))
|
|
|
|
chunk.Length = 3 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
|
|
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[3:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x0E:
|
|
|
|
if payload[1] == 0xFE {
|
|
|
|
chunk.Length = 10
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
|
|
chunk.Value = payload[2:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if payload[1] == 0xFF {
|
|
|
|
chunk.Length = 7
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
|
|
chunk.Value = payload[2:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2025-06-13 16:28:44 +02:00
|
|
|
valueLength := uint64(payload[2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 4 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_KEY_VALUE
|
|
|
|
chunk.Key = parseVarUint64(payload[1 : 1+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[4:chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x0F:
|
|
|
|
valueLength := parseVarUint64(payload[3 : 3+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = min(5+valueLength, uint64(len(payload)))
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SEGMENTED_DATA
|
|
|
|
chunk.Index = parseVarUint64(payload[1 : 1+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[5:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x10, 0x11:
|
2025-06-13 17:23:58 +02:00
|
|
|
valueLength := 3 + (uint64(chunkCode) - 0x10)
|
|
|
|
chunk.Length = 1 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x12, 0x13, 0x14, 0x15:
|
2025-06-13 17:23:58 +02:00
|
|
|
valueLength := 1 + 2*(uint64(chunkCode)-0x10)
|
|
|
|
chunk.Length = 1 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x16:
|
2025-06-13 16:28:44 +02:00
|
|
|
valueLength := uint64(payload[4])
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 5 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Key = parseVarUint64(payload[1 : 1+3])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[5:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x17:
|
2025-06-12 21:21:55 +02:00
|
|
|
valueLength := parseVarUint64(payload[4 : 4+2])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 6 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
|
|
|
chunk.Key = parseVarUint64(payload[1 : 1+3])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[6:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x19:
|
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
|
|
chunk.Length = 2
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x1A, 0x1B, 0x1C, 0x1D:
|
2025-06-13 17:23:58 +02:00
|
|
|
valueLength := 2 * uint64(chunkCode-0x19)
|
2025-06-13 16:28:44 +02:00
|
|
|
chunk.Length = 1 + valueLength
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x1E:
|
2025-06-13 16:28:44 +02:00
|
|
|
keyLength := uint64(payload[1])
|
|
|
|
valueLength := uint64(payload[2+keyLength])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 2 + keyLength + 1 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
|
|
|
chunk.Key = parseVarUint64(payload[2 : 2+keyLength])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[2+keyLength+1 : chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x1F:
|
2025-06-13 16:28:44 +02:00
|
|
|
keyLength := uint64(uint64(payload[1]))
|
2025-06-12 11:52:09 +02:00
|
|
|
valueLength := parseVarUint64(payload[2+keyLength : 2+keyLength+2+1])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 2 + keyLength + 2 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_LONG_KEY_VALUE
|
|
|
|
chunk.Key = parseVarUint64(payload[2 : 2+keyLength])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[2+keyLength+2 : chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x20:
|
|
|
|
if payload[1] == 0xFE {
|
|
|
|
chunk.Length = 10
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
break
|
|
|
|
}
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Length = 2
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x23:
|
|
|
|
chunk.Length = 2
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_SIMPLE_DATA
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x28:
|
|
|
|
chunk.Length = 3
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x30:
|
|
|
|
chunk.Length = 4
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
|
|
|
chunk.Value = payload[1:chunk.Length]
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x38:
|
2025-06-13 16:28:44 +02:00
|
|
|
valueLength := uint64(payload[1])
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Length = 2 + valueLength
|
2025-06-13 14:44:32 +02:00
|
|
|
chunk.Type = FMP_CHUNK_PATH_PUSH
|
2025-06-13 17:23:58 +02:00
|
|
|
chunk.Value = payload[2:chunk.Length]
|
2025-06-13 14:44:32 +02:00
|
|
|
|
|
|
|
case 0x3D, 0x40:
|
|
|
|
chunk.Type = FMP_CHUNK_PATH_POP
|
|
|
|
chunk.Length = 1
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
case 0x80:
|
|
|
|
chunk.Type = FMP_CHUNK_NOOP
|
|
|
|
chunk.Length = 1
|
2025-06-11 21:52:52 +02:00
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
default:
|
|
|
|
return nil, ErrBadChunk
|
2025-06-11 21:52:52 +02:00
|
|
|
}
|
|
|
|
|
2025-06-13 14:44:32 +02:00
|
|
|
return chunk, nil
|
2025-06-11 21:52:52 +02:00
|
|
|
}
|