diff --git a/decoder.go b/decoder.go index aa28bef..59de0a8 100644 --- a/decoder.go +++ b/decoder.go @@ -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] diff --git a/internal/decoders/chunk.go b/internal/decoders/chunk.go index 60aba44..7b56d85 100644 --- a/internal/decoders/chunk.go +++ b/internal/decoders/chunk.go @@ -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 } diff --git a/internal/decoders/chunk_test.go b/internal/decoders/chunk_test.go index 8fd0a52..7e097cc 100644 --- a/internal/decoders/chunk_test.go +++ b/internal/decoders/chunk_test.go @@ -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) diff --git a/internal/decoders/data_packet_chunk.go b/internal/decoders/data_packet_chunk.go index a1e2602..9d30fc7 100644 --- a/internal/decoders/data_packet_chunk.go +++ b/internal/decoders/data_packet_chunk.go @@ -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 } diff --git a/internal/decoders/data_tracker_chunk.go b/internal/decoders/data_tracker_chunk.go index 038d5e9..3b042bb 100644 --- a/internal/decoders/data_tracker_chunk.go +++ b/internal/decoders/data_tracker_chunk.go @@ -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 = ×tamp 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 } diff --git a/internal/decoders/data_tracker_list_chunk.go b/internal/decoders/data_tracker_list_chunk.go index 2bbd0e1..097839c 100644 --- a/internal/decoders/data_tracker_list_chunk.go +++ b/internal/decoders/data_tracker_list_chunk.go @@ -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 } diff --git a/internal/decoders/data_tracker_status_chunk.go b/internal/decoders/data_tracker_status_chunk.go index 051f0d3..fb69c18 100644 --- a/internal/decoders/data_tracker_status_chunk.go +++ b/internal/decoders/data_tracker_status_chunk.go @@ -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 } diff --git a/internal/decoders/data_tracker_timestamp_chunk.go b/internal/decoders/data_tracker_timestamp_chunk.go index 28988ab..9d34636 100644 --- a/internal/decoders/data_tracker_timestamp_chunk.go +++ b/internal/decoders/data_tracker_timestamp_chunk.go @@ -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 } diff --git a/internal/decoders/data_tracker_xyz_chunk.go b/internal/decoders/data_tracker_xyz_chunk.go index 815a841..0d58e5d 100644 --- a/internal/decoders/data_tracker_xyz_chunk.go +++ b/internal/decoders/data_tracker_xyz_chunk.go @@ -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 } diff --git a/internal/decoders/info_packet_chunk.go b/internal/decoders/info_packet_chunk.go index b07c2a6..67bb352 100644 --- a/internal/decoders/info_packet_chunk.go +++ b/internal/decoders/info_packet_chunk.go @@ -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 } diff --git a/internal/decoders/info_system_name_chunk.go b/internal/decoders/info_system_name_chunk.go index df99254..15577d8 100644 --- a/internal/decoders/info_system_name_chunk.go +++ b/internal/decoders/info_system_name_chunk.go @@ -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 } diff --git a/internal/decoders/info_tracker_chunk.go b/internal/decoders/info_tracker_chunk.go index 67169eb..f1f18fb 100644 --- a/internal/decoders/info_tracker_chunk.go +++ b/internal/decoders/info_tracker_chunk.go @@ -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 } diff --git a/internal/decoders/info_tracker_list_chunk.go b/internal/decoders/info_tracker_list_chunk.go index 1a72cf7..b5a7df9 100644 --- a/internal/decoders/info_tracker_list_chunk.go +++ b/internal/decoders/info_tracker_list_chunk.go @@ -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 } diff --git a/internal/decoders/info_tracker_name_chunk.go b/internal/decoders/info_tracker_name_chunk.go index 70fcffb..7f55743 100644 --- a/internal/decoders/info_tracker_name_chunk.go +++ b/internal/decoders/info_tracker_name_chunk.go @@ -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 } diff --git a/internal/decoders/packet_header_chunk.go b/internal/decoders/packet_header_chunk.go index f34b99f..f41b948 100644 --- a/internal/decoders/packet_header_chunk.go +++ b/internal/decoders/packet_header_chunk.go @@ -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 }