aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pipewire
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-11-25 04:08:52 +0900
committerOphestra <cat@gensokyo.uk>2025-11-25 04:08:52 +0900
commite51e81bb22a85f0324a80a32bb2b10f3a8616e17 (patch)
tree2c365fd2b44555d9c21ea70994aef831145cb06c /internal/pipewire
parent8f4a3bcf9f3d2dc0d8363b2f66ba41f5bc9f7c6a (diff)
internal/pipewire: implement spa_dict type
This is a terrible type that defies the type system. It is implemented on the concrete type to avoid special cases. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pipewire')
-rw-r--r--internal/pipewire/pod.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/internal/pipewire/pod.go b/internal/pipewire/pod.go
index 4ba4c6ca..6281913d 100644
--- a/internal/pipewire/pod.go
+++ b/internal/pipewire/pod.go
@@ -360,6 +360,74 @@ func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
return nil
}
+// SPADictItem is an encoding-compatible representation of spa_dict_item.
+type SPADictItem struct{ Key, Value string }
+
+// SPADict is an encoding-compatible representation of spa_dict.
+type SPADict struct {
+ NItems Int
+ Items []SPADictItem
+}
+
+func (d *SPADict) MarshalPOD() ([]byte, error) {
+ return appendInner(nil, func(data []byte) ([]byte, error) {
+ data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Struct)
+ if extraData, err := Marshal(d.NItems); err != nil {
+ return data, err
+ } else {
+ data = append(data, extraData...)
+ }
+ for i := range d.Items {
+ if extraData, err := Marshal(d.Items[i].Key); err != nil {
+ return data, err
+ } else {
+ data = append(data, extraData...)
+ }
+ if extraData, err := Marshal(d.Items[i].Value); err != nil {
+ return data, err
+ } else {
+ data = append(data, extraData...)
+ }
+ }
+ return data, nil
+ })
+}
+
+func (d *SPADict) UnmarshalPOD(data []byte) (Word, error) {
+ var wireSize Word
+ if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Struct, &wireSize); err != nil {
+ return wireSize, err
+ }
+
+ if size, err := Unmarshal(data, &d.NItems); err != nil {
+ return wireSize, err
+ } else {
+ // bounds check completed in successful call to Unmarshal
+ data = data[size:]
+ }
+
+ d.Items = make([]SPADictItem, d.NItems)
+ for i := range d.Items {
+ if size, err := Unmarshal(data, &d.Items[i].Key); err != nil {
+ return wireSize, err
+ } else {
+ // bounds check completed in successful call to Unmarshal
+ data = data[size:]
+ }
+ if size, err := Unmarshal(data, &d.Items[i].Value); err != nil {
+ return wireSize, err
+ } else {
+ // bounds check completed in successful call to Unmarshal
+ data = data[size:]
+ }
+ }
+
+ if len(data) != 0 {
+ return wireSize, &TrailingGarbageError{data}
+ }
+ return wireSize, nil
+}
+
/* Pointers */
const (
SPA_TYPE_POINTER_START = 0x10000 + iota