PipeWire 0.3.65
spa/include/spa/pod/filter.h
Go to the documentation of this file.
1/* Simple Plugin API
2 *
3 * Copyright © 2018 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef SPA_POD_FILTER_H
26#define SPA_POD_FILTER_H
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32#include <errno.h>
33#include <stdint.h>
34#include <stddef.h>
35#include <stdio.h>
36#include <string.h>
37
38#include <spa/param/props.h>
39#include <spa/pod/iter.h>
40#include <spa/pod/builder.h>
41#include <spa/pod/compare.h>
42
48static inline int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
49{
50 void *val, *alt;
51 int i, nvals;
52 uint32_t type, size;
54 nvals = SPA_POD_CHOICE_N_VALUES(choice);
55 type = SPA_POD_CHOICE_VALUE_TYPE(choice);
56 size = SPA_POD_CHOICE_VALUE_SIZE(choice);
57 alt = val = SPA_POD_CHOICE_VALUES(choice);
58
59 switch (choice->body.type) {
60 case SPA_CHOICE_None:
61 break;
63 case SPA_CHOICE_Step:
64 if (nvals > 1) {
65 alt = SPA_PTROFF(alt, size, void);
66 if (spa_pod_compare_value(type, val, alt, size) < 0)
67 memcpy(val, alt, size);
68 }
69 if (nvals > 2) {
70 alt = SPA_PTROFF(alt, size, void);
71 if (spa_pod_compare_value(type, val, alt, size) > 0)
72 memcpy(val, alt, size);
73 }
74 break;
76 case SPA_CHOICE_Enum:
77 {
78 void *best = NULL;
79
80 for (i = 1; i < nvals; i++) {
81 alt = SPA_PTROFF(alt, size, void);
82 if (spa_pod_compare_value(type, val, alt, size) == 0) {
83 best = alt;
84 break;
85 }
86 if (best == NULL)
87 best = alt;
88 }
89 if (best)
90 memcpy(val, best, size);
91
92 if (nvals <= 1)
93 choice->body.type = SPA_CHOICE_None;
94 break;
95 }
96 }
97 return 0;
98}
99
100static inline int spa_pod_filter_flags_value(struct spa_pod_builder *b,
101 uint32_t type, const void *r1, const void *r2, uint32_t size)
102{
103 switch (type) {
104 case SPA_TYPE_Int:
106 int32_t val = (*(int32_t *) r1) & (*(int32_t *) r2);
107 if (val == 0)
108 return 0;
109 spa_pod_builder_int(b, val);
110 break;
111 }
112 case SPA_TYPE_Long:
113 {
114 int64_t val = (*(int64_t *) r1) & (*(int64_t *) r2);
115 if (val == 0)
116 return 0;
117 spa_pod_builder_long(b, val);
118 break;
119 }
120 default:
121 return -ENOTSUP;
122 }
123 return 1;
124}
125
126static inline int spa_pod_filter_is_step_of(uint32_t type, const void *r1,
127 const void *r2, uint32_t size)
128{
129 switch (type) {
130 case SPA_TYPE_Int:
131 return *(int32_t *) r1 % *(int32_t *) r2 == 0;
132 case SPA_TYPE_Long:
133 return *(int64_t *) r1 % *(int64_t *) r2 == 0;
135 {
136 const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1,
137 *rec2 = (struct spa_rectangle *) r2;
138
139 return (rec1->width % rec2->width == 0 &&
140 rec1->height % rec2->height == 0);
141 }
142 default:
143 return -ENOTSUP;
144 }
145 return 0;
146}
147
148static inline int
150 const struct spa_pod_prop *p1,
151 const struct spa_pod_prop *p2)
152{
153 const struct spa_pod *v1, *v2;
154 struct spa_pod_choice *nc;
155 uint32_t j, k, nalt1, nalt2;
156 void *alt1, *alt2, *a1, *a2;
157 uint32_t type, size, p1c, p2c;
158 struct spa_pod_frame f;
159
160 v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c);
161 alt1 = SPA_POD_BODY(v1);
162 v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
163 alt2 = SPA_POD_BODY(v2);
164
165 type = v1->type;
166 size = v1->size;
167
168 /* incompatible property types */
169 if (type != v2->type || size != v2->size || p1->key != p2->key)
170 return -EINVAL;
171
172 if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) {
173 nalt1 = 1;
174 } else {
175 alt1 = SPA_PTROFF(alt1, size, void);
176 nalt1--;
177 }
178
179 if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) {
180 nalt2 = 1;
181 } else {
182 alt2 = SPA_PTROFF(alt2, size, void);
183 nalt2--;
184 }
185
186 /* start with copying the property */
187 spa_pod_builder_prop(b, p1->key, p1->flags & p2->flags);
188 spa_pod_builder_push_choice(b, &f, 0, 0);
189 nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f);
190
191 /* default value */
193
194 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) ||
195 (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) ||
196 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) ||
197 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) {
198 int n_copied = 0;
199 /* copy all equal values but don't copy the default value again */
200 for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) {
201 for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
202 if (spa_pod_compare_value(type, a1, a2, size) == 0) {
203 if (p1c == SPA_CHOICE_Enum || j > 0)
204 spa_pod_builder_raw(b, a1, size);
205 n_copied++;
206 }
207 }
208 }
209 if (n_copied == 0)
210 return -EINVAL;
212 }
213
214 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) ||
215 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) {
216 int n_copied = 0;
217 /* copy all values inside the range */
218 for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
219 if (spa_pod_compare_value(type, a1, a2, size) < 0)
220 continue;
221 if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
222 continue;
223 spa_pod_builder_raw(b, a1, size);
224 n_copied++;
225 }
226 if (n_copied == 0)
227 return -EINVAL;
229 }
230
231 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) ||
232 (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) {
233 int n_copied = 0;
234 for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
235 int res;
236 if (spa_pod_compare_value(type, a1, a2, size) < 0)
237 continue;
238 if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
239 continue;
240
241 res = spa_pod_filter_is_step_of(type, a1, SPA_PTROFF(a2,size*2,void), size);
242 if (res == 0)
243 continue;
244 if (res == -ENOTSUP)
245 return -EINVAL;
246
247 spa_pod_builder_raw(b, a1, size);
248 n_copied++;
249 }
250 if (n_copied == 0)
251 return -EINVAL;
253 }
254
255 if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) ||
256 (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) {
257 int n_copied = 0;
258 /* copy all values inside the range */
259 for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
260 if (spa_pod_compare_value(type, a2, a1, size) < 0)
261 continue;
262 if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
263 continue;
264 spa_pod_builder_raw(b, a2, size);
265 n_copied++;
266 }
267 if (n_copied == 0)
268 return -EINVAL;
270 }
271
272 if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) ||
273 (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) ||
274 (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) ||
275 (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) {
276 if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
277 spa_pod_builder_raw(b, alt2, size);
278 else
279 spa_pod_builder_raw(b, alt1, size);
280
281 alt1 = SPA_PTROFF(alt1,size,void);
282 alt2 = SPA_PTROFF(alt2,size,void);
283
284 if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
285 spa_pod_builder_raw(b, alt1, size);
286 else
287 spa_pod_builder_raw(b, alt2, size);
288
290 }
291
292 if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) ||
293 (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) ||
294 (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) {
295 if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1)
296 return -EINVAL;
298 }
299
300 if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags)
301 return -ENOTSUP;
302
303 if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags)
304 return -ENOTSUP;
305
306 if ((p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None) ||
307 (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum)) {
308 int n_copied = 0;
309 for (j = 0, a1 = alt1, a2 = alt2; j < nalt2; j++, a2 = SPA_PTROFF(a1,size,void)) {
310 int res;
311 if (spa_pod_compare_value(type, a2, a1, size) < 0)
312 continue;
313 if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
314 continue;
315
316 res = spa_pod_filter_is_step_of(type, a2, SPA_PTROFF(a1,size*2,void), size);
317 if (res == 0)
318 continue;
319 if (res == -ENOTSUP)
320 return -EINVAL;
321
322 spa_pod_builder_raw(b, a2, size);
323 n_copied++;
324 }
325 if (n_copied == 0)
326 return -EINVAL;
328 }
329 if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags)
330 return -ENOTSUP;
331
332 if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range)
333 return -ENOTSUP;
334 if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step)
335 return -ENOTSUP;
336 if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum)
337 return -ENOTSUP;
338
339 spa_pod_builder_pop(b, &f);
341
342 return 0;
343}
344
345static inline int spa_pod_filter_part(struct spa_pod_builder *b,
346 const struct spa_pod *pod, uint32_t pod_size,
347 const struct spa_pod *filter, uint32_t filter_size)
348{
349 const struct spa_pod *pp, *pf;
350 int res = 0;
351
352 pf = filter;
353
354 SPA_POD_FOREACH(pod, pod_size, pp) {
355 bool do_copy = false, do_advance = false;
356 uint32_t filter_offset = 0;
357 struct spa_pod_frame f;
358
359 switch (SPA_POD_TYPE(pp)) {
360 case SPA_TYPE_Object:
361 if (pf != NULL) {
362 struct spa_pod_object *op = (struct spa_pod_object *) pp;
363 struct spa_pod_object *of = (struct spa_pod_object *) pf;
364 const struct spa_pod_prop *p1, *p2;
365
366 if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
367 return -EINVAL;
368
370 p2 = NULL;
371 SPA_POD_OBJECT_FOREACH(op, p1) {
372 p2 = spa_pod_object_find_prop(of, p2, p1->key);
373 if (p2 != NULL)
374 res = spa_pod_filter_prop(b, p1, p2);
375 else if ((p1->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
376 res = -EINVAL;
377 else
379 if (res < 0)
380 break;
381 }
382 if (res >= 0) {
383 p1 = NULL;
384 SPA_POD_OBJECT_FOREACH(of, p2) {
385 p1 = spa_pod_object_find_prop(op, p1, p2->key);
386 if (p1 != NULL)
387 continue;
388 if ((p2->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
389 res = -EINVAL;
390 if (res < 0)
391 break;
393 }
394 }
395 spa_pod_builder_pop(b, &f);
396 do_advance = true;
397 }
398 else
399 do_copy = true;
400 break;
401
402 case SPA_TYPE_Struct:
403 if (pf != NULL) {
404 if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
405 return -EINVAL;
406
407 filter_offset = sizeof(struct spa_pod_struct);
409 res = spa_pod_filter_part(b,
410 SPA_PTROFF(pp,filter_offset,const struct spa_pod),
411 SPA_POD_SIZE(pp) - filter_offset,
412 SPA_PTROFF(pf,filter_offset,const struct spa_pod),
413 SPA_POD_SIZE(pf) - filter_offset);
414 spa_pod_builder_pop(b, &f);
415 do_advance = true;
416 }
417 else
418 do_copy = true;
419 break;
420
421 default:
422 if (pf != NULL) {
423 if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf))
424 return -EINVAL;
425 if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0)
426 return -EINVAL;
427 do_advance = true;
428 }
429 do_copy = true;
430 break;
431 }
432 if (do_copy)
434 if (do_advance) {
435 pf = (const struct spa_pod*)spa_pod_next(pf);
436 if (!spa_pod_is_inside(filter, filter_size, pf))
437 pf = NULL;
438 }
439 if (res < 0)
440 break;
441 }
442 return res;
443}
444
445static inline int
447 struct spa_pod **result,
448 const struct spa_pod *pod,
449 const struct spa_pod *filter)
450{
451 int res;
452 struct spa_pod_builder_state state;
453
454 spa_return_val_if_fail(pod != NULL, -EINVAL);
455 spa_return_val_if_fail(b != NULL, -EINVAL);
456
457 spa_pod_builder_get_state(b, &state);
458 if (filter == NULL)
459 res = spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod));
460 else
461 res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter));
462
463 if (res < 0) {
464 spa_pod_builder_reset(b, &state);
465 } else if (result) {
466 *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
467 if (*result == NULL)
468 res = -ENOSPC;
469 }
470 return res;
471}
472
477#ifdef __cplusplus
478} /* extern "C" */
479#endif
480
481#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:470
#define SPA_POD_CHOICE_VALUE_TYPE(choice)
Definition: pod/pod.h:158
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:105
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:408
static int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: compare.h:53
#define SPA_POD_PROP_FLAG_MANDATORY
is mandatory
Definition: pod/pod.h:242
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:131
#define SPA_POD_CHOICE_VALUE_SIZE(choice)
Definition: pod/pod.h:160
static void * spa_pod_next(const void *iter)
Definition: iter.h:60
#define SPA_POD_OBJECT_FOREACH(obj, iter)
Definition: iter.h:128
#define SPA_POD_BODY(pod)
Definition: pod/pod.h:59
static struct spa_pod * spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:125
static void spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:98
#define SPA_POD_TYPE(pod)
Definition: pod/pod.h:48
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:350
static int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
Definition: spa/include/spa/pod/filter.h:53
static int spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:180
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:154
static void * spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:188
static int spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
Definition: builder.h:206
static bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
Definition: iter.h:54
static int spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:442
static void spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:85
#define SPA_POD_FOREACH(pod, size, iter)
Definition: iter.h:115
#define SPA_POD_CHOICE_VALUES(choice)
Definition: pod/pod.h:164
#define SPA_POD_PROP_SIZE(prop)
Definition: pod/pod.h:225
static struct spa_pod * spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
Definition: iter.h:367
static int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:148
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:426
static int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
Definition: builder.h:267
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:455
static int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
Definition: builder.h:276
#define SPA_POD_CHOICE_N_VALUES(choice)
Definition: pod/pod.h:162
#define SPA_POD_SIZE(pod)
Definition: pod/pod.h:50
static struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
Definition: builder.h:113
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:451
@ SPA_CHOICE_Step
range with step: default, min, max, step
Definition: pod/pod.h:169
@ SPA_CHOICE_None
no choice, first value is current
Definition: pod/pod.h:167
@ SPA_CHOICE_Flags
flags: default, possible flags,...
Definition: pod/pod.h:171
@ SPA_CHOICE_Range
range: default, min, max
Definition: pod/pod.h:168
@ SPA_CHOICE_Enum
list: default, alternative,...
Definition: pod/pod.h:170
@ SPA_TYPE_Int
Definition: spa/include/spa/utils/type.h:54
@ SPA_TYPE_Rectangle
Definition: spa/include/spa/utils/type.h:60
@ SPA_TYPE_Long
Definition: spa/include/spa/utils/type.h:55
@ SPA_TYPE_Object
Definition: spa/include/spa/utils/type.h:65
@ SPA_TYPE_Struct
Definition: spa/include/spa/utils/type.h:64
#define spa_return_val_if_fail(expr, val)
Definition: defs.h:381
#define SPA_PTROFF(ptr_, offset_, type_)
Return the address (buffer + offset) as pointer of type.
Definition: defs.h:210
spa/pod/iter.h
spa/utils/string.h
Definition: builder.h:52
Definition: builder.h:73
uint32_t type
type of choice, one of enum spa_choice_type
Definition: pod/pod.h:175
Definition: pod/pod.h:182
struct spa_pod_choice_body body
Definition: pod/pod.h:184
struct spa_pod pod
Definition: pod/pod.h:183
Definition: iter.h:47
uint32_t type
one of enum spa_type
Definition: pod/pod.h:198
uint32_t id
id of the object, depends on the object type
Definition: pod/pod.h:199
Definition: pod/pod.h:203
struct spa_pod_object_body body
Definition: pod/pod.h:205
Definition: pod/pod.h:228
uint32_t key
key of property, list of valid keys depends on the object type
Definition: pod/pod.h:229
uint32_t flags
flags for property
Definition: pod/pod.h:245
struct spa_pod value
Definition: pod/pod.h:246
Definition: pod/pod.h:187
Definition: pod/pod.h:63
uint32_t type
Definition: pod/pod.h:65
uint32_t size
Definition: pod/pod.h:64
Definition: defs.h:118
uint32_t width
Definition: defs.h:119
uint32_t height
Definition: defs.h:120