PipeWire  1.4.2
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
9 extern "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 
37 {
38  void *val, *alt;
39  int i, nvals;
40  uint32_t type, size;
41 
42  nvals = SPA_POD_CHOICE_N_VALUES(choice);
43  type = SPA_POD_CHOICE_VALUE_TYPE(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;
50  case SPA_CHOICE_Range:
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;
63  case SPA_CHOICE_Flags:
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 
114 SPA_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;
122  case SPA_TYPE_Rectangle:
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  alt1 = SPA_POD_BODY(v1);
150  v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
151  alt2 = SPA_POD_BODY(v2);
152 
153  type = v1->type;
154  size = v1->size;
155 
156  /* incompatible property types */
157  if (type != v2->type || size != v2->size || p1->key != p2->key)
158  return -EINVAL;
159 
160  if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) {
161  nalt1 = 1;
162  } else {
163  alt1 = SPA_PTROFF(alt1, size, void);
164  nalt1--;
165  }
166 
167  if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) {
168  nalt2 = 1;
169  } else {
170  alt2 = SPA_PTROFF(alt2, size, void);
171  nalt2--;
172  }
173 
174  /* start with copying the property */
175  spa_pod_builder_prop(b, p1->key, p1->flags & p2->flags);
176  spa_pod_builder_push_choice(b, &f, 0, 0);
177  nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f);
178  /* write to dummy value when builder overflows. We don't want to error
179  * because overflowing is a way to determine the required buffer size. */
180  if (nc == NULL)
181  nc = &dummy;
182 
183  /* default value */
185 
186  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) ||
187  (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) ||
188  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) ||
189  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) {
190  int n_copied = 0;
191  /* copy all equal values but don't copy the default value again */
192  for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) {
193  for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
194  if (spa_pod_compare_value(type, a1, a2, size) == 0) {
195  if (p1c == SPA_CHOICE_Enum || j > 0)
196  spa_pod_builder_raw(b, a1, size);
197  n_copied++;
198  }
199  }
200  }
201  if (n_copied == 0)
202  return -EINVAL;
203  nc->body.type = SPA_CHOICE_Enum;
204  }
205 
206  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) ||
207  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) {
208  int n_copied = 0;
209  /* copy all values inside the range */
210  for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
211  if (spa_pod_compare_value(type, a1, a2, size) < 0)
212  continue;
213  if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
214  continue;
215  spa_pod_builder_raw(b, a1, size);
216  n_copied++;
217  }
218  if (n_copied == 0)
219  return -EINVAL;
220  nc->body.type = SPA_CHOICE_Enum;
221  }
222 
223  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) ||
224  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) {
225  int n_copied = 0;
226  for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
227  int res;
228  if (spa_pod_compare_value(type, a1, a2, size) < 0)
229  continue;
230  if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
231  continue;
232 
233  res = spa_pod_filter_is_step_of(type, a1, SPA_PTROFF(a2,size*2,void), size);
234  if (res == 0)
235  continue;
236  if (res == -ENOTSUP)
237  return -EINVAL;
238 
239  spa_pod_builder_raw(b, a1, size);
240  n_copied++;
241  }
242  if (n_copied == 0)
243  return -EINVAL;
244  nc->body.type = SPA_CHOICE_Enum;
245  }
246 
247  if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) ||
248  (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) {
249  int n_copied = 0;
250  /* copy all values inside the range */
251  for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
252  if (spa_pod_compare_value(type, a2, a1, size) < 0)
253  continue;
254  if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
255  continue;
256  spa_pod_builder_raw(b, a2, size);
257  n_copied++;
258  }
259  if (n_copied == 0)
260  return -EINVAL;
261  nc->body.type = SPA_CHOICE_Enum;
262  }
263 
264  if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) ||
265  (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) ||
266  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) ||
267  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) {
268  if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
269  spa_pod_builder_raw(b, alt2, size);
270  else
271  spa_pod_builder_raw(b, alt1, size);
272 
273  alt1 = SPA_PTROFF(alt1,size,void);
274  alt2 = SPA_PTROFF(alt2,size,void);
275 
276  if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
277  spa_pod_builder_raw(b, alt1, size);
278  else
279  spa_pod_builder_raw(b, alt2, size);
280 
281  nc->body.type = SPA_CHOICE_Range;
282  }
283 
284  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) ||
285  (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) ||
286  (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) {
287  if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1)
288  return -EINVAL;
289  nc->body.type = SPA_CHOICE_Flags;
290  }
291 
292  if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags)
293  return -ENOTSUP;
294 
295  if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags)
296  return -ENOTSUP;
297 
298  if ((p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None) ||
299  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum)) {
300  int n_copied = 0;
301  for (j = 0, a1 = alt1, a2 = alt2; j < nalt2; j++, a2 = SPA_PTROFF(a1,size,void)) {
302  int res;
303  if (spa_pod_compare_value(type, a2, a1, size) < 0)
304  continue;
305  if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
306  continue;
307 
308  res = spa_pod_filter_is_step_of(type, a2, SPA_PTROFF(a1,size*2,void), size);
309  if (res == 0)
310  continue;
311  if (res == -ENOTSUP)
312  return -EINVAL;
313 
314  spa_pod_builder_raw(b, a2, size);
315  n_copied++;
316  }
317  if (n_copied == 0)
318  return -EINVAL;
319  nc->body.type = SPA_CHOICE_Enum;
320  }
321  if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags)
322  return -ENOTSUP;
323 
324  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range)
325  return -ENOTSUP;
326  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step)
327  return -ENOTSUP;
328  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum)
329  return -ENOTSUP;
330 
331  spa_pod_builder_pop(b, &f);
333 
334  return 0;
335 }
336 
338  const struct spa_pod *pod, uint32_t pod_size,
339  const struct spa_pod *filter, uint32_t filter_size)
340 {
341  const struct spa_pod *pp, *pf;
342  int res = 0;
343 
344  pf = filter;
345 
346  SPA_POD_FOREACH(pod, pod_size, pp) {
347  bool do_copy = false, do_advance = false;
348  uint32_t filter_offset = 0;
349  struct spa_pod_frame f;
350 
351  switch (SPA_POD_TYPE(pp)) {
352  case SPA_TYPE_Object:
353  if (pf != NULL) {
354  struct spa_pod_object *op = (struct spa_pod_object *) pp;
355  struct spa_pod_object *of = (struct spa_pod_object *) pf;
356  const struct spa_pod_prop *p1, *p2;
357 
358  if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
359  return -EINVAL;
360 
361  spa_pod_builder_push_object(b, &f, op->body.type, op->body.id);
362  p2 = NULL;
363  SPA_POD_OBJECT_FOREACH(op, p1) {
364  p2 = spa_pod_object_find_prop(of, p2, p1->key);
365  if (p2 != NULL)
366  res = spa_pod_filter_prop(b, p1, p2);
367  else if ((p1->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
368  res = -EINVAL;
369  else
371  if (res < 0)
372  break;
373  }
374  if (res >= 0) {
375  p1 = NULL;
376  SPA_POD_OBJECT_FOREACH(of, p2) {
377  p1 = spa_pod_object_find_prop(op, p1, p2->key);
378  if (p1 != NULL)
379  continue;
380  if ((p2->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
381  res = -EINVAL;
382  if (res < 0)
383  break;
385  }
386  }
387  spa_pod_builder_pop(b, &f);
388  do_advance = true;
389  }
390  else
391  do_copy = true;
392  break;
393 
394  case SPA_TYPE_Struct:
395  if (pf != NULL) {
396  if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
397  return -EINVAL;
398 
399  filter_offset = sizeof(struct spa_pod_struct);
402  SPA_PTROFF(pp,filter_offset,const struct spa_pod),
403  SPA_POD_SIZE(pp) - filter_offset,
404  SPA_PTROFF(pf,filter_offset,const struct spa_pod),
405  SPA_POD_SIZE(pf) - filter_offset);
406  spa_pod_builder_pop(b, &f);
407  do_advance = true;
408  }
409  else
410  do_copy = true;
411  break;
412 
413  default:
414  if (pf != NULL) {
415  if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf))
416  return -EINVAL;
417  if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0)
418  return -EINVAL;
419  do_advance = true;
420  }
421  do_copy = true;
422  break;
423  }
424  if (do_copy)
426  if (do_advance) {
427  pf = (const struct spa_pod*)spa_pod_next(pf);
428  if (!spa_pod_is_inside(filter, filter_size, pf))
429  pf = NULL;
430  }
431  if (res < 0)
432  break;
433  }
434  return res;
435 }
436 
439  struct spa_pod **result,
440  const struct spa_pod *pod,
441  const struct spa_pod *filter)
442 {
443  int res;
444  struct spa_pod_builder_state state;
445 
446  spa_return_val_if_fail(pod != NULL, -EINVAL);
447  spa_return_val_if_fail(b != NULL, -EINVAL);
448 
449  spa_pod_builder_get_state(b, &state);
450  if (filter == NULL)
452  else
453  res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter));
454 
455  if (res < 0) {
456  spa_pod_builder_reset(b, &state);
457  } else if (result) {
458  *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
459  if (*result == NULL)
460  res = -ENOSPC;
461  }
462  return res;
463 }
464 
469 #ifdef __cplusplus
470 } /* extern "C" */
471 #endif
472 
473 #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 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:425
#define SPA_POD_CHOICE_VALUE_TYPE(choice)
Definition: pod.h:138
SPA_API_POD_ITER void * spa_pod_next(const void *iter)
Definition: iter.h:52
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_BUILDER struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
Definition: builder.h:103
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 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_BUILDER int spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:441
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:454
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:445
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_BUILDER void * spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:187
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:344
#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:469
@ 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