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