diff --git a/internal/pipewire/pod.go b/internal/pipewire/pod.go index f8a824c..103154a 100644 --- a/internal/pipewire/pod.go +++ b/internal/pipewire/pod.go @@ -384,19 +384,16 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error { return nil case reflect.Pointer: - if len(data) < SizePrefix { - return ErrEOFPrefix - } - switch SPAKind(binary.NativeEndian.Uint32(data[SizeSPrefix:])) { - case SPA_TYPE_None: + if ok, err := unmarshalHandleNone(&data, wireSizeP); err != nil { + return err + } else if ok { v.SetZero() return nil - - default: - v.Set(reflect.New(v.Type().Elem())) - return unmarshalValue(data, v.Elem(), wireSizeP) } + v.Set(reflect.New(v.Type().Elem())) + return unmarshalValue(data, v.Elem(), wireSizeP) + case reflect.String: *wireSizeP = 0 if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_String, wireSizeP); err != nil { @@ -422,6 +419,29 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error { } } +// unmarshalHandleNone establishes prefix bounds and, for a value of type [SPA_TYPE_None], +// validates its size and skips the header. This is for unmarshalling values that can be nil. +func unmarshalHandleNone(data *[]byte, wireSizeP *Word) (bool, error) { + if len(*data) < SizePrefix { + return false, ErrEOFPrefix + } + + if SPAKind(binary.NativeEndian.Uint32((*data)[SizeSPrefix:])) != SPA_TYPE_None { + return false, nil + } + + *wireSizeP = 0 + if err := unmarshalCheckTypeBounds(data, SPA_TYPE_None, wireSizeP); err != nil { + return true, err + } + + if len(*data) != 0 { + return true, TrailingGarbageError(*data) + } + + return true, nil +} + // An InconsistentSizeError describes an inconsistent size prefix encountered // in data passed to [Unmarshal]. type InconsistentSizeError struct{ Prefix, Expect Word }