diff --git a/spa/include/spa/debug/format.h b/spa/include/spa/debug/format.h index 571b4df20..874dd094a 100644 --- a/spa/include/spa/debug/format.h +++ b/spa/include/spa/debug/format.h @@ -7,7 +7,7 @@ #include -#include +#include #include #include #include diff --git a/spa/include/spa/param/audio/dsd-utils.h b/spa/include/spa/param/audio/dsd-utils.h index 5b93b7a8b..980bdf971 100644 --- a/spa/include/spa/param/audio/dsd-utils.h +++ b/spa/include/spa/param/audio/dsd-utils.h @@ -5,6 +5,7 @@ #ifndef SPA_AUDIO_DSD_UTILS_H #define SPA_AUDIO_DSD_UTILS_H +#include #include #include #include diff --git a/spa/include/spa/param/audio/raw-utils.h b/spa/include/spa/param/audio/raw-utils.h index d0a174e85..c36491445 100644 --- a/spa/include/spa/param/audio/raw-utils.h +++ b/spa/include/spa/param/audio/raw-utils.h @@ -6,6 +6,7 @@ #define SPA_AUDIO_RAW_UTILS_H #include +#include #include #include #include diff --git a/spa/include/spa/param/tag-utils.h b/spa/include/spa/param/tag-utils.h index 331def883..7d7fbb092 100644 --- a/spa/include/spa/param/tag-utils.h +++ b/spa/include/spa/param/tag-utils.h @@ -9,6 +9,7 @@ #include #include +#include #include #include diff --git a/spa/include/spa/param/video/dsp-utils.h b/spa/include/spa/param/video/dsp-utils.h index 338b21608..26018cab9 100644 --- a/spa/include/spa/param/video/dsp-utils.h +++ b/spa/include/spa/param/video/dsp-utils.h @@ -5,6 +5,7 @@ #ifndef SPA_VIDEO_DSP_UTILS_H #define SPA_VIDEO_DSP_UTILS_H +#include #include #include #include diff --git a/spa/include/spa/param/video/raw-utils.h b/spa/include/spa/param/video/raw-utils.h index 067cf32e5..738f64cf4 100644 --- a/spa/include/spa/param/video/raw-utils.h +++ b/spa/include/spa/param/video/raw-utils.h @@ -5,6 +5,7 @@ #ifndef SPA_VIDEO_RAW_UTILS_H #define SPA_VIDEO_RAW_UTILS_H +#include #include #include #include diff --git a/spa/include/spa/pod/body.h b/spa/include/spa/pod/body.h new file mode 100644 index 000000000..9ab2ae7e3 --- /dev/null +++ b/spa/include/spa/pod/body.h @@ -0,0 +1,392 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_POD_BODY_H +#define SPA_POD_BODY_H + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SPA_API_POD_BODY + #ifdef SPA_API_IMPL + #define SPA_API_POD_BODY SPA_API_IMPL + #else + #define SPA_API_POD_BODY static inline + #endif +#endif + +/** + * \addtogroup spa_pod + * \{ + */ + +struct spa_pod_frame { + struct spa_pod pod; + struct spa_pod_frame *parent; + uint32_t offset; + uint32_t flags; +}; + +SPA_API_POD_BODY uint32_t spa_pod_type_size(uint32_t type) +{ + switch (type) { + case SPA_TYPE_None: + case SPA_TYPE_Bytes: + case SPA_TYPE_Struct: + case SPA_TYPE_Pod: + return 0; + case SPA_TYPE_String: + return 1; + case SPA_TYPE_Bool: + case SPA_TYPE_Int: + return sizeof(int32_t); + case SPA_TYPE_Id: + return sizeof(uint32_t); + case SPA_TYPE_Long: + return sizeof(int64_t); + case SPA_TYPE_Float: + return sizeof(float); + case SPA_TYPE_Double: + return sizeof(double); + case SPA_TYPE_Rectangle: + return sizeof(struct spa_rectangle); + case SPA_TYPE_Fraction: + return sizeof(struct spa_fraction); + case SPA_TYPE_Bitmap: + return sizeof(uint8_t); + case SPA_TYPE_Array: + return sizeof(struct spa_pod_array_body); + case SPA_TYPE_Object: + return sizeof(struct spa_pod_object_body); + case SPA_TYPE_Sequence: + return sizeof(struct spa_pod_sequence_body); + case SPA_TYPE_Pointer: + return sizeof(struct spa_pod_pointer_body); + case SPA_TYPE_Fd: + return sizeof(int64_t); + case SPA_TYPE_Choice: + return sizeof(struct spa_pod_choice_body); + } + return 0; +} + +SPA_API_POD_BODY int spa_pod_body_from_data(void *data, size_t maxsize, off_t offset, size_t size, + struct spa_pod *pod, const void **body) +{ + if (offset < 0 || offset > (int64_t)UINT32_MAX) + return -EINVAL; + if (size < sizeof(struct spa_pod) || + size > maxsize || + maxsize - size < (uint32_t)offset) + return -EINVAL; + memcpy(pod, SPA_PTROFF(data, offset, void), sizeof(struct spa_pod)); + if (!SPA_POD_IS_VALID(pod)) + return -EINVAL; + if (pod->size > size - sizeof(struct spa_pod)) + return -EINVAL; + *body = SPA_PTROFF(data, offset + sizeof(struct spa_pod), void); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_none(const struct spa_pod *pod) +{ + return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_None); +} + +SPA_API_POD_BODY int spa_pod_is_bool(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Bool, sizeof(int32_t)); +} + +SPA_API_POD_BODY int spa_pod_body_get_bool(const struct spa_pod *pod, const void *body, bool *value) +{ + if (!spa_pod_is_bool(pod)) + return -EINVAL; + *value = !!*((int32_t*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_id(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Id, sizeof(uint32_t)); +} + +SPA_API_POD_BODY int spa_pod_body_get_id(const struct spa_pod *pod, const void *body, uint32_t *value) +{ + if (!spa_pod_is_id(pod)) + return -EINVAL; + *value = *((uint32_t*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_int(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Int, sizeof(int32_t)); +} + +SPA_API_POD_BODY int spa_pod_body_get_int(const struct spa_pod *pod, const void *body, int32_t *value) +{ + if (!spa_pod_is_int(pod)) + return -EINVAL; + *value = *((int32_t*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_long(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Long, sizeof(int64_t)); +} + +SPA_API_POD_BODY int spa_pod_body_get_long(const struct spa_pod *pod, const void *body, int64_t *value) +{ + if (!spa_pod_is_long(pod)) + return -EINVAL; + *value = *((int64_t*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_float(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Float, sizeof(float)); +} + +SPA_API_POD_BODY int spa_pod_body_get_float(const struct spa_pod *pod, const void *body, float *value) +{ + if (!spa_pod_is_float(pod)) + return -EINVAL; + *value = *((float*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_double(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Double, sizeof(double)); +} + +SPA_API_POD_BODY int spa_pod_body_get_double(const struct spa_pod *pod, const void *body, double *value) +{ + if (!spa_pod_is_double(pod)) + return -EINVAL; + *value = *((double*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_string(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_String, 1); +} + +SPA_API_POD_BODY int spa_pod_body_get_string(const struct spa_pod *pod, + const void *body, const char **value) +{ + const char *s; + if (!spa_pod_is_string(pod)) + return -EINVAL; + s = (const char *)body; + if (s[pod->size-1] != '\0') + return -EINVAL; + *value = s; + return 0; +} + +SPA_API_POD_BODY int spa_pod_body_copy_string(const struct spa_pod *pod, const void *body, + size_t maxlen, char *dest) +{ + const char *s; + if (spa_pod_body_get_string(pod, body, &s) < 0 || maxlen < 1) + return -EINVAL; + strncpy(dest, s, maxlen-1); + dest[maxlen-1]= '\0'; + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_bytes(const struct spa_pod *pod) +{ + return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_Bytes); +} + +SPA_API_POD_BODY int spa_pod_body_get_bytes(const struct spa_pod *pod, const void *body, + const void **value, uint32_t *len) +{ + if (!spa_pod_is_bytes(pod)) + return -EINVAL; + *value = (const void *)body; + *len = pod->size; + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_pointer(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Pointer, sizeof(struct spa_pod_pointer_body)); +} + +SPA_API_POD_BODY int spa_pod_body_get_pointer(const struct spa_pod *pod, const void *body, + uint32_t *type, const void **value) +{ + if (!spa_pod_is_pointer(pod)) + return -EINVAL; + *type = ((struct spa_pod_pointer_body*)body)->type; + *value = ((struct spa_pod_pointer_body*)body)->value; + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_fd(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Fd, sizeof(int64_t)); +} + +SPA_API_POD_BODY int spa_pod_body_get_fd(const struct spa_pod *pod, const void *body, + int64_t *value) +{ + if (!spa_pod_is_fd(pod)) + return -EINVAL; + *value = *((int64_t*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_rectangle(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Rectangle, sizeof(struct spa_rectangle)); +} + +SPA_API_POD_BODY int spa_pod_body_get_rectangle(const struct spa_pod *pod, const void *body, + struct spa_rectangle *value) +{ + if (!spa_pod_is_rectangle(pod)) + return -EINVAL; + *value = *((struct spa_rectangle*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_fraction(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Fraction, sizeof(struct spa_fraction)); +} +SPA_API_POD_BODY int spa_pod_body_get_fraction(const struct spa_pod *pod, const void *body, + struct spa_fraction *value) +{ + if (!spa_pod_is_fraction(pod)) + return -EINVAL; + *value = *((struct spa_fraction*)body); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_bitmap(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Bitmap, sizeof(uint8_t)); +} + +SPA_API_POD_BODY int spa_pod_is_array(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Array, sizeof(struct spa_pod_array_body)); +} +SPA_API_POD_BODY int spa_pod_body_get_array(const struct spa_pod *pod, const void *body, + struct spa_pod_array *arr, const void **arr_body) +{ + if (!spa_pod_is_array(pod)) + return -EINVAL; + arr->pod = *pod; + memcpy(&arr->body, body, sizeof(struct spa_pod_array_body)); + *arr_body = SPA_PTROFF(body, sizeof(struct spa_pod_array_body), void); + return 0; +} +SPA_API_POD_BODY const void *spa_pod_array_body_get_values(const struct spa_pod_array *arr, + const void *body, uint32_t *n_values, uint32_t *val_size, uint32_t *val_type) +{ + uint32_t child_size = arr->body.child.size; + *n_values = child_size ? (arr->pod.size - sizeof(arr->body)) / child_size : 0; + *val_size = child_size; + *val_type = arr->body.child.type; + return body; +} + +SPA_API_POD_BODY const void *spa_pod_body_get_array_values(const struct spa_pod *pod, + const void *body, uint32_t *n_values, uint32_t *val_size, uint32_t *val_type) +{ + struct spa_pod_array arr; + if (spa_pod_body_get_array(pod, body, &arr, &body) < 0) + return NULL; + return spa_pod_array_body_get_values(&arr, body, n_values, val_size, val_type); +} + +SPA_API_POD_BODY int spa_pod_is_choice(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Choice, sizeof(struct spa_pod_choice_body)); +} +SPA_API_POD_BODY int spa_pod_body_get_choice(const struct spa_pod *pod, const void *body, + struct spa_pod_choice *choice, const void **choice_body) +{ + if (!spa_pod_is_choice(pod)) + return -EINVAL; + choice->pod = *pod; + memcpy(&choice->body, body, sizeof(struct spa_pod_choice_body)); + if (choice->pod.size - sizeof(struct spa_pod_choice_body) < choice->body.child.size) + return -EINVAL; + *choice_body = SPA_PTROFF(body, sizeof(struct spa_pod_choice_body), void); + return 0; +} +SPA_API_POD_BODY const void *spa_pod_choice_body_get_values(const struct spa_pod_choice *pod, + const void *body, uint32_t *n_values, uint32_t *choice, + uint32_t *val_size, uint32_t *val_type) +{ + uint32_t child_size = pod->body.child.size; + *val_size = child_size; + *val_type = pod->body.child.type; + *n_values = child_size ? (pod->pod.size - sizeof(pod->body)) / child_size : 0; + *choice = pod->body.type; + if (*choice == SPA_CHOICE_None) + *n_values = SPA_MIN(1u, *n_values); + return body; +} + +SPA_API_POD_BODY int spa_pod_is_struct(const struct spa_pod *pod) +{ + return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_Struct); +} + +SPA_API_POD_BODY int spa_pod_is_object(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Object, sizeof(struct spa_pod_object_body)); +} +SPA_API_POD_BODY int spa_pod_body_get_object(const struct spa_pod *pod, const void *body, + struct spa_pod_object *object, const void **object_body) +{ + if (!spa_pod_is_object(pod)) + return -EINVAL; + object->pod = *pod; + memcpy(&object->body, body, sizeof(struct spa_pod_object_body)); + *object_body = SPA_PTROFF(body, sizeof(struct spa_pod_object_body), void); + return 0; +} + +SPA_API_POD_BODY int spa_pod_is_sequence(const struct spa_pod *pod) +{ + return SPA_POD_CHECK(pod, SPA_TYPE_Sequence, sizeof(struct spa_pod_sequence_body)); +} +SPA_API_POD_BODY int spa_pod_body_get_sequence(const struct spa_pod *pod, const void *body, + struct spa_pod_sequence *seq, const void **seq_body) +{ + if (!spa_pod_is_sequence(pod)) + return -EINVAL; + seq->pod = *pod; + memcpy(&seq->body, body, sizeof(struct spa_pod_sequence_body)); + *seq_body = SPA_PTROFF(body, sizeof(struct spa_pod_sequence_body), void); + return 0; +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_POD_BODY_H */ diff --git a/spa/include/spa/pod/builder.h b/spa/include/spa/pod/builder.h index b30e97b9e..225ca28b1 100644 --- a/spa/include/spa/pod/builder.h +++ b/spa/include/spa/pod/builder.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include #ifdef __cplusplus diff --git a/spa/include/spa/pod/iter.h b/spa/include/spa/pod/iter.h index cf65b8c62..d8a7c5b4e 100644 --- a/spa/include/spa/pod/iter.h +++ b/spa/include/spa/pod/iter.h @@ -9,6 +9,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -27,66 +28,6 @@ extern "C" { * \{ */ -struct spa_pod_frame { - struct spa_pod pod; - struct spa_pod_frame *parent; - uint32_t offset; - uint32_t flags; -}; - -#define SPA_POD_IS_VALID(pod) \ - (SPA_POD_BODY_SIZE(pod) < SPA_POD_MAX_SIZE) - -#define SPA_POD_CHECK_TYPE(pod,_type) \ - (SPA_POD_IS_VALID(pod) && \ - (pod)->type == (_type)) - -#define SPA_POD_CHECK(pod,_type,_size) \ - (SPA_POD_CHECK_TYPE(pod,_type) && (pod)->size >= (_size)) - -SPA_API_POD_ITER uint32_t spa_pod_type_size(uint32_t type) -{ - switch (type) { - case SPA_TYPE_None: - case SPA_TYPE_Bytes: - case SPA_TYPE_Struct: - case SPA_TYPE_Pod: - return 0; - case SPA_TYPE_String: - return 1; - case SPA_TYPE_Bool: - case SPA_TYPE_Int: - return sizeof(int32_t); - case SPA_TYPE_Id: - return sizeof(uint32_t); - case SPA_TYPE_Long: - return sizeof(int64_t); - case SPA_TYPE_Float: - return sizeof(float); - case SPA_TYPE_Double: - return sizeof(double); - case SPA_TYPE_Rectangle: - return sizeof(struct spa_rectangle); - case SPA_TYPE_Fraction: - return sizeof(struct spa_fraction); - case SPA_TYPE_Bitmap: - return sizeof(uint8_t); - case SPA_TYPE_Array: - return sizeof(struct spa_pod_array_body); - case SPA_TYPE_Object: - return sizeof(struct spa_pod_object_body); - case SPA_TYPE_Sequence: - return sizeof(struct spa_pod_sequence_body); - case SPA_TYPE_Pointer: - return sizeof(struct spa_pod_pointer_body); - case SPA_TYPE_Fd: - return sizeof(int64_t); - case SPA_TYPE_Choice: - return sizeof(struct spa_pod_choice_body); - } - return 0; -} - SPA_API_POD_ITER bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter) { size_t remaining; @@ -180,214 +121,82 @@ SPA_API_POD_ITER struct spa_pod_control *spa_pod_control_next(const struct spa_p SPA_API_POD_ITER void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size) { - void *pod; - if (offset < 0 || offset > (int64_t)UINT32_MAX) + struct spa_pod pod; + const void *body; + if (spa_pod_body_from_data(data, maxsize, offset, size, &pod, &body) < 0) return NULL; - if (size < sizeof(struct spa_pod) || - size > maxsize || - maxsize - size < (uint32_t)offset) - return NULL; - pod = SPA_PTROFF(data, offset, void); - if (!SPA_POD_IS_VALID(pod)) - return NULL; - if (SPA_POD_BODY_SIZE(pod) > size - sizeof(struct spa_pod)) - return NULL; - return pod; -} -SPA_API_POD_ITER int spa_pod_is_none(const struct spa_pod *pod) -{ - return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_None); -} - -SPA_API_POD_ITER int spa_pod_is_bool(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Bool, sizeof(int32_t)); + return SPA_PTROFF(data, offset, void); } SPA_API_POD_ITER int spa_pod_get_bool(const struct spa_pod *pod, bool *value) { - if (!spa_pod_is_bool(pod)) - return -EINVAL; - *value = !!SPA_POD_VALUE(struct spa_pod_bool, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_id(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Id, sizeof(uint32_t)); + return spa_pod_body_get_bool(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value) { - if (!spa_pod_is_id(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_id, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_int(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Int, sizeof(int32_t)); + return spa_pod_body_get_id(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_int(const struct spa_pod *pod, int32_t *value) { - if (!spa_pod_is_int(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_int, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_long(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Long, sizeof(int64_t)); + return spa_pod_body_get_int(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_long(const struct spa_pod *pod, int64_t *value) { - if (!spa_pod_is_long(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_long, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_float(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Float, sizeof(float)); + return spa_pod_body_get_long(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_float(const struct spa_pod *pod, float *value) { - if (!spa_pod_is_float(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_float, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_double(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Double, sizeof(double)); + return spa_pod_body_get_float(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_double(const struct spa_pod *pod, double *value) { - if (!spa_pod_is_double(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_double, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_string(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_String, 1); + return spa_pod_body_get_double(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_string(const struct spa_pod *pod, const char **value) { - const char *s; - if (!spa_pod_is_string(pod)) - return -EINVAL; - s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod); - if (s[pod->size-1] != '\0') - return -EINVAL; - *value = s; - return 0; + return spa_pod_body_get_string(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest) { - const char *s; - if (spa_pod_get_string(pod, &s) < 0 || maxlen < 1) - return -EINVAL; - strncpy(dest, s, maxlen-1); - dest[maxlen-1]= '\0'; - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_bytes(const struct spa_pod *pod) -{ - return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_Bytes); + return spa_pod_body_copy_string(pod, SPA_POD_BODY_CONST(pod), maxlen, dest); } SPA_API_POD_ITER int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len) { - if (!spa_pod_is_bytes(pod)) - return -EINVAL; - *value = (const void *)SPA_POD_CONTENTS(struct spa_pod_bytes, pod); - *len = pod->size; - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_pointer(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Pointer, sizeof(struct spa_pod_pointer_body)); + return spa_pod_body_get_bytes(pod, SPA_POD_BODY_CONST(pod), value, len); } SPA_API_POD_ITER int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value) { - if (!spa_pod_is_pointer(pod)) - return -EINVAL; - *type = ((struct spa_pod_pointer*)pod)->body.type; - *value = ((struct spa_pod_pointer*)pod)->body.value; - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_fd(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Fd, sizeof(int64_t)); + return spa_pod_body_get_pointer(pod, SPA_POD_BODY_CONST(pod), type, value); } SPA_API_POD_ITER int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value) { - if (!spa_pod_is_fd(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_fd, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_rectangle(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Rectangle, sizeof(struct spa_rectangle)); + return spa_pod_body_get_fd(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value) { - if (!spa_pod_is_rectangle(pod)) - return -EINVAL; - *value = SPA_POD_VALUE(struct spa_pod_rectangle, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_fraction(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Fraction, sizeof(struct spa_fraction)); + return spa_pod_body_get_rectangle(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value) { - spa_return_val_if_fail(spa_pod_is_fraction(pod), -EINVAL); - *value = SPA_POD_VALUE(struct spa_pod_fraction, pod); - return 0; -} - -SPA_API_POD_ITER int spa_pod_is_bitmap(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Bitmap, sizeof(uint8_t)); -} - -SPA_API_POD_ITER int spa_pod_is_array(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Array, sizeof(struct spa_pod_array_body)); + return spa_pod_body_get_fraction(pod, SPA_POD_BODY_CONST(pod), value); } SPA_API_POD_ITER void *spa_pod_get_array_full(const struct spa_pod *pod, uint32_t *n_values, uint32_t *val_size, uint32_t *val_type) { - spa_return_val_if_fail(spa_pod_is_array(pod), NULL); - *n_values = SPA_POD_ARRAY_N_VALUES(pod); - *val_size = SPA_POD_ARRAY_VALUE_SIZE(pod); - *val_type = SPA_POD_ARRAY_VALUE_TYPE(pod); - return SPA_POD_ARRAY_VALUES(pod); + return (void*)spa_pod_body_get_array_values(pod, SPA_POD_BODY(pod), n_values, val_size, val_type); } SPA_API_POD_ITER void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values) { @@ -399,7 +208,7 @@ SPA_API_POD_ITER uint32_t spa_pod_copy_array_full(const struct spa_pod *pod, uin uint32_t size, void *values, uint32_t max_values) { uint32_t n_values, val_size, val_type; - void *v = spa_pod_get_array_full(pod, &n_values, &val_size, &val_type); + const void *v = spa_pod_get_array_full(pod, &n_values, &val_size, &val_type); if (v == NULL || max_values == 0 || val_type != type || val_size != size) return 0; n_values = SPA_MIN(n_values, max_values); @@ -410,20 +219,20 @@ SPA_API_POD_ITER uint32_t spa_pod_copy_array_full(const struct spa_pod *pod, uin #define spa_pod_copy_array(pod,type,values,max_values) \ spa_pod_copy_array_full(pod,type,sizeof(values[0]),values,max_values) -SPA_API_POD_ITER int spa_pod_is_choice(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Choice, sizeof(struct spa_pod_choice_body)); -} - SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice) { if (spa_pod_is_choice(pod)) { - *n_vals = SPA_POD_CHOICE_N_VALUES(pod); - *choice = SPA_POD_CHOICE_TYPE(pod); - if (*choice == SPA_CHOICE_None) - *n_vals = SPA_MIN(1u, *n_vals); - return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod); + const struct spa_pod_choice *p = (const struct spa_pod_choice*)pod; + uint32_t type, size; + spa_pod_choice_body_get_values(p, SPA_POD_BODY_CONST(p), n_vals, choice, &size, &type); + return (struct spa_pod*)&p->body.child; + } else if (spa_pod_is_array(pod)) { + const struct spa_pod_array *p = (const struct spa_pod_array*)pod; + uint32_t type, size; + spa_pod_array_body_get_values(p, SPA_POD_BODY_CONST(p), n_vals, &size, &type); + *choice = SPA_CHOICE_None; + return (struct spa_pod*)&p->body.child; } else { *n_vals = 1; *choice = SPA_CHOICE_None; @@ -431,16 +240,6 @@ SPA_API_POD_ITER struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, } } -SPA_API_POD_ITER int spa_pod_is_struct(const struct spa_pod *pod) -{ - return SPA_POD_CHECK_TYPE(pod, SPA_TYPE_Struct); -} - -SPA_API_POD_ITER int spa_pod_is_object(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Object, sizeof(struct spa_pod_object_body)); -} - SPA_API_POD_ITER bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type) { return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_TYPE(pod) == type); @@ -451,11 +250,6 @@ SPA_API_POD_ITER bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t i return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_ID(pod) == id); } -SPA_API_POD_ITER int spa_pod_is_sequence(const struct spa_pod *pod) -{ - return SPA_POD_CHECK(pod, SPA_TYPE_Sequence, sizeof(struct spa_pod_sequence_body)); -} - SPA_API_POD_ITER const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod, const struct spa_pod_prop *start, uint32_t key) { @@ -535,4 +329,4 @@ SPA_API_POD_ITER int spa_pod_is_fixated(const struct spa_pod *pod) } /* extern "C" */ #endif -#endif /* SPA_POD_H */ +#endif /* SPA_POD_ITER_H */ diff --git a/spa/include/spa/pod/parser.h b/spa/include/spa/pod/parser.h index a76f2fef4..9c26e0f14 100644 --- a/spa/include/spa/pod/parser.h +++ b/spa/include/spa/pod/parser.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include #ifdef __cplusplus @@ -55,6 +55,22 @@ SPA_API_POD_PARSER void spa_pod_parser_pod(struct spa_pod_parser *parser, spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod)); } +SPA_API_POD_PARSER void spa_pod_parser_init_pod_body(struct spa_pod_parser *parser, + const struct spa_pod *pod, const void *body) +{ + spa_pod_parser_init(parser, + SPA_PTROFF(body, -sizeof(struct spa_pod), const struct spa_pod), + pod->size + sizeof(struct spa_pod)); +} +SPA_API_POD_PARSER void spa_pod_parser_init_from_data(struct spa_pod_parser *parser, + const void *data, uint32_t maxsize, uint32_t offset, uint32_t size) +{ + size_t offs, sz; + offs = SPA_MIN(offset, maxsize); + sz = SPA_MIN(maxsize - offs, size); + spa_pod_parser_init(parser, SPA_PTROFF(data, offs, void), sz); +} + SPA_API_POD_PARSER void spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state) { @@ -67,21 +83,32 @@ spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state parser->state = *state; } +SPA_API_POD_PARSER int +spa_pod_parser_read_header(struct spa_pod_parser *parser, uint32_t offset, uint32_t size, + void *header, uint32_t header_size, uint32_t pod_offset, const void **body) +{ + /* Cast to uint64_t to avoid wraparound. */ + const uint64_t long_offset = (uint64_t)offset + header_size; + if (long_offset <= size && (offset & 7) == 0) { + memcpy(header, SPA_PTROFF(parser->data, offset, void), header_size); + struct spa_pod *pod = SPA_PTROFF(header, pod_offset, struct spa_pod); + /* Check that the size (rounded to the next multiple of 8) is in bounds. */ + if (long_offset + SPA_ROUND_UP_N((uint64_t)pod->size, SPA_POD_ALIGN) <= size) { + *body = SPA_PTROFF(parser->data, long_offset, void); + return 0; + } + } + return -EPIPE; +} + SPA_API_POD_PARSER struct spa_pod * spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size) { - /* Cast to uint64_t to avoid wraparound. Add 8 for the pod itself. */ - const uint64_t long_offset = (uint64_t)offset + 8; - if (long_offset <= size && (offset & 7) == 0) { - /* Use void* because creating a misaligned pointer is undefined. */ - void *pod = SPA_PTROFF(parser->data, offset, void); - /* - * Check that the size (rounded to the next multiple of 8) is in bounds. - */ - if (long_offset + SPA_ROUND_UP_N((uint64_t)SPA_POD_BODY_SIZE(pod), SPA_POD_ALIGN) <= size) - return (struct spa_pod *)pod; - } - return NULL; + struct spa_pod pod; + const void *body; + if (spa_pod_parser_read_header(parser, offset, size, &pod, sizeof(pod), 0, &body) < 0) + return NULL; + return SPA_PTROFF(body, -sizeof(pod), struct spa_pod); } SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame) @@ -99,11 +126,28 @@ SPA_API_POD_PARSER void spa_pod_parser_push(struct spa_pod_parser *parser, parser->state.frame = frame; } -SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser) +SPA_API_POD_PARSER int spa_pod_parser_get_header(struct spa_pod_parser *parser, + void *header, uint32_t header_size, uint32_t pod_offset, const void **body) { struct spa_pod_frame *f = parser->state.frame; uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size; - return spa_pod_parser_deref(parser, parser->state.offset, size); + return spa_pod_parser_read_header(parser, parser->state.offset, size, + header, header_size, pod_offset, body); +} + +SPA_API_POD_PARSER int spa_pod_parser_current_body(struct spa_pod_parser *parser, + struct spa_pod *pod, const void **body) +{ + return spa_pod_parser_get_header(parser, pod, sizeof(struct spa_pod), 0, body); +} + +SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser) +{ + struct spa_pod pod; + const void *body; + if (spa_pod_parser_current_body(parser, &pod, &body) < 0) + return NULL; + return SPA_PTROFF(body, -sizeof(struct spa_pod), struct spa_pod); } SPA_API_POD_PARSER void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod) @@ -111,171 +155,351 @@ SPA_API_POD_PARSER void spa_pod_parser_advance(struct spa_pod_parser *parser, co parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), SPA_POD_ALIGN); } -SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser) +SPA_API_POD_PARSER int spa_pod_parser_next_body(struct spa_pod_parser *parser, + struct spa_pod *pod, const void **body) { - struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod) - spa_pod_parser_advance(parser, pod); - return pod; + if (spa_pod_parser_current_body(parser, pod, body) < 0) + return -EINVAL; + spa_pod_parser_advance(parser, pod); + return 0; } -SPA_API_POD_PARSER int spa_pod_parser_pop(struct spa_pod_parser *parser, +SPA_API_POD_PARSER struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser) +{ + struct spa_pod pod; + const void *body; + if (spa_pod_parser_current_body(parser, &pod, &body) < 0) + return NULL; + spa_pod_parser_advance(parser, &pod); + return SPA_PTROFF(body, -sizeof(struct spa_pod), struct spa_pod); +} + +SPA_API_POD_PARSER void spa_pod_parser_restart(struct spa_pod_parser *parser, struct spa_pod_frame *frame) { + parser->state.offset = frame->offset; +} + +SPA_API_POD_PARSER void spa_pod_parser_unpush(struct spa_pod_parser *parser, + struct spa_pod_frame *frame) +{ + spa_pod_parser_restart(parser, frame); parser->state.frame = frame->parent; - parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), SPA_POD_ALIGN); - return 0; +} + +SPA_API_POD_PARSER void spa_pod_parser_pop(struct spa_pod_parser *parser, + struct spa_pod_frame *frame) +{ + spa_pod_parser_unpush(parser, frame); + spa_pod_parser_advance(parser, &frame->pod); } SPA_API_POD_PARSER int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_bool(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_id(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_int(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_long(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_float(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_double(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_string(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_bytes(&pod, body, value, len)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_pointer(&pod, body, type, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_fd(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_rectangle(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } SPA_API_POD_PARSER int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value) { - int res = -EPIPE; - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0) - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_fraction(&pod, body, value)) >= 0) + spa_pod_parser_advance(parser, &pod); return res; } +SPA_API_POD_PARSER int spa_pod_parser_get_pod_body(struct spa_pod_parser *parser, + struct spa_pod *value, const void **body) +{ + int res; + if ((res = spa_pod_parser_current_body(parser, value, body)) < 0) + return res; + spa_pod_parser_advance(parser, value); + return 0; +} + SPA_API_POD_PARSER int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value) { - struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod == NULL) - return -EPIPE; - *value = pod; - spa_pod_parser_advance(parser, pod); + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_get_pod_body(parser, &pod, &body)) < 0) + return res; + *value = SPA_PTROFF(body, -sizeof(struct spa_pod), struct spa_pod); return 0; } -SPA_API_POD_PARSER int spa_pod_parser_push_struct(struct spa_pod_parser *parser, - struct spa_pod_frame *frame) + +SPA_API_POD_PARSER int spa_pod_parser_init_struct_body(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, const struct spa_pod *pod, const void *body) { - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod == NULL) - return -EPIPE; if (!spa_pod_is_struct(pod)) return -EINVAL; + spa_pod_parser_init_pod_body(parser, pod, body); spa_pod_parser_push(parser, frame, pod, parser->state.offset); parser->state.offset += sizeof(struct spa_pod_struct); return 0; } -SPA_API_POD_PARSER int spa_pod_parser_push_object(struct spa_pod_parser *parser, - struct spa_pod_frame *frame, uint32_t type, uint32_t *id) +SPA_API_POD_PARSER int spa_pod_parser_push_struct_body(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, struct spa_pod *str, const void **str_body) { - const struct spa_pod *pod = spa_pod_parser_current(parser); - if (pod == NULL) - return -EPIPE; + int res; + if ((res = spa_pod_parser_current_body(parser, str, str_body)) < 0) + return res; + if (!spa_pod_is_struct(str)) + return -EINVAL; + spa_pod_parser_push(parser, frame, str, parser->state.offset); + parser->state.offset += sizeof(struct spa_pod_struct); + return 0; +} +SPA_API_POD_PARSER int spa_pod_parser_push_struct(struct spa_pod_parser *parser, + struct spa_pod_frame *frame) +{ + struct spa_pod pod; + const void *body; + return spa_pod_parser_push_struct_body(parser, frame, &pod, &body); +} + +SPA_API_POD_PARSER int spa_pod_parser_init_object_body(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, const struct spa_pod *pod, const void *body, + struct spa_pod_object *object, const void **object_body) +{ + int res; if (!spa_pod_is_object(pod)) return -EINVAL; - if (type != SPA_POD_OBJECT_TYPE(pod)) - return -EPROTO; - if (id != NULL) - *id = SPA_POD_OBJECT_ID(pod); + spa_pod_parser_init_pod_body(parser, pod, body); + if ((res = spa_pod_body_get_object(pod, body, object, object_body)) < 0) + return res; spa_pod_parser_push(parser, frame, pod, parser->state.offset); - parser->state.offset = parser->size; + parser->state.offset += sizeof(struct spa_pod_object); return 0; } -SPA_API_POD_PARSER bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type) +SPA_API_POD_PARSER int spa_pod_parser_push_object_body(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, struct spa_pod_object *object, const void **object_body) { + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_object(&pod, body, object, object_body)) < 0) + return res; + spa_pod_parser_push(parser, frame, &pod, parser->state.offset); + parser->state.offset += sizeof(struct spa_pod_object); + return 0; +} +SPA_API_POD_PARSER int spa_pod_parser_push_object(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, uint32_t type, uint32_t *id) +{ + int res; + struct spa_pod_object obj; + const void *obj_body; + if ((res = spa_pod_parser_push_object_body(parser, frame, &obj, &obj_body)) < 0) + return res; + if (type != obj.body.type) { + spa_pod_parser_unpush(parser, frame); + return -EPROTO; + } + if (id != NULL) + *id = obj.body.id; + return 0; +} +SPA_API_POD_PARSER int spa_pod_parser_get_prop_body(struct spa_pod_parser *parser, + struct spa_pod_prop *prop, const void **body) +{ + int res; + if ((res = spa_pod_parser_get_header(parser, prop, + sizeof(struct spa_pod_prop), + offsetof(struct spa_pod_prop, value), body)) >= 0) + parser->state.offset += SPA_ROUND_UP_N(SPA_POD_PROP_SIZE(prop), SPA_POD_ALIGN); + return res; +} + +SPA_API_POD_PARSER int spa_pod_parser_push_sequence_body(struct spa_pod_parser *parser, + struct spa_pod_frame *frame, struct spa_pod_sequence *seq, const void **seq_body) +{ + int res; + struct spa_pod pod; + const void *body; + if ((res = spa_pod_parser_current_body(parser, &pod, &body)) < 0) + return res; + if ((res = spa_pod_body_get_sequence(&pod, body, seq, seq_body)) < 0) + return res; + spa_pod_parser_push(parser, frame, &pod, parser->state.offset); + parser->state.offset += sizeof(struct spa_pod_sequence); + return 0; +} + +SPA_API_POD_PARSER int spa_pod_parser_get_control_body(struct spa_pod_parser *parser, + struct spa_pod_control *control, const void **body) +{ + int res; + if ((res = spa_pod_parser_get_header(parser, control, + sizeof(struct spa_pod_control), + offsetof(struct spa_pod_control, value), body)) >= 0) + parser->state.offset += SPA_ROUND_UP_N(SPA_POD_CONTROL_SIZE(control), SPA_POD_ALIGN); + return res; +} + +SPA_API_POD_PARSER int spa_pod_parser_object_find_prop(struct spa_pod_parser *parser, + uint32_t key, struct spa_pod_prop *prop, const void **body) +{ + uint32_t start_offset; + struct spa_pod_frame *f = parser->state.frame; + + if (f == NULL || f->pod.type != SPA_TYPE_Object) + return -EINVAL; + + start_offset = f->offset; + while (spa_pod_parser_get_prop_body(parser, prop, body) >= 0) { + if (prop->key == key) + return 0; + } + spa_pod_parser_restart(parser, f); + parser->state.offset += sizeof(struct spa_pod_object); + while (parser->state.offset != start_offset && + spa_pod_parser_get_prop_body(parser, prop, body) >= 0) { + if (prop->key == key) + return 0; + } + return -ENOENT; +} + +SPA_API_POD_PARSER bool spa_pod_parser_body_can_collect(const struct spa_pod *pod, const void *body, char type) +{ + struct spa_pod_choice choice; + if (pod == NULL) return false; @@ -284,12 +508,11 @@ SPA_API_POD_PARSER bool spa_pod_parser_can_collect(const struct spa_pod *pod, ch return false; if (type == 'V') return true; - if (SPA_POD_CHOICE_TYPE(pod) != SPA_CHOICE_None) + if (spa_pod_body_get_choice(pod, body, &choice, &body) < 0) return false; - if (pod->size - sizeof(struct spa_pod_choice_body) < - SPA_POD_CHOICE_VALUE_SIZE(pod)) + if (choice.body.type != SPA_CHOICE_None) return false; - pod = SPA_POD_CHOICE_CHILD(pod); + pod = &choice.body.child; } switch (type) { @@ -334,72 +557,81 @@ SPA_API_POD_PARSER bool spa_pod_parser_can_collect(const struct spa_pod *pod, ch return false; } } +SPA_API_POD_PARSER bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type) +{ + return spa_pod_parser_body_can_collect(pod, SPA_POD_BODY_CONST(pod), type); +} -#define SPA_POD_PARSER_COLLECT(pod,_type,args) \ +#define SPA_POD_PARSER_COLLECT_BODY(pod,body,_type,args) \ do { \ switch (_type) { \ case 'b': \ - *va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod); \ + *va_arg(args, bool*) = !!*((int32_t*)(body)); \ break; \ case 'I': \ case 'i': \ - *va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod); \ + *va_arg(args, int32_t*) = *((int32_t*)(body)); \ break; \ case 'l': \ - *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod); \ + *va_arg(args, int64_t*) = *((int64_t*)(body)); \ break; \ case 'f': \ - *va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod); \ + *va_arg(args, float*) = *((float*)(body)); \ break; \ case 'd': \ - *va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod); \ + *va_arg(args, double*) = *((double*)(body)); \ break; \ case 's': \ - *va_arg(args, char**) = \ - ((pod) == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \ - ? NULL \ - : (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod)); \ + *va_arg(args, char**) = ((pod)->type == SPA_TYPE_None) ? \ + NULL : (char *)(body); \ break; \ case 'S': \ { \ char *dest = va_arg(args, char*); \ uint32_t maxlen = va_arg(args, uint32_t); \ - strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \ + maxlen = SPA_MIN(maxlen, (pod)->size); \ + strncpy(dest, (char *)(body), maxlen-1); \ dest[maxlen-1] = '\0'; \ break; \ } \ case 'y': \ - *(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \ - *(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \ + *(va_arg(args, void **)) = (void*)(body); \ + *(va_arg(args, uint32_t *)) = (pod)->size; \ break; \ case 'R': \ *va_arg(args, struct spa_rectangle*) = \ - SPA_POD_VALUE(struct spa_pod_rectangle, pod); \ + *((struct spa_rectangle*)(body)); \ break; \ case 'F': \ *va_arg(args, struct spa_fraction*) = \ - SPA_POD_VALUE(struct spa_pod_fraction, pod); \ + *((struct spa_fraction*)(body)); \ break; \ case 'B': \ - *va_arg(args, uint32_t **) = \ - (uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \ + *va_arg(args, uint32_t **) = (uint32_t*)(body); \ break; \ case 'a': \ - *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod); \ - *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod); \ - *va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod); \ - *va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod); \ + { \ + struct spa_pod_array_body *b = \ + (struct spa_pod_array_body*)(body); \ + uint32_t child_size = b->child.size; \ + *va_arg(args, uint32_t*) = child_size; \ + *va_arg(args, uint32_t*) = b->child.type; \ + *va_arg(args, uint32_t*) = child_size ? \ + ((pod)->size - sizeof(struct spa_pod_array_body))/child_size : 0; \ + *va_arg(args, void**) = SPA_PTROFF(b, \ + sizeof(struct spa_pod_array_body), void); \ break; \ + } \ case 'p': \ { \ struct spa_pod_pointer_body *b = \ - (struct spa_pod_pointer_body *) SPA_POD_BODY(pod); \ + (struct spa_pod_pointer_body *)(body); \ *(va_arg(args, uint32_t *)) = b->type; \ *(va_arg(args, const void **)) = b->value; \ break; \ } \ case 'h': \ - *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \ + *va_arg(args, int64_t*) = *((int64_t*)(body)); \ break; \ case 'P': \ case 'T': \ @@ -408,8 +640,8 @@ do { \ { \ const struct spa_pod **d = va_arg(args, const struct spa_pod**); \ if (d) \ - *d = ((pod) == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \ - ? NULL : (pod)); \ + *d = ((pod)->type == SPA_TYPE_None) ? \ + NULL : SPA_PTROFF((body), -sizeof(struct spa_pod), const struct spa_pod); \ break; \ } \ default: \ @@ -417,6 +649,9 @@ do { \ } \ } while(false) +#define SPA_POD_PARSER_COLLECT(pod,_type,args) \ + SPA_POD_PARSER_COLLECT_BODY(pod, SPA_POD_BODY_CONST(pod),_type,args) + #define SPA_POD_PARSER_SKIP(_type,args) \ do { \ switch (_type) { \ @@ -455,49 +690,58 @@ do { \ SPA_API_POD_PARSER int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args) { struct spa_pod_frame *f = parser->state.frame; - uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct; - const struct spa_pod_prop *prop = NULL; int count = 0; - do { - bool optional; - const struct spa_pod *pod = NULL; - const char *format; + if (f == NULL) + return -EINVAL; - if (f && ftype == SPA_TYPE_Object) { + do { + bool optional, have_pod = false; + struct spa_pod pod; + const void *body = NULL; + const char *format; + struct spa_pod_prop prop; + + if (f->pod.type == SPA_TYPE_Object) { uint32_t key = va_arg(args, uint32_t); - const struct spa_pod_object *object; if (key == 0) break; - object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f); - prop = spa_pod_object_find_prop(object, prop, key); - pod = prop ? &prop->value : NULL; + if (spa_pod_parser_object_find_prop(parser, key, &prop, &body) >= 0) { + pod = prop.value; + have_pod = true; + } } if ((format = va_arg(args, char *)) == NULL) break; - if (ftype == SPA_TYPE_Struct) - pod = spa_pod_parser_next(parser); + if (f->pod.type == SPA_TYPE_Struct) + if (spa_pod_parser_next_body(parser, &pod, &body) >= 0) + have_pod = true; if ((optional = (*format == '?'))) format++; - if (!spa_pod_parser_can_collect(pod, *format)) { + if (!have_pod || !spa_pod_parser_body_can_collect(&pod, body, *format)) { if (!optional) { - if (pod == NULL) + if (!have_pod) return -ESRCH; else return -EPROTO; } SPA_POD_PARSER_SKIP(*format, args); } else { - if (pod->type == SPA_TYPE_Choice && *format != 'V') - pod = SPA_POD_CHOICE_CHILD(pod); + struct spa_pod_choice choice; - SPA_POD_PARSER_COLLECT(pod, *format, args); + if (pod.type == SPA_TYPE_Choice && *format != 'V') { + if (spa_pod_body_get_choice(&pod, body, &choice, &body) < 0) + return -EINVAL; + pod = choice.body.child; + } + + SPA_POD_PARSER_COLLECT_BODY(&pod, body, *format, args); count++; } } while (true); diff --git a/spa/include/spa/pod/pod.h b/spa/include/spa/pod/pod.h index 4f87427da..3cd1aae49 100644 --- a/spa/include/spa/pod/pod.h +++ b/spa/include/spa/pod/pod.h @@ -30,6 +30,15 @@ extern "C" { #define SPA_POD_BODY(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),void) #define SPA_POD_BODY_CONST(pod) SPA_PTROFF((pod),sizeof(struct spa_pod),const void) +#define SPA_POD_IS_VALID(pod) \ + (SPA_POD_BODY_SIZE(pod) < SPA_POD_MAX_SIZE) +#define SPA_POD_CHECK_TYPE(pod,_type) \ + (SPA_POD_IS_VALID(pod) && \ + (pod)->type == (_type)) +#define SPA_POD_CHECK(pod,_type,_size) \ + (SPA_POD_CHECK_TYPE(pod,_type) && (pod)->size >= (_size)) + + struct spa_pod { uint32_t size; /* size of the body */ uint32_t type; /* a basic id of enum spa_type */ diff --git a/spa/lib/lib.c b/spa/lib/lib.c index 648fb82a1..165fc81ba 100644 --- a/spa/lib/lib.c +++ b/spa/lib/lib.c @@ -129,6 +129,7 @@ #include #include #include +#include #include #include #include diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index b9c8a7a7b..e6f7ff9d0 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 0917a7365..96e99f35e 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -26,7 +26,6 @@ #include #endif -#include #include #include #include diff --git a/src/pipewire/buffers.c b/src/pipewire/buffers.c index bef597a06..9ead5175a 100644 --- a/src/pipewire/buffers.c +++ b/src/pipewire/buffers.c @@ -3,7 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include -#include +#include #include #include #include diff --git a/src/tools/pw-profiler.c b/src/tools/pw-profiler.c index 38e34b68d..2115a0899 100644 --- a/src/tools/pw-profiler.c +++ b/src/tools/pw-profiler.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include