PipeWire 0.3.77
Loading...
Searching...
No Matches
spa/include/spa/pod/filter.h
Go to the documentation of this file.
1/* Simple Plugin API */
2/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
3/* SPDX-License-Identifier: MIT */
4
5#ifndef SPA_POD_FILTER_H
6#define SPA_POD_FILTER_H
7
8#ifdef __cplusplus
9extern "C" {
10#endif
11
12#include <errno.h>
13#include <stdint.h>
14#include <stddef.h>
15#include <stdio.h>
16#include <string.h>
17
18#include <spa/param/props.h>
19#include <spa/pod/iter.h>
20#include <spa/pod/builder.h>
21#include <spa/pod/compare.h>
22
28static inline int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
29{
30 void *val, *alt;
31 int i, nvals;
32 uint32_t type, size;
34 nvals = SPA_POD_CHOICE_N_VALUES(choice);
35 type = SPA_POD_CHOICE_VALUE_TYPE(choice);
36 size = SPA_POD_CHOICE_VALUE_SIZE(choice);
37 alt = val = SPA_POD_CHOICE_VALUES(choice);
38
39 switch (choice->body.type) {
40 case SPA_CHOICE_None:
41 break;
43 case SPA_CHOICE_Step:
44 if (nvals > 1) {
45 alt = SPA_PTROFF(alt, size, void);
46 if (spa_pod_compare_value(type, val, alt, size) < 0)
47 memcpy(val, alt, size);
48 }
49 if (nvals > 2) {
50 alt = SPA_PTROFF(alt, size, void);
51 if (spa_pod_compare_value(type, val, alt, size) > 0)
52 memcpy(val, alt, size);
53 }
54 break;
56 case SPA_CHOICE_Enum:
57 {
58 void *best = NULL;
59
60 for (i = 1; i < nvals; i++) {
61 alt = SPA_PTROFF(alt, size, void);
62 if (spa_pod_compare_value(type, val, alt, size) == 0) {
63 best = alt;
64 break;
65 }
66 if (best == NULL)
67 best = alt;
68 }
69 if (best)
70 memcpy(val, best, size);
71
72 if (nvals <= 1)
73 choice->body.type = SPA_CHOICE_None;
74 break;
75 }
76 }
77 return 0;
78}
79
80static inline int spa_pod_filter_flags_value(struct spa_pod_builder *b,
81 uint32_t type, const void *r1, const void *r2, uint32_t size)
82{
83 switch (type) {
84 case SPA_TYPE_Int:
85 {
86 int32_t val = (*(int32_t *) r1) & (*(int32_t *) r2);
87 if (val == 0)
88 return 0;
89 spa_pod_builder_int(b, val);
90 break;
91 }
92 case SPA_TYPE_Long:
93 {
94 int64_t val = (*(int64_t *) r1) & (*(int64_t *) r2);
95 if (val == 0)
96 return 0;
98 break;
99 }
100 default:
101 return -ENOTSUP;
102 }
103 return 1;
104}
105
106static inline int spa_pod_filter_is_step_of(uint32_t type, const void *r1,
107 const void *r2, uint32_t size)
108{
109 switch (type) {
110 case SPA_TYPE_Int:
111 return *(int32_t *) r1 % *(int32_t *) r2 == 0;
112 case SPA_TYPE_Long:
113 return *(int64_t *) r1 % *(int64_t *) r2 == 0;
115 {
116 const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1,
117 *rec2 = (struct spa_rectangle *) r2;
118
119 return (rec1->width % rec2->width == 0 &&
120 rec1->height % rec2->height == 0);
121 }
122 default:
123 return -ENOTSUP;
124 }
125 return 0;
126}
127
128static inline int
130 const struct spa_pod_prop *p1,
131 const struct spa_pod_prop *p2)
132{
133 const struct spa_pod *v1, *v2;
134 struct spa_pod_choice *nc;
135 uint32_t j, k, nalt1, nalt2;
136 void *alt1, *alt2, *a1, *a2;
137 uint32_t type, size, p1c, p2c;
138 struct spa_pod_frame f;
139
140 v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c);
141 alt1 = SPA_POD_BODY(v1);
142 v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
143 alt2 = SPA_POD_BODY(v2);
144
145 type = v1->type;
146 size = v1->size;
147
148 /* incompatible property types */
149 if (type != v2->type || size != v2->size || p1->key != p2->key)
150 return -EINVAL;
151
152 if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) {
153 nalt1 = 1;
154 } else {
155 alt1 = SPA_PTROFF(alt1, size, void);
156 nalt1--;
157 }
158
159 if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) {
160 nalt2 = 1;
161 } else {
162 alt2 = SPA_PTROFF(alt2, size, void);
163 nalt2--;
164 }
165
166 /* start with copying the property */
167 spa_pod_builder_prop(b, p1->key, p1->flags & p2->flags);
168 spa_pod_builder_push_choice(b, &f, 0, 0);
169 nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f);
170
171 /* default value */
173
174 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) ||
175 (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) ||
176 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) ||
177 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) {
178 int n_copied = 0;
179 /* copy all equal values but don't copy the default value again */
180 for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) {
181 for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
182 if (spa_pod_compare_value(type, a1, a2, size) == 0) {
183 if (p1c == SPA_CHOICE_Enum || j > 0)
184 spa_pod_builder_raw(b, a1, size);
185 n_copied++;
186 }
187 }
188 }
189 if (n_copied == 0)
190 return -EINVAL;
192 }
193
194 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) ||
195 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) {
196 int n_copied = 0;
197 /* copy all values inside the range */
198 for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
199 if (spa_pod_compare_value(type, a1, a2, size) < 0)
200 continue;
201 if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
202 continue;
203 spa_pod_builder_raw(b, a1, size);
204 n_copied++;
205 }
206 if (n_copied == 0)
207 return -EINVAL;
209 }
210
211 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) ||
212 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) {
213 int n_copied = 0;
214 for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
215 int res;
216 if (spa_pod_compare_value(type, a1, a2, size) < 0)
217 continue;
218 if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
219 continue;
220
221 res = spa_pod_filter_is_step_of(type, a1, SPA_PTROFF(a2,size*2,void), size);
222 if (res == 0)
223 continue;
224 if (res == -ENOTSUP)
225 return -EINVAL;
226
227 spa_pod_builder_raw(b, a1, size);
228 n_copied++;
229 }
230 if (n_copied == 0)
231 return -EINVAL;
233 }
234
235 if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) ||
236 (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) {
237 int n_copied = 0;
238 /* copy all values inside the range */
239 for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
240 if (spa_pod_compare_value(type, a2, a1, size) < 0)
241 continue;
242 if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
243 continue;
244 spa_pod_builder_raw(b, a2, size);
245 n_copied++;
246 }
247 if (n_copied == 0)
248 return -EINVAL;
250 }
251
252 if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) ||
253 (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) ||
254 (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) ||
255 (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) {
256 if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
257 spa_pod_builder_raw(b, alt2, size);
258 else
259 spa_pod_builder_raw(b, alt1, size);
260
261 alt1 = SPA_PTROFF(alt1,size,void);
262 alt2 = SPA_PTROFF(alt2,size,void);
263
264 if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
265 spa_pod_builder_raw(b, alt1, size);
266 else
267 spa_pod_builder_raw(b, alt2, size);
268
270 }
271
272 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) ||
273 (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) ||
274 (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) {
275 if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1)
276 return -EINVAL;
278 }
279
280 if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags)
281 return -ENOTSUP;
282
283 if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags)
284 return -ENOTSUP;
285
286 if ((p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None) ||
287 (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum)) {
288 int n_copied = 0;
289 for (j = 0, a1 = alt1, a2 = alt2; j < nalt2; j++, a2 = SPA_PTROFF(a1,size,void)) {
290 int res;
291 if (spa_pod_compare_value(type, a2, a1, size) < 0)
292 continue;
293 if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
294 continue;
295
296 res = spa_pod_filter_is_step_of(type, a2, SPA_PTROFF(a1,size*2,void), size);
297 if (res == 0)
298 continue;
299 if (res == -ENOTSUP)
300 return -EINVAL;
301
302 spa_pod_builder_raw(b, a2, size);
303 n_copied++;
304 }
305 if (n_copied == 0)
306 return -EINVAL;
308 }
309 if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags)
310 return -ENOTSUP;
311
312 if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range)
313 return -ENOTSUP;
314 if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step)
315 return -ENOTSUP;
316 if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum)
317 return -ENOTSUP;
318
319 spa_pod_builder_pop(b, &f);
321
322 return 0;
323}
324
325static inline int spa_pod_filter_part(struct spa_pod_builder *b,
326 const struct spa_pod *pod, uint32_t pod_size,
327 const struct spa_pod *filter, uint32_t filter_size)
328{
329 const struct spa_pod *pp, *pf;
330 int res = 0;
331
332 pf = filter;
333
334 SPA_POD_FOREACH(pod, pod_size, pp) {
335 bool do_copy = false, do_advance = false;
336 uint32_t filter_offset = 0;
337 struct spa_pod_frame f;
338
339 switch (SPA_POD_TYPE(pp)) {
340 case SPA_TYPE_Object:
341 if (pf != NULL) {
342 struct spa_pod_object *op = (struct spa_pod_object *) pp;
343 struct spa_pod_object *of = (struct spa_pod_object *) pf;
344 const struct spa_pod_prop *p1, *p2;
345
346 if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
347 return -EINVAL;
348
350 p2 = NULL;
351 SPA_POD_OBJECT_FOREACH(op, p1) {
352 p2 = spa_pod_object_find_prop(of, p2, p1->key);
353 if (p2 != NULL)
354 res = spa_pod_filter_prop(b, p1, p2);
355 else if ((p1->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
356 res = -EINVAL;
357 else
359 if (res < 0)
360 break;
361 }
362 if (res >= 0) {
363 p1 = NULL;
364 SPA_POD_OBJECT_FOREACH(of, p2) {
365 p1 = spa_pod_object_find_prop(op, p1, p2->key);
366 if (p1 != NULL)
367 continue;
368 if ((p2->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
369 res = -EINVAL;
370 if (res < 0)
371 break;
373 }
374 }
375 spa_pod_builder_pop(b, &f);
376 do_advance = true;
377 }
378 else
379 do_copy = true;
380 break;
381
382 case SPA_TYPE_Struct:
383 if (pf != NULL) {
384 if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
385 return -EINVAL;
386
387 filter_offset = sizeof(struct spa_pod_struct);
389 res = spa_pod_filter_part(b,
390 SPA_PTROFF(pp,filter_offset,const struct spa_pod),
391 SPA_POD_SIZE(pp) - filter_offset,
392 SPA_PTROFF(pf,filter_offset,const struct spa_pod),
393 SPA_POD_SIZE(pf) - filter_offset);
394 spa_pod_builder_pop(b, &f);
395 do_advance = true;
396 }
397 else
398 do_copy = true;
399 break;
400
401 default:
402 if (pf != NULL) {
403 if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf))
404 return -EINVAL;
405 if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0)
406 return -EINVAL;
407 do_advance = true;
408 }
409 do_copy = true;
410 break;
411 }
412 if (do_copy)
414 if (do_advance) {
415 pf = (const struct spa_pod*)spa_pod_next(pf);
416 if (!spa_pod_is_inside(filter, filter_size, pf))
417 pf = NULL;
418 }
419 if (res < 0)
420 break;
421 }
422 return res;
423}
424
425static inline int
427 struct spa_pod **result,
428 const struct spa_pod *pod,
429 const struct spa_pod *filter)
430{
431 int res;
432 struct spa_pod_builder_state state;
433
434 spa_return_val_if_fail(pod != NULL, -EINVAL);
435 spa_return_val_if_fail(b != NULL, -EINVAL);
436
437 spa_pod_builder_get_state(b, &state);
438 if (filter == NULL)
439 res = spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod));
440 else
441 res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter));
442
443 if (res < 0) {
444 spa_pod_builder_reset(b, &state);
445 } else if (result) {
446 *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
447 if (*result == NULL)
448 res = -ENOSPC;
449 }
450 return res;
451}
452
457#ifdef __cplusplus
458} /* extern "C" */
459#endif
460
461#endif /* SPA_POD_FILTER_H */
spa/pod/builder.h
spa/pod/compare.h
static int spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
Definition: builder.h:450
#define SPA_POD_CHOICE_VALUE_TYPE(choice)
Definition: pod/pod.h:138
static int spa_pod_filter_flags_value(struct spa_pod_builder *b, uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: spa/include/spa/pod/filter.h:85
static 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)
Definition: iter.h:388
static int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: compare.h:33
#define SPA_POD_PROP_FLAG_MANDATORY
is mandatory
Definition: pod/pod.h:222
static int spa_pod_filter_is_step_of(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: spa/include/spa/pod/filter.h:111
#define SPA_POD_CHOICE_VALUE_SIZE(choice)
Definition: pod/pod.h:140
static void * spa_pod_next(const void *iter)
Definition: iter.h:40
#define SPA_POD_OBJECT_FOREACH(obj, iter)
Definition: iter.h:108
#define SPA_POD_BODY(pod)
Definition: pod/pod.h:39
static struct spa_pod * spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:105
static void spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:78
#define SPA_POD_TYPE(pod)
Definition: pod/pod.h:28
static int spa_pod_filter_part(struct spa_pod_builder *b, const struct spa_pod *pod, uint32_t pod_size, const struct spa_pod *filter, uint32_t filter_size)
Definition: spa/include/spa/pod/filter.h:330
static int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
Definition: spa/include/spa/pod/filter.h:33
static int spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:160
static int spa_pod_filter_prop(struct spa_pod_builder *b, const struct spa_pod_prop *p1, const struct spa_pod_prop *p2)
Definition: spa/include/spa/pod/filter.h:134
static void * spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:168
static int spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
Definition: builder.h:186
static bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
Definition: iter.h:34
static int spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:422
static void spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:65
#define SPA_POD_FOREACH(pod, size, iter)
Definition: iter.h:95
#define SPA_POD_CHOICE_VALUES(choice)
Definition: pod/pod.h:144
#define SPA_POD_PROP_SIZE(prop)
Definition: pod/pod.h:205
static struct spa_pod * spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
Definition: iter.h:347
static int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:128
static int spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t type, uint32_t flags)
Definition: builder.h:406
static int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
Definition: builder.h:247
static int spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t type, uint32_t id)
Definition: builder.h:435
static int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
Definition: builder.h:256
#define SPA_POD_CHOICE_N_VALUES(choice)
Definition: pod/pod.h:142
#define SPA_POD_SIZE(pod)
Definition: pod/pod.h:30
static struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
Definition: builder.h:93
static int spa_pod_filter(struct spa_pod_builder *b, struct spa_pod **result, const struct spa_pod *pod, const struct spa_pod *filter)
Definition: spa/include/spa/pod/filter.h:431
@ SPA_CHOICE_Step
range with step: default, min, max, step
Definition: pod/pod.h:149
@ SPA_CHOICE_None
no choice, first value is current
Definition: pod/pod.h:147
@ SPA_CHOICE_Flags
flags: default, possible flags,...
Definition: pod/pod.h:151
@ SPA_CHOICE_Range
range: default, min, max
Definition: pod/pod.h:148
@ SPA_CHOICE_Enum
list: default, alternative,...
Definition: pod/pod.h:150
@ SPA_TYPE_Int
Definition: spa/include/spa/utils/type.h:34
@ SPA_TYPE_Rectangle
Definition: spa/include/spa/utils/type.h:40
@ SPA_TYPE_Long
Definition: spa/include/spa/utils/type.h:35
@ SPA_TYPE_Object
Definition: spa/include/spa/utils/type.h:45
@ SPA_TYPE_Struct
Definition: spa/include/spa/utils/type.h:44
#define spa_return_val_if_fail(expr, val)
Definition: defs.h:365
#define SPA_PTROFF(ptr_, offset_, type_)
Return the address (buffer + offset) as pointer of type.
Definition: defs.h:194
spa/pod/iter.h
spa/utils/string.h
Definition: builder.h:32
Definition: builder.h:53
uint32_t type
type of choice, one of enum spa_choice_type
Definition: pod/pod.h:155
Definition: pod/pod.h:162
struct spa_pod_choice_body body
Definition: pod/pod.h:164
struct spa_pod pod
Definition: pod/pod.h:163
Definition: iter.h:27
uint32_t type
one of enum spa_type
Definition: pod/pod.h:178
uint32_t id
id of the object, depends on the object type
Definition: pod/pod.h:179
Definition: pod/pod.h:183
struct spa_pod_object_body body
Definition: pod/pod.h:185
Definition: pod/pod.h:208
uint32_t key
key of property, list of valid keys depends on the object type
Definition: pod/pod.h:209
uint32_t flags
flags for property
Definition: pod/pod.h:225
struct spa_pod value
Definition: pod/pod.h:226
Definition: pod/pod.h:167
Definition: pod/pod.h:43
uint32_t type
Definition: pod/pod.h:45
uint32_t size
Definition: pod/pod.h:44
Definition: defs.h:102
uint32_t width
Definition: defs.h:103
uint32_t height
Definition: defs.h:104