PipeWire  0.3.29
x86_64-redhat-linux-gnu/doc/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 #include <errno.h>
26 #include <stdint.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include <spa/param/props.h>
32 #include <spa/pod/iter.h>
33 #include <spa/pod/builder.h>
34 #include <spa/pod/compare.h>
35 
41 /* static */ inline int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
42 {
43  void *val, *alt;
44  int i, nvals;
45  uint32_t type, size;
46 
47  nvals = SPA_POD_CHOICE_N_VALUES(choice);
48  type = SPA_POD_CHOICE_VALUE_TYPE(choice);
50  alt = val = SPA_POD_CHOICE_VALUES(choice);
51 
52  switch (choice->body.type) {
53  case SPA_CHOICE_None:
54  break;
55  case SPA_CHOICE_Range:
56  case SPA_CHOICE_Step:
57  if (nvals > 1) {
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  if (nvals > 2) {
63  alt = SPA_PTROFF(alt, size, void);
64  if (spa_pod_compare_value(type, val, alt, size) > 0)
65  memcpy(val, alt, size);
66  }
67  break;
68  case SPA_CHOICE_Flags:
69  case SPA_CHOICE_Enum:
70  {
71  void *best = NULL;
72 
73  for (i = 1; i < nvals; i++) {
74  alt = SPA_PTROFF(alt, size, void);
75  if (spa_pod_compare_value(type, val, alt, size) == 0) {
76  best = alt;
77  break;
78  }
79  if (best == NULL)
80  best = alt;
81  }
82  if (best)
83  memcpy(val, best, size);
84 
85  if (nvals <= 1)
86  choice->body.type = SPA_CHOICE_None;
87  break;
88  }
89  }
90  return 0;
91 }
92 
93 /* static */ inline int spa_pod_filter_flags_value(struct spa_pod_builder *b,
94  uint32_t type, const void *r1, const void *r2, uint32_t size)
95 {
96  switch (type) {
97  case SPA_TYPE_Int:
98  {
99  int32_t val = (*(int32_t *) r1) & (*(int32_t *) r2);
100  if (val == 0)
101  return 0;
102  spa_pod_builder_int(b, val);
103  break;
104  }
105  case SPA_TYPE_Long:
106  {
107  int64_t val = (*(int64_t *) r1) & (*(int64_t *) r2);
108  if (val == 0)
109  return 0;
110  spa_pod_builder_long(b, val);
111  break;
112  }
113  default:
114  return -ENOTSUP;
115  }
116  return 1;
117 }
118 
119 
120 /* static */ inline int
122  const struct spa_pod_prop *p1,
123  const struct spa_pod_prop *p2)
124 {
125  const struct spa_pod *v1, *v2;
126  struct spa_pod_choice *nc;
127  uint32_t j, k, nalt1, nalt2;
128  void *alt1, *alt2, *a1, *a2;
129  uint32_t type, size, p1c, p2c;
130  struct spa_pod_frame f;
131 
132  v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c);
133  alt1 = SPA_POD_BODY(v1);
134  v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
135  alt2 = SPA_POD_BODY(v2);
136 
137  type = v1->type;
138  size = v1->size;
139 
140  /* incompatible property types */
141  if (type != v2->type || size != v2->size || p1->key != p2->key)
142  return -EINVAL;
143 
144  if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) {
145  nalt1 = 1;
146  } else {
147  alt1 = SPA_PTROFF(alt1, size, void);
148  nalt1--;
149  }
150 
151  if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) {
152  nalt2 = 1;
153  } else {
154  alt2 = SPA_PTROFF(alt2, size, void);
155  nalt2--;
156  }
157 
158  /* start with copying the property */
159  spa_pod_builder_prop(b, p1->key, 0);
160  spa_pod_builder_push_choice(b, &f, 0, 0);
161  nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f);
162 
163  /* default value */
165 
166  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) ||
167  (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) ||
168  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) ||
169  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) {
170  int n_copied = 0;
171  /* copy all equal values but don't copy the default value again */
172  for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_PTROFF(a1, size, void)) {
173  for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
174  if (spa_pod_compare_value(type, a1, a2, size) == 0) {
175  if (p1c == SPA_CHOICE_Enum || j > 0)
176  spa_pod_builder_raw(b, a1, size);
177  n_copied++;
178  }
179  }
180  }
181  if (n_copied == 0)
182  return -EINVAL;
183  nc->body.type = SPA_CHOICE_Enum;
184  }
185 
186  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) ||
187  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) {
188  int n_copied = 0;
189  /* copy all values inside the range */
190  for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_PTROFF(a1,size,void)) {
191  if (spa_pod_compare_value(type, a1, a2, size) < 0)
192  continue;
193  if (spa_pod_compare_value(type, a1, SPA_PTROFF(a2,size,void), size) > 0)
194  continue;
195  spa_pod_builder_raw(b, a1, size);
196  n_copied++;
197  }
198  if (n_copied == 0)
199  return -EINVAL;
200  nc->body.type = SPA_CHOICE_Enum;
201  }
202 
203  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) ||
204  (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) {
205  return -ENOTSUP;
206  }
207 
208  if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) ||
209  (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) {
210  int n_copied = 0;
211  /* copy all values inside the range */
212  for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_PTROFF(a2,size,void)) {
213  if (spa_pod_compare_value(type, a2, a1, size) < 0)
214  continue;
215  if (spa_pod_compare_value(type, a2, SPA_PTROFF(a1,size,void), size) > 0)
216  continue;
217  spa_pod_builder_raw(b, a2, size);
218  n_copied++;
219  }
220  if (n_copied == 0)
221  return -EINVAL;
222  nc->body.type = SPA_CHOICE_Enum;
223  }
224 
225  if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) ||
226  (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) ||
227  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) ||
228  (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) {
229  if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
230  spa_pod_builder_raw(b, alt2, size);
231  else
232  spa_pod_builder_raw(b, alt1, size);
233 
234  alt1 = SPA_PTROFF(alt1,size,void);
235  alt2 = SPA_PTROFF(alt2,size,void);
236 
237  if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
238  spa_pod_builder_raw(b, alt1, size);
239  else
240  spa_pod_builder_raw(b, alt2, size);
241 
242  nc->body.type = SPA_CHOICE_Range;
243  }
244 
245  if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) ||
246  (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) ||
247  (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) {
248  if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1)
249  return -EINVAL;
250  nc->body.type = SPA_CHOICE_Flags;
251  }
252 
253  if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags)
254  return -ENOTSUP;
255 
256  if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags)
257  return -ENOTSUP;
258 
259  if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None)
260  return -ENOTSUP;
261  if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum)
262  return -ENOTSUP;
263  if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags)
264  return -ENOTSUP;
265 
266  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range)
267  return -ENOTSUP;
268  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step)
269  return -ENOTSUP;
270  if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum)
271  return -ENOTSUP;
272 
273  spa_pod_builder_pop(b, &f);
275 
276  return 0;
277 }
278 
279 /* static */ inline int spa_pod_filter_part(struct spa_pod_builder *b,
280  const struct spa_pod *pod, uint32_t pod_size,
281  const struct spa_pod *filter, uint32_t filter_size)
282 {
283  const struct spa_pod *pp, *pf;
284  int res = 0;
285 
286  pf = filter;
287 
288  SPA_POD_FOREACH(pod, pod_size, pp) {
289  bool do_copy = false, do_advance = false;
290  uint32_t filter_offset = 0;
291  struct spa_pod_frame f;
292 
293  switch (SPA_POD_TYPE(pp)) {
294  case SPA_TYPE_Object:
295  if (pf != NULL) {
296  struct spa_pod_object *op = (struct spa_pod_object *) pp;
297  struct spa_pod_object *of = (struct spa_pod_object *) pf;
298  const struct spa_pod_prop *p1, *p2;
299 
300  if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
301  return -EINVAL;
302 
303  spa_pod_builder_push_object(b, &f, op->body.type, op->body.id);
304  p2 = NULL;
305  SPA_POD_OBJECT_FOREACH(op, p1) {
306  p2 = spa_pod_object_find_prop(of, p2, p1->key);
307  if (p2 != NULL)
308  res = spa_pod_filter_prop(b, p1, p2);
309  else if ((p1->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
310  res = -EINVAL;
311  else
313  if (res < 0)
314  break;
315  }
316  if (res >= 0) {
317  p1 = NULL;
318  SPA_POD_OBJECT_FOREACH(of, p2) {
319  p1 = spa_pod_object_find_prop(op, p1, p2->key);
320  if (p1 != NULL)
321  continue;
322  if ((p2->flags & SPA_POD_PROP_FLAG_MANDATORY) != 0)
323  res = -EINVAL;
324  if (res < 0)
325  break;
327  }
328  }
329  spa_pod_builder_pop(b, &f);
330  do_advance = true;
331  }
332  else
333  do_copy = true;
334  break;
335 
336  case SPA_TYPE_Struct:
337  if (pf != NULL) {
338  if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
339  return -EINVAL;
340 
341  filter_offset = sizeof(struct spa_pod_struct);
344  SPA_PTROFF(pp,filter_offset,const struct spa_pod),
345  SPA_POD_SIZE(pp) - filter_offset,
346  SPA_PTROFF(pf,filter_offset,const struct spa_pod),
347  SPA_POD_SIZE(pf) - filter_offset);
348  spa_pod_builder_pop(b, &f);
349  do_advance = true;
350  }
351  else
352  do_copy = true;
353  break;
354 
355  default:
356  if (pf != NULL) {
357  if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf))
358  return -EINVAL;
359  if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0)
360  return -EINVAL;
361  do_advance = true;
362  }
363  do_copy = true;
364  break;
365  }
366  if (do_copy)
368  if (do_advance) {
369  pf = (const struct spa_pod*)spa_pod_next(pf);
370  if (!spa_pod_is_inside(filter, filter_size, pf))
371  pf = NULL;
372  }
373  if (res < 0)
374  break;
375  }
376  return res;
377 }
378 
379 /* static */ inline int
381  struct spa_pod **result,
382  const struct spa_pod *pod,
383  const struct spa_pod *filter)
384 {
385  int res;
386  struct spa_pod_builder_state state;
387 
388  spa_return_val_if_fail(pod != NULL, -EINVAL);
389  spa_return_val_if_fail(b != NULL, -EINVAL);
390 
391  spa_pod_builder_get_state(b, &state);
392  if (filter == NULL)
394  else
396 
397  if (res < 0) {
398  spa_pod_builder_reset(b, &state);
399  } else if (result) {
400  *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
401  if (*result == NULL)
402  res = -ENOSPC;
403  }
404  return res;
405 }
406 
Definition: pod/pod.h:199
#define SPA_POD_CHOICE_N_VALUES(choice)
Definition: pod/pod.h:137
int spa_pod_filter_flags_value(struct spa_pod_builder *b, uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: x86_64-redhat-linux-gnu/doc/spa/pod/filter.h:93
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:399
#define SPA_POD_PROP_SIZE(prop)
Definition: pod/pod.h:196
void * spa_pod_next(const void *iter)
Definition: iter.h:55
void spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:87
int spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:414
Definition: pod/pod.h:161
int spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:167
uint32_t type
one of enum spa_type
Definition: pod/pod.h:170
uint32_t id
id of the object, depends on the object type
Definition: pod/pod.h:171
int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
Definition: x86_64-redhat-linux-gnu/doc/spa/pod/filter.h:41
#define SPA_POD_OBJECT_FOREACH(obj, iter)
Definition: iter.h:123
flags: default, possible flags,...
Definition: pod/pod.h:145
Definition: iter.h:42
struct spa_pod_choice_body body
Definition: pod/pod.h:158
#define SPA_POD_PROP_FLAG_MANDATORY
is mandatory
Definition: pod/pod.h:213
int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: compare.h:48
static uint32_t int int res
Definition: core.h:328
#define SPA_POD_TYPE(pod)
Definition: pod/pod.h:41
uint32_t type
Definition: pod/pod.h:52
#define SPA_POD_CHOICE_VALUE_SIZE(choice)
Definition: pod/pod.h:136
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:426
bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
Definition: iter.h:49
int spa_pod_filter_prop(struct spa_pod_builder *b, const struct spa_pod_prop *p1, const struct spa_pod_prop *p2)
Definition: x86_64-redhat-linux-gnu/doc/spa/pod/filter.h:121
Definition: x86_64-redhat-linux-gnu/doc/spa/utils/type.h:49
int spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
Definition: builder.h:193
Definition: builder.h:46
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: x86_64-redhat-linux-gnu/doc/spa/pod/filter.h:279
void * spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:175
int spa_pod_filter(struct spa_pod_builder *b, struct spa_pod **result, const struct spa_pod *pod, const struct spa_pod *filter)
Definition: x86_64-redhat-linux-gnu/doc/spa/pod/filter.h:380
struct spa_pod * spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
Definition: builder.h:114
int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
Definition: builder.h:137
Definition: x86_64-redhat-linux-gnu/doc/spa/utils/type.h:59
struct spa_pod * spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
Definition: iter.h:362
Definition: x86_64-redhat-linux-gnu/doc/spa/utils/type.h:58
struct spa_pod_object_body body
Definition: pod/pod.h:177
#define SPA_POD_BODY(pod)
Definition: pod/pod.h:47
Definition: pod/pod.h:50
uint64_t size
This field is set by the user and the sum of all queued buffer is returned in the time info...
Definition: stream.h:178
no choice, first value is current
Definition: pod/pod.h:141
#define spa_return_val_if_fail(expr, val)
Definition: defs.h:248
list: default, alternative,...
Definition: pod/pod.h:144
range: default, min, max
Definition: pod/pod.h:142
struct spa_pod pod
Definition: pod/pod.h:157
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:403
struct spa_pod * spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
Definition: builder.h:102
Definition: pod/pod.h:175
Definition: x86_64-redhat-linux-gnu/doc/spa/utils/type.h:48
int spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
Definition: builder.h:441
range with step: default, min, max, step
Definition: pod/pod.h:143
Definition: filter.c:124
void spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
Definition: builder.h:74
int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
Definition: builder.h:257
Definition: builder.h:63
int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
Definition: builder.h:249
uint32_t key
key of property, list of valid keys depends on the object type
Definition: pod/pod.h:200
uint32_t size
Definition: pod/pod.h:51
struct spa_pod value
Definition: pod/pod.h:215
#define SPA_POD_CHOICE_VALUES(choice)
Definition: pod/pod.h:138
#define SPA_POD_SIZE(pod)
Definition: pod/pod.h:42
uint32_t offset
Definition: builder.h:47
uint32_t type
type of choice, one of enum spa_choice_type
Definition: pod/pod.h:149
#define SPA_PTROFF(ptr_, offset_, type_)
Return the address (buffer + offset) as pointer of type.
Definition: defs.h:158
uint32_t flags
flags for property
Definition: pod/pod.h:214
#define SPA_POD_FOREACH(pod, size, iter)
Definition: iter.h:110
#define SPA_POD_CHOICE_VALUE_TYPE(choice)
Definition: pod/pod.h:135
Definition: pod/pod.h:156