internal/pipewire: define size constants
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 2m26s
Test / Hakurei (push) Successful in 3m17s
Test / Hpkg (push) Successful in 4m13s
Test / Sandbox (race detector) (push) Successful in 4m23s
Test / Hakurei (race detector) (push) Successful in 5m11s
Test / Flake checks (push) Successful in 1m26s
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 2m26s
Test / Hakurei (push) Successful in 3m17s
Test / Hpkg (push) Successful in 4m13s
Test / Sandbox (race detector) (push) Successful in 4m23s
Test / Hakurei (race detector) (push) Successful in 5m11s
Test / Flake checks (push) Successful in 1m26s
This gets rid of magic numbers in marshal/unmarshal. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
2698ca00e8
commit
2edcfe1e68
@ -6,8 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// HeaderSize is the fixed size of [Header].
|
// SizeHeader is the fixed size of [Header].
|
||||||
HeaderSize = 16
|
SizeHeader = 16
|
||||||
// SizeMax is the largest value of [Header.Size] that can be represented in its 3-byte segment.
|
// SizeMax is the largest value of [Header.Size] that can be represented in its 3-byte segment.
|
||||||
SizeMax = 0x00ffffff
|
SizeMax = 0x00ffffff
|
||||||
)
|
)
|
||||||
@ -50,11 +50,11 @@ func (h *Header) MarshalBinary() (data []byte, err error) {
|
|||||||
if h.Size&^SizeMax != 0 {
|
if h.Size&^SizeMax != 0 {
|
||||||
return nil, ErrSizeRange
|
return nil, ErrSizeRange
|
||||||
}
|
}
|
||||||
return h.append(make([]byte, 0, HeaderSize)), nil
|
return h.append(make([]byte, 0, SizeHeader)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshalBinary decodes the protocol native message header.
|
// unmarshalBinary decodes the protocol native message header.
|
||||||
func (h *Header) unmarshalBinary(data [HeaderSize]byte) {
|
func (h *Header) unmarshalBinary(data [SizeHeader]byte) {
|
||||||
h.ID = binary.NativeEndian.Uint32(data[0:4])
|
h.ID = binary.NativeEndian.Uint32(data[0:4])
|
||||||
h.Size = binary.NativeEndian.Uint32(data[4:8])
|
h.Size = binary.NativeEndian.Uint32(data[4:8])
|
||||||
h.Opcode = byte(h.Size >> 24)
|
h.Opcode = byte(h.Size >> 24)
|
||||||
@ -65,9 +65,9 @@ func (h *Header) unmarshalBinary(data [HeaderSize]byte) {
|
|||||||
|
|
||||||
// UnmarshalBinary decodes the protocol native message header.
|
// UnmarshalBinary decodes the protocol native message header.
|
||||||
func (h *Header) UnmarshalBinary(data []byte) error {
|
func (h *Header) UnmarshalBinary(data []byte) error {
|
||||||
if len(data) != HeaderSize {
|
if len(data) != SizeHeader {
|
||||||
return ErrBadHeader
|
return ErrBadHeader
|
||||||
}
|
}
|
||||||
h.unmarshalBinary(([HeaderSize]byte)(data))
|
h.unmarshalBinary(([SizeHeader]byte)(data))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,25 @@ type (
|
|||||||
Bytes = []byte
|
Bytes = []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SizeAlign is the boundary which POD starts are always aligned to.
|
||||||
|
SizeAlign = 8
|
||||||
|
|
||||||
|
// SizeSPrefix is the fixed, unpadded size of the fixed-size prefix encoding POD wire size.
|
||||||
|
SizeSPrefix = 4
|
||||||
|
// SizeTPrefix is the fixed, unpadded size of the fixed-size prefix encoding POD value type.
|
||||||
|
SizeTPrefix = 4
|
||||||
|
// SizePrefix is the fixed, unpadded size of the fixed-size POD prefix.
|
||||||
|
SizePrefix = SizeSPrefix + SizeTPrefix
|
||||||
|
|
||||||
|
// SizeId is the fixed, unpadded size of a [SPA_TYPE_Id] value.
|
||||||
|
SizeId = 4
|
||||||
|
// SizeInt is the fixed, unpadded size of a [SPA_TYPE_Int] value.
|
||||||
|
SizeInt = 4
|
||||||
|
// SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value.
|
||||||
|
SizeLong = 8
|
||||||
|
)
|
||||||
|
|
||||||
/* Basic types */
|
/* Basic types */
|
||||||
const (
|
const (
|
||||||
/* POD's can contain a number of basic SPA types: */
|
/* POD's can contain a number of basic SPA types: */
|
||||||
@ -98,21 +117,21 @@ func MarshalAppend(data []byte, v any) ([]byte, error) {
|
|||||||
// appendInner calls f and handles size prefix and padding around the appended data.
|
// appendInner calls f and handles size prefix and padding around the appended data.
|
||||||
// f must only append to data.
|
// f must only append to data.
|
||||||
func appendInner(data []byte, f func(data []byte) ([]byte, error)) ([]byte, error) {
|
func appendInner(data []byte, f func(data []byte) ([]byte, error)) ([]byte, error) {
|
||||||
data = append(data, make([]byte, 4)...)
|
data = append(data, make([]byte, SizeSPrefix)...)
|
||||||
|
|
||||||
rData, err := f(data)
|
rData, err := f(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
size := len(rData) - len(data) + 4
|
size := len(rData) - len(data) + SizeSPrefix
|
||||||
paddingSize := (8 - (size)%8) % 8
|
paddingSize := (SizeAlign - (size)%SizeAlign) % SizeAlign
|
||||||
// compensated for size and type prefix
|
// compensated for size and type prefix
|
||||||
wireSize := size - 8
|
wireSize := size - SizePrefix
|
||||||
if wireSize > math.MaxUint32 {
|
if wireSize > math.MaxUint32 {
|
||||||
return data, UnsupportedSizeError(wireSize)
|
return data, UnsupportedSizeError(wireSize)
|
||||||
}
|
}
|
||||||
binary.NativeEndian.PutUint32(rData[len(data)-4:len(data)], Word(wireSize))
|
binary.NativeEndian.PutUint32(rData[len(data)-SizeSPrefix:len(data)], Word(wireSize))
|
||||||
rData = append(rData, make([]byte, paddingSize)...)
|
rData = append(rData, make([]byte, paddingSize)...)
|
||||||
|
|
||||||
return rData, nil
|
return rData, nil
|
||||||
@ -223,7 +242,7 @@ func UnmarshalNext(data []byte, v any) (size Word, err error) {
|
|||||||
}
|
}
|
||||||
err = unmarshalValue(data, rv.Elem(), &size)
|
err = unmarshalValue(data, rv.Elem(), &size)
|
||||||
// prefix and padding size
|
// prefix and padding size
|
||||||
size += 8 + (8-(size)%8)%8
|
size += SizePrefix + (SizeAlign-(size)%SizeAlign)%SizeAlign
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +257,10 @@ func (u *UnmarshalSetError) Error() string { return "cannot set: " + u.Type.Stri
|
|||||||
type TrailingGarbageError struct{ Data []byte }
|
type TrailingGarbageError struct{ Data []byte }
|
||||||
|
|
||||||
func (e *TrailingGarbageError) Error() string {
|
func (e *TrailingGarbageError) Error() string {
|
||||||
if len(e.Data) < 8 {
|
if len(e.Data) < SizePrefix {
|
||||||
return "got " + strconv.Itoa(len(e.Data)) + " bytes of trailing garbage"
|
return "got " + strconv.Itoa(len(e.Data)) + " bytes of trailing garbage"
|
||||||
}
|
}
|
||||||
return "data has extra values starting with type " + strconv.Itoa(int(binary.NativeEndian.Uint32(e.Data[4:])))
|
return "data has extra values starting with type " + strconv.Itoa(int(binary.NativeEndian.Uint32(e.Data[SizeSPrefix:])))
|
||||||
}
|
}
|
||||||
|
|
||||||
// A StringTerminationError describes an incorrectly terminated string
|
// A StringTerminationError describes an incorrectly terminated string
|
||||||
@ -272,7 +291,7 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
|
|||||||
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Uint32:
|
case reflect.Uint32:
|
||||||
*wireSizeP = 4
|
*wireSizeP = SizeId
|
||||||
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Id, wireSizeP); err != nil {
|
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Id, wireSizeP); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -280,7 +299,7 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
case reflect.Int32:
|
case reflect.Int32:
|
||||||
*wireSizeP = 4
|
*wireSizeP = SizeInt
|
||||||
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, wireSizeP); err != nil {
|
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, wireSizeP); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -288,7 +307,7 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
*wireSizeP = 8
|
*wireSizeP = SizeLong
|
||||||
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Long, wireSizeP); err != nil {
|
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Long, wireSizeP); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -306,9 +325,9 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
|
|||||||
if err := unmarshalValue(data, v.Field(i), &fieldWireSize); err != nil {
|
if err := unmarshalValue(data, v.Field(i), &fieldWireSize); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
paddingSize := (8 - (fieldWireSize)%8) % 8
|
paddingSize := (SizeAlign - (fieldWireSize)%SizeAlign) % SizeAlign
|
||||||
// bounds check completed in successful call to unmarshalValue
|
// bounds check completed in successful call to unmarshalValue
|
||||||
data = data[8+fieldWireSize+paddingSize:]
|
data = data[SizePrefix+fieldWireSize+paddingSize:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
@ -317,10 +336,10 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
case reflect.Pointer:
|
case reflect.Pointer:
|
||||||
if len(data) < 8 {
|
if len(data) < SizePrefix {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
switch binary.NativeEndian.Uint32(data[4:]) {
|
switch binary.NativeEndian.Uint32(data[SizeSPrefix:]) {
|
||||||
case SPA_TYPE_None:
|
case SPA_TYPE_None:
|
||||||
v.SetZero()
|
v.SetZero()
|
||||||
return nil
|
return nil
|
||||||
@ -374,7 +393,7 @@ func (u *UnexpectedTypeError) Error() string {
|
|||||||
// unmarshalCheckTypeBounds performs bounds checks on data and validates the type and size prefixes.
|
// unmarshalCheckTypeBounds performs bounds checks on data and validates the type and size prefixes.
|
||||||
// An expected size of zero skips further bounds checks.
|
// An expected size of zero skips further bounds checks.
|
||||||
func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
|
func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
|
||||||
if len(*data) < 8 {
|
if len(*data) < SizePrefix {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,16 +404,16 @@ func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
|
|||||||
if wantSize != 0 && gotSize != wantSize {
|
if wantSize != 0 && gotSize != wantSize {
|
||||||
return &InconsistentSizeError{gotSize, wantSize}
|
return &InconsistentSizeError{gotSize, wantSize}
|
||||||
}
|
}
|
||||||
if len(*data)-8 < int(gotSize) {
|
if len(*data)-SizePrefix < int(gotSize) {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
gotType := binary.NativeEndian.Uint32((*data)[4:])
|
gotType := binary.NativeEndian.Uint32((*data)[SizeSPrefix:])
|
||||||
if gotType != t {
|
if gotType != t {
|
||||||
return &UnexpectedTypeError{gotType, t}
|
return &UnexpectedTypeError{gotType, t}
|
||||||
}
|
}
|
||||||
|
|
||||||
*data = (*data)[8 : gotSize+8]
|
*data = (*data)[SizePrefix : gotSize+SizePrefix]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user