diff --git a/spa/include/spa/pod/builder.h b/spa/include/spa/pod/builder.h index 9ba3288f4..2957d41e7 100644 --- a/spa/include/spa/pod/builder.h +++ b/spa/include/spa/pod/builder.h @@ -168,6 +168,10 @@ static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct { struct spa_pod *pod; + if (SPA_FLAG_IS_SET(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST)) { + const struct spa_pod p = { 0, SPA_TYPE_None }; + spa_pod_builder_raw(builder, &p, sizeof(p)); + } if ((pod = (struct spa_pod*)spa_pod_builder_frame(builder, frame)) != NULL) *pod = frame->pod; @@ -209,6 +213,13 @@ static inline int spa_pod_builder_none(struct spa_pod_builder *builder) return spa_pod_builder_primitive(builder, &p); } +static inline int spa_pod_builder_child(struct spa_pod_builder *builder, uint32_t size, uint32_t type) +{ + const struct spa_pod p = SPA_POD_INIT(size,type); + SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST); + return spa_pod_builder_raw(builder, &p, sizeof(p)); +} + #define SPA_POD_INIT_Bool(val) (struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, val ? 1 : 0, 0 } static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val) diff --git a/spa/include/spa/pod/iter.h b/spa/include/spa/pod/iter.h index 0c6b87ccf..2a36d3fa6 100644 --- a/spa/include/spa/pod/iter.h +++ b/spa/include/spa/pod/iter.h @@ -357,8 +357,9 @@ static inline int spa_pod_is_choice(const struct spa_pod *pod) static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice) { if (pod->type == SPA_TYPE_Choice) { - *choice = SPA_POD_CHOICE_TYPE(pod); - *n_vals = *choice == SPA_CHOICE_None ? 1 : SPA_POD_CHOICE_N_VALUES(pod); + *n_vals = SPA_POD_CHOICE_N_VALUES(pod); + if ((*choice = SPA_POD_CHOICE_TYPE(pod)) == SPA_CHOICE_None) + *n_vals = SPA_MIN(1u, SPA_POD_CHOICE_N_VALUES(pod)); return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod); } else { *n_vals = 1; diff --git a/spa/include/spa/pod/pod.h b/spa/include/spa/pod/pod.h index 8033ae0c5..817b6b0ce 100644 --- a/spa/include/spa/pod/pod.h +++ b/spa/include/spa/pod/pod.h @@ -111,7 +111,7 @@ struct spa_pod_bitmap { #define SPA_POD_ARRAY_CHILD(arr) (&((struct spa_pod_array*)(arr))->body.child) #define SPA_POD_ARRAY_VALUE_TYPE(arr) (SPA_POD_TYPE(SPA_POD_ARRAY_CHILD(arr))) #define SPA_POD_ARRAY_VALUE_SIZE(arr) (SPA_POD_BODY_SIZE(SPA_POD_ARRAY_CHILD(arr))) -#define SPA_POD_ARRAY_N_VALUES(arr) ((SPA_POD_BODY_SIZE(arr) - sizeof(struct spa_pod_array_body)) / SPA_POD_ARRAY_VALUE_SIZE(arr)) +#define SPA_POD_ARRAY_N_VALUES(arr) (SPA_POD_ARRAY_VALUE_SIZE(arr) ? ((SPA_POD_BODY_SIZE(arr) - sizeof(struct spa_pod_array_body)) / SPA_POD_ARRAY_VALUE_SIZE(arr)) : 0) #define SPA_POD_ARRAY_VALUES(arr) SPA_POD_CONTENTS(struct spa_pod_array, arr) struct spa_pod_array_body { @@ -129,7 +129,7 @@ struct spa_pod_array { #define SPA_POD_CHOICE_FLAGS(choice) (((struct spa_pod_choice*)(choice))->body.flags) #define SPA_POD_CHOICE_VALUE_TYPE(choice) (SPA_POD_TYPE(SPA_POD_CHOICE_CHILD(choice))) #define SPA_POD_CHOICE_VALUE_SIZE(choice) (SPA_POD_BODY_SIZE(SPA_POD_CHOICE_CHILD(choice))) -#define SPA_POD_CHOICE_N_VALUES(choice) ((SPA_POD_BODY_SIZE(choice) - sizeof(struct spa_pod_choice_body)) / SPA_POD_CHOICE_VALUE_SIZE(choice)) +#define SPA_POD_CHOICE_N_VALUES(choice) (SPA_POD_CHOICE_VALUE_SIZE(choice) ? ((SPA_POD_BODY_SIZE(choice) - sizeof(struct spa_pod_choice_body)) / SPA_POD_CHOICE_VALUE_SIZE(choice)) : 0) #define SPA_POD_CHOICE_VALUES(choice) (SPA_POD_CONTENTS(struct spa_pod_choice, choice)) enum spa_choice_type { diff --git a/spa/tests/test-pod.c b/spa/tests/test-pod.c index c208374ed..80b7355e7 100644 --- a/spa/tests/test-pod.c +++ b/spa/tests/test-pod.c @@ -674,6 +674,72 @@ static void test_build(void) } } +static void test_empty(void) +{ + uint8_t buffer[4096]; + struct spa_pod_builder b; + struct spa_pod *array, *a2, *choice, *ch2; + struct spa_pod_frame f; + uint32_t n_vals, ch; + + /* create empty arrays */ + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_push_array(&b, &f) == 0); + spa_assert(spa_pod_builder_child(&b, sizeof(uint32_t), SPA_TYPE_Id) == 0); + spa_assert((array = spa_pod_builder_pop(&b, &f)) != NULL); + spa_debug_mem(0, array, 16); + spa_assert(spa_pod_is_array(array)); + spa_assert((a2 = spa_pod_get_array(array, &n_vals)) != NULL); + spa_assert(n_vals == 0); + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_push_array(&b, &f) == 0); + spa_assert((array = spa_pod_builder_pop(&b, &f)) != NULL); + spa_assert(spa_pod_is_array(array)); + spa_assert((a2 = spa_pod_get_array(array, &n_vals)) != NULL); + spa_assert(n_vals == 0); + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_push_array(&b, &f) == 0); + spa_assert(spa_pod_builder_none(&b) == 0); + spa_assert((array = spa_pod_builder_pop(&b, &f)) != NULL); + spa_assert(spa_pod_is_array(array)); + spa_assert((a2 = spa_pod_get_array(array, &n_vals)) != NULL); + spa_assert(n_vals == 0); + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_array(&b, 4, SPA_TYPE_Id, 0, NULL) == 0); + array = (struct spa_pod*)buffer; + spa_assert(spa_pod_is_array(array)); + spa_assert((a2 = spa_pod_get_array(array, &n_vals)) != NULL); + spa_assert(n_vals == 0); + + /* create empty choice */ + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_push_choice(&b, &f, 0, 0) == 0); + spa_assert(spa_pod_builder_child(&b, sizeof(uint32_t), SPA_TYPE_Id) == 0); + spa_assert((choice = spa_pod_builder_pop(&b, &f)) != NULL); + spa_debug_mem(0, choice, 32); + spa_assert(spa_pod_is_choice(choice)); + spa_assert((ch2 = spa_pod_get_values(choice, &n_vals, &ch)) != NULL); + spa_assert(n_vals == 0); + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_push_choice(&b, &f, 0, 0) == 0); + spa_assert((choice = spa_pod_builder_pop(&b, &f)) != NULL); + spa_assert(spa_pod_is_choice(choice)); + spa_assert((ch2 = spa_pod_get_values(choice, &n_vals, &ch)) != NULL); + spa_assert(n_vals == 0); + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_assert(spa_pod_builder_push_choice(&b, &f, 0, 0) == 0); + spa_assert(spa_pod_builder_none(&b) == 0); + spa_assert((choice = spa_pod_builder_pop(&b, &f)) != NULL); + spa_assert(spa_pod_is_choice(choice)); + spa_assert((ch2 = spa_pod_get_values(choice, &n_vals, &ch)) != NULL); + spa_assert(n_vals == 0); +} + static void test_varargs(void) { uint8_t buffer[4096]; @@ -1528,6 +1594,7 @@ int main(int argc, char *argv[]) { test_abi(); test_init(); + test_empty(); test_build(); test_varargs(); test_varargs2();