add most basic error handling on the decode side

This commit is contained in:
2024-12-23 23:59:11 -06:00
parent 0c297d606d
commit 6bc6fb3668
15 changed files with 227 additions and 84 deletions
+21 -4
View File
@@ -1,6 +1,10 @@
package psn
import "github.com/jwetzell/psn-go/internal/decoders"
import (
"log/slog"
"github.com/jwetzell/psn-go/internal/decoders"
)
type Decoder struct {
lastInfoPacketHeader *decoders.PacketHeaderChunk
@@ -49,10 +53,19 @@ func (d *Decoder) updateData(framePackets []decoders.DataPacketChunk) {
}
func (d *Decoder) Decode(bytes []byte) {
chunk := decoders.DecodeChunk(bytes)
chunk, err := decoders.DecodeChunk(bytes)
if err != nil {
slog.Error("error decoding", "err", err)
return
}
if chunk.Header.Id == 0x6756 {
infoPacket := decoders.DecodeInfoPacketChunk(bytes)
infoPacket, err := decoders.DecodeInfoPacketChunk(bytes)
if err != nil {
slog.Error("error decoding", "err", err)
return
}
currentInfoPacketHeader := infoPacket.Data.PacketHeader
_, ok := d.infoPacketFrames[currentInfoPacketHeader.Data.FrameId]
@@ -67,7 +80,11 @@ func (d *Decoder) Decode(bytes []byte) {
delete(d.infoPacketFrames, currentInfoPacketHeader.Data.FrameId)
}
} else if chunk.Header.Id == 0x6755 {
dataPacket := decoders.DecodeDataPacketChunk(bytes)
dataPacket, err := decoders.DecodeDataPacketChunk(bytes)
if err != nil {
slog.Error("error decoding", "err", err)
return
}
currentInfoPacketHeader := dataPacket.Data.PacketHeader
_, ok := d.dataPacketFrames[currentInfoPacketHeader.Data.FrameId]
+8 -2
View File
@@ -2,6 +2,7 @@ package decoders
import (
"encoding/binary"
"errors"
)
type ChunkHeader struct {
@@ -15,7 +16,12 @@ type Chunk struct {
ChunkData []byte
}
func DecodeChunk(bytes []byte) Chunk {
func DecodeChunk(bytes []byte) (Chunk, error) {
if len(bytes) < 4 {
return Chunk{}, errors.New("chunk must be at least 4 bytes")
}
id := binary.LittleEndian.Uint16(bytes[0:2])
lengthAndFlag := binary.LittleEndian.Uint16(bytes[2:4])
@@ -38,5 +44,5 @@ func DecodeChunk(bytes []byte) Chunk {
return Chunk{
Header: header,
ChunkData: chunk_data,
}
}, nil
}
+6 -1
View File
@@ -56,7 +56,12 @@ func TestChunkDecoding(t *testing.T) {
for _, testCase := range testCases {
actual := DecodeChunk(testCase.bytes)
actual, err := DecodeChunk(testCase.bytes)
if err != nil {
t.Errorf("Test '%s' failed to decode chunk properly", testCase.description)
fmt.Println(err)
}
if !reflect.DeepEqual(actual, testCase.expected) {
t.Errorf("Test '%s' failed to decode chunk properly", testCase.description)
+19 -7
View File
@@ -15,8 +15,13 @@ type DataPacketChunk struct {
Data DataPacketChunkData
}
func DecodeDataPacketChunk(bytes []byte) DataPacketChunk {
chunk := DecodeChunk(bytes)
func DecodeDataPacketChunk(bytes []byte) (DataPacketChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return DataPacketChunk{}, err
}
data := DataPacketChunkData{}
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
@@ -25,14 +30,20 @@ func DecodeDataPacketChunk(bytes []byte) DataPacketChunk {
for offset < int(chunk.Header.DataLen) {
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
case 0x0000:
packet_header := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
packet_header, err := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
if err != nil {
return DataPacketChunk{}, err
}
data.PacketHeader = &packet_header
offset += 4
if packet_header.Chunk.Header.DataLen > 0 {
offset = offset + int(packet_header.Chunk.Header.DataLen)
}
case 0x0001:
tracker_list := DecodeDataTrackerListChunk(chunk.ChunkData[offset:])
tracker_list, err := DecodeDataTrackerListChunk(chunk.ChunkData[offset:])
if err != nil {
return DataPacketChunk{}, err
}
data.TrackerList = &tracker_list
offset += 4
if tracker_list.Chunk.Header.DataLen > 0 {
@@ -46,7 +57,8 @@ func DecodeDataPacketChunk(bytes []byte) DataPacketChunk {
}
return DataPacketChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+39 -12
View File
@@ -20,8 +20,13 @@ type DataTrackerChunk struct {
Data DataTrackerChunkData
}
func DecodeDataTrackerChunk(bytes []byte) DataTrackerChunk {
chunk := DecodeChunk(bytes)
func DecodeDataTrackerChunk(bytes []byte) (DataTrackerChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return DataTrackerChunk{}, err
}
data := DataTrackerChunkData{}
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
@@ -30,49 +35,70 @@ func DecodeDataTrackerChunk(bytes []byte) DataTrackerChunk {
for offset < int(chunk.Header.DataLen) {
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
case 0x0000:
pos := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
pos, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.Pos = &pos
offset += 4
if data.Pos.Chunk.Header.DataLen > 0 {
offset = offset + int(data.Pos.Chunk.Header.DataLen)
}
case 0x0001:
speed := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
speed, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.Speed = &speed
offset += 4
if data.Speed.Chunk.Header.DataLen > 0 {
offset = offset + int(data.Speed.Chunk.Header.DataLen)
}
case 0x0002:
ori := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
ori, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.Ori = &ori
offset += 4
if data.Ori.Chunk.Header.DataLen > 0 {
offset = offset + int(data.Ori.Chunk.Header.DataLen)
}
case 0x0003:
status := DecodeDataTrackerStatusChunk(chunk.ChunkData[offset:])
status, err := DecodeDataTrackerStatusChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.Status = &status
offset += 4
if data.Status.Chunk.Header.DataLen > 0 {
offset = offset + int(data.Status.Chunk.Header.DataLen)
}
case 0x0004:
accel := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
accel, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.Accel = &accel
offset += 4
if data.Accel.Chunk.Header.DataLen > 0 {
offset = offset + int(data.Accel.Chunk.Header.DataLen)
}
case 0x0005:
trgtpos := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
trgtpos, err := DecodeDataTrackerXYZChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.TrgtPos = &trgtpos
offset += 4
if data.TrgtPos.Chunk.Header.DataLen > 0 {
offset = offset + int(data.TrgtPos.Chunk.Header.DataLen)
}
case 0x0006:
timestamp := DecodeDataTrackerTimestampChunk(chunk.ChunkData[offset:])
timestamp, err := DecodeDataTrackerTimestampChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerChunk{}, err
}
data.Timestamp = &timestamp
offset += 4
if data.Timestamp.Chunk.Header.DataLen > 0 {
@@ -86,7 +112,8 @@ func DecodeDataTrackerChunk(bytes []byte) DataTrackerChunk {
}
return DataTrackerChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+14 -6
View File
@@ -8,14 +8,21 @@ type DataTrackerListChunk struct {
Data DataTrackerListChunkData
}
func DecodeDataTrackerListChunk(bytes []byte) DataTrackerListChunk {
chunk := DecodeChunk(bytes)
func DecodeDataTrackerListChunk(bytes []byte) (DataTrackerListChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return DataTrackerListChunk{}, err
}
trackers := []DataTrackerChunk{}
if chunk.Header.HasSubchunks && chunk.Header.DataLen > 0 {
offset := 0
for offset < int(chunk.Header.DataLen) {
trackerChunk := DecodeDataTrackerChunk(chunk.ChunkData[offset:])
trackerChunk, err := DecodeDataTrackerChunk(chunk.ChunkData[offset:])
if err != nil {
return DataTrackerListChunk{}, err
}
offset += 4
if trackerChunk.Chunk.Header.DataLen > 0 {
offset += int(trackerChunk.Chunk.Header.DataLen)
@@ -29,7 +36,8 @@ func DecodeDataTrackerListChunk(bytes []byte) DataTrackerListChunk {
}
return DataTrackerListChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+15 -5
View File
@@ -2,6 +2,7 @@ package decoders
import (
"encoding/binary"
"errors"
"math"
)
@@ -14,8 +15,16 @@ type DataTrackerStatusChunk struct {
Data DataTrackerStatusChunkData
}
func DecodeDataTrackerStatusChunk(bytes []byte) DataTrackerStatusChunk {
chunk := DecodeChunk(bytes)
func DecodeDataTrackerStatusChunk(bytes []byte) (DataTrackerStatusChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return DataTrackerStatusChunk{}, err
}
if len(chunk.ChunkData) < 4 {
return DataTrackerStatusChunk{}, errors.New("DATA_TRACKER_STATUS chunk must be at least 4 bytes")
}
statusBits := binary.LittleEndian.Uint32(chunk.ChunkData[0:4])
@@ -24,7 +33,8 @@ func DecodeDataTrackerStatusChunk(bytes []byte) DataTrackerStatusChunk {
}
return DataTrackerStatusChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
@@ -2,6 +2,7 @@ package decoders
import (
"encoding/binary"
"errors"
)
type DataTrackerTimestampChunkData struct {
@@ -13,8 +14,16 @@ type DataTrackerTimestampChunk struct {
Data DataTrackerTimestampChunkData
}
func DecodeDataTrackerTimestampChunk(bytes []byte) DataTrackerTimestampChunk {
chunk := DecodeChunk(bytes)
func DecodeDataTrackerTimestampChunk(bytes []byte) (DataTrackerTimestampChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return DataTrackerTimestampChunk{}, err
}
if len(chunk.ChunkData) < 8 {
return DataTrackerTimestampChunk{}, errors.New("DATA_TRACKER_TIMESTAMP chunk must be at least 8 bytes")
}
timestamp := binary.LittleEndian.Uint64(chunk.ChunkData[0:8])
@@ -23,7 +32,8 @@ func DecodeDataTrackerTimestampChunk(bytes []byte) DataTrackerTimestampChunk {
}
return DataTrackerTimestampChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+12 -3
View File
@@ -2,6 +2,7 @@ package decoders
import (
"encoding/binary"
"errors"
"math"
)
@@ -16,8 +17,16 @@ type DataTrackerXYZChunk struct {
Data DataTrackerXYZChunkData
}
func DecodeDataTrackerXYZChunk(bytes []byte) DataTrackerXYZChunk {
chunk := DecodeChunk(bytes)
func DecodeDataTrackerXYZChunk(bytes []byte) (DataTrackerXYZChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return DataTrackerXYZChunk{}, err
}
if len(chunk.ChunkData) < 12 {
return DataTrackerXYZChunk{}, errors.New("DATA_TRACKER_XYZ chunk must be at least 12 bytes")
}
xBits := binary.LittleEndian.Uint32(chunk.ChunkData[0:4])
yBits := binary.LittleEndian.Uint32(chunk.ChunkData[4:8])
@@ -32,5 +41,5 @@ func DecodeDataTrackerXYZChunk(bytes []byte) DataTrackerXYZChunk {
return DataTrackerXYZChunk{
Chunk: chunk,
Data: data,
}
}, nil
}
+21 -8
View File
@@ -16,8 +16,11 @@ type InfoPacketChunk struct {
Data InfoPacketChunkData
}
func DecodeInfoPacketChunk(bytes []byte) InfoPacketChunk {
chunk := DecodeChunk(bytes)
func DecodeInfoPacketChunk(bytes []byte) (InfoPacketChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return InfoPacketChunk{}, err
}
data := InfoPacketChunkData{}
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
@@ -26,21 +29,30 @@ func DecodeInfoPacketChunk(bytes []byte) InfoPacketChunk {
for offset < int(chunk.Header.DataLen) {
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
case 0x0000:
packet_header := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
packet_header, err := DecodePacketHeaderChunk(chunk.ChunkData[offset:])
if err != nil {
return InfoPacketChunk{}, err
}
data.PacketHeader = &packet_header
offset += 4
if packet_header.Chunk.Header.DataLen > 0 {
offset = offset + int(packet_header.Chunk.Header.DataLen)
}
case 0x0001:
system_name := DecodeInfoSystemNameChunk(chunk.ChunkData[offset:])
system_name, err := DecodeInfoSystemNameChunk(chunk.ChunkData[offset:])
if err != nil {
return InfoPacketChunk{}, err
}
data.SystemName = &system_name
offset += 4
if system_name.Chunk.Header.DataLen > 0 {
offset = offset + int(system_name.Chunk.Header.DataLen)
}
case 0x0002:
tracker_list := DecodeInfoTrackerListChunk(chunk.ChunkData[offset:])
tracker_list, err := DecodeInfoTrackerListChunk(chunk.ChunkData[offset:])
if err != nil {
return InfoPacketChunk{}, err
}
data.TrackerList = &tracker_list
offset += 4
if tracker_list.Chunk.Header.DataLen > 0 {
@@ -54,7 +66,8 @@ func DecodeInfoPacketChunk(bytes []byte) InfoPacketChunk {
}
return InfoPacketChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+9 -6
View File
@@ -9,16 +9,19 @@ type InfoSystemNameChunk struct {
Data InfoSystemNameChunkData
}
func DecodeInfoSystemNameChunk(bytes []byte) InfoSystemNameChunk {
chunk := DecodeChunk(bytes)
system_name := string(chunk.ChunkData[0:chunk.Header.DataLen])
func DecodeInfoSystemNameChunk(bytes []byte) (InfoSystemNameChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return InfoSystemNameChunk{}, err
}
data := InfoSystemNameChunkData{}
data := InfoSystemNameChunkData{
SystemName: system_name,
if chunk.Header.DataLen > 0 {
data.SystemName = string(chunk.ChunkData[0:chunk.Header.DataLen])
}
return InfoSystemNameChunk{
Chunk: chunk,
Data: data,
}
}, nil
}
+13 -6
View File
@@ -14,8 +14,11 @@ type InfoTrackerChunk struct {
Data InfoTrackerChunkData
}
func DecodeInfoTrackerChunk(bytes []byte) InfoTrackerChunk {
chunk := DecodeChunk(bytes)
func DecodeInfoTrackerChunk(bytes []byte) (InfoTrackerChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return InfoTrackerChunk{}, err
}
data := InfoTrackerChunkData{}
if chunk.Header.HasSubchunks && chunk.ChunkData != nil && chunk.Header.DataLen > 0 {
@@ -24,7 +27,10 @@ func DecodeInfoTrackerChunk(bytes []byte) InfoTrackerChunk {
for offset < int(chunk.Header.DataLen) {
switch id := binary.LittleEndian.Uint16(chunk.ChunkData[offset : offset+2]); id {
case 0x0000:
tracker_name := DecodeInfoTrackerNameChunk(chunk.ChunkData[offset:])
tracker_name, err := DecodeInfoTrackerNameChunk(chunk.ChunkData[offset:])
if err != nil {
return InfoTrackerChunk{}, err
}
data.TrackerName = &tracker_name
offset += 4
if tracker_name.Chunk.Header.DataLen > 0 {
@@ -37,7 +43,8 @@ func DecodeInfoTrackerChunk(bytes []byte) InfoTrackerChunk {
}
return InfoTrackerChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+13 -6
View File
@@ -9,14 +9,20 @@ type InfoTrackerListChunk struct {
Data InfoTrackerListChunkData
}
func DecodeInfoTrackerListChunk(bytes []byte) InfoTrackerListChunk {
chunk := DecodeChunk(bytes)
func DecodeInfoTrackerListChunk(bytes []byte) (InfoTrackerListChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return InfoTrackerListChunk{}, err
}
trackers := []InfoTrackerChunk{}
if chunk.Header.HasSubchunks && chunk.Header.DataLen > 0 {
offset := 0
for offset < int(chunk.Header.DataLen) {
trackerChunk := DecodeInfoTrackerChunk(chunk.ChunkData[offset:])
trackerChunk, err := DecodeInfoTrackerChunk(chunk.ChunkData[offset:])
if err != nil {
return InfoTrackerListChunk{}, err
}
offset += 4
if trackerChunk.Chunk.Header.DataLen > 0 {
offset += int(trackerChunk.Chunk.Header.DataLen)
@@ -30,7 +36,8 @@ func DecodeInfoTrackerListChunk(bytes []byte) InfoTrackerListChunk {
}
return InfoTrackerListChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+13 -8
View File
@@ -9,17 +9,22 @@ type InfoTrackerNameChunk struct {
Data InfoTrackerNameChunkData
}
func DecodeInfoTrackerNameChunk(bytes []byte) InfoTrackerNameChunk {
chunk := DecodeChunk(bytes)
func DecodeInfoTrackerNameChunk(bytes []byte) (InfoTrackerNameChunk, error) {
chunk, err := DecodeChunk(bytes)
tracker_name := string(chunk.ChunkData[0:chunk.Header.DataLen])
if err != nil {
return InfoTrackerNameChunk{}, err
}
data := InfoTrackerNameChunkData{
TrackerName: tracker_name,
data := InfoTrackerNameChunkData{}
if chunk.Header.DataLen > 0 {
data.TrackerName = string(chunk.ChunkData[0:chunk.Header.DataLen])
}
return InfoTrackerNameChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}
+9 -5
View File
@@ -15,8 +15,11 @@ type PacketHeaderChunk struct {
Data PacketHeaderChunkData
}
func DecodePacketHeaderChunk(bytes []byte) PacketHeaderChunk {
chunk := DecodeChunk(bytes)
func DecodePacketHeaderChunk(bytes []byte) (PacketHeaderChunk, error) {
chunk, err := DecodeChunk(bytes)
if err != nil {
return PacketHeaderChunk{}, err
}
packet_timestamp := binary.LittleEndian.Uint64(chunk.ChunkData[0:8])
version_high := chunk.ChunkData[8]
@@ -33,7 +36,8 @@ func DecodePacketHeaderChunk(bytes []byte) PacketHeaderChunk {
}
return PacketHeaderChunk{
Chunk: chunk,
Data: data,
}
Chunk: chunk,
Data: data,
},
nil
}