PipeWire  0.3.66
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
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 
28 static 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;
33 
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;
42  case SPA_CHOICE_Range:
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;
55  case SPA_CHOICE_Flags:
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 
80 static 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;
97  spa_pod_builder_long(b, val);
98  break;
99  }
100  default:
101  return -ENOTSUP;
102  }
103  return 1;
104 }
105 
106 static 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;
114  case SPA_TYPE_Rectangle:
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 
128 static 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;
191  nc->body.type = SPA_CHOICE_Enum;
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;
208  nc->body.type = SPA_CHOICE_Enum;
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;
232  nc->body.type = SPA_CHOICE_Enum;
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;
249  nc->body.type = SPA_CHOICE_Enum;
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 
269  nc->body.type = SPA_CHOICE_Range;
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;
277  nc->body.type = SPA_CHOICE_Flags;
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;
307  nc->body.type = SPA_CHOICE_Enum;
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 
325 static 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 
349  spa_pod_builder_push_object(b, &f, op->body.type, op->body.id);
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 
425 static 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 struct spa_pod * spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
Definition: iter.h:347
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 void * spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:168
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
#define SPA_POD_OBJECT_FOREACH(obj, iter)
Definition: iter.h:108
#define SPA_POD_BODY(pod)
Definition: pod/pod.h:39
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 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
static void * spa_pod_next(const void *iter)
Definition: iter.h:40
#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_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:105
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 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
static struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
Definition: builder.h:93
@ 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:361
#define SPA_PTROFF(ptr_, offset_, type_)
Return the address (buffer + offset) as pointer of type.
Definition: defs.h:190
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:98
uint32_t width
Definition: defs.h:99
uint32_t height
Definition: defs.h:100