PipeWire  1.6.4
compare.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_COMPARE_H
6 #define SPA_POD_COMPARE_H
7 
8 #include <stdarg.h>
9 #include <errno.h>
10 #include <stdint.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <spa/param/props.h>
16 #include <spa/pod/iter.h>
17 #include <spa/pod/builder.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 #ifndef SPA_API_POD_COMPARE
24  #ifdef SPA_API_IMPL
25  #define SPA_API_POD_COMPARE SPA_API_IMPL
26  #else
27  #define SPA_API_POD_COMPARE static inline
28  #endif
29 #endif
30 
36 SPA_API_POD_COMPARE int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size)
37 {
38  switch (type) {
39  case SPA_TYPE_None:
40  return 0;
41  case SPA_TYPE_Bool:
42  return SPA_CMP(!!*(int32_t *)r1, !!*(int32_t *)r2);
44  return SPA_CMP(*(uint32_t *)r1, *(uint32_t *)r2);
45  case SPA_TYPE_Int:
46  return SPA_CMP(*(int32_t *)r1, *(int32_t *)r2);
47  case SPA_TYPE_Long:
48  return SPA_CMP(*(int64_t *)r1, *(int64_t *)r2);
49  case SPA_TYPE_Float:
50  return SPA_CMP(*(float *)r1, *(float *)r2);
51  case SPA_TYPE_Double:
52  return SPA_CMP(*(double *)r1, *(double *)r2);
53  case SPA_TYPE_String:
54  return strncmp((char *)r1, (char *)r2, size);
55  case SPA_TYPE_Rectangle:
56  {
57  const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1,
58  *rec2 = (struct spa_rectangle *) r2;
59  uint64_t a1, a2;
60  a1 = ((uint64_t) rec1->width) * rec1->height;
61  a2 = ((uint64_t) rec2->width) * rec2->height;
62  if (a1 < a2)
63  return -1;
64  if (a1 > a2)
65  return 1;
66  return SPA_CMP(rec1->width, rec2->width);
67  }
68  case SPA_TYPE_Fraction:
69  {
70  const struct spa_fraction *f1 = (struct spa_fraction *) r1,
71  *f2 = (struct spa_fraction *) r2;
72  uint64_t n1, n2;
73  n1 = ((uint64_t) f1->num) * f2->denom;
74  n2 = ((uint64_t) f2->num) * f1->denom;
75  return SPA_CMP(n1, n2);
76  }
77  default:
78  return memcmp(r1, r2, size);
79  }
80  return 0;
81 }
82 
83 SPA_API_POD_COMPARE int spa_pod_memcmp(const struct spa_pod *a,
84  const struct spa_pod *b)
85 {
86  return ((a == b) || (a && b && SPA_POD_SIZE(a) == SPA_POD_SIZE(b) &&
87  memcmp(a, b, SPA_POD_SIZE(b)) == 0)) ? 0 : 1;
88 }
89 
91  const struct spa_pod *pod2)
92 {
93  int res = 0;
94  uint32_t n_vals1, n_vals2;
95  uint32_t choice1, choice2;
96 
97  spa_return_val_if_fail(pod1 != NULL, -EINVAL);
98  spa_return_val_if_fail(pod2 != NULL, -EINVAL);
99 
100  pod1 = spa_pod_get_values(pod1, &n_vals1, &choice1);
101  pod2 = spa_pod_get_values(pod2, &n_vals2, &choice2);
102 
103  if (n_vals1 != n_vals2)
104  return -EINVAL;
105 
106  if (pod1->type != pod2->type)
107  return -EINVAL;
108 
109  if (n_vals1 < 1)
110  return -EINVAL; /* empty choice */
111 
112  switch (pod1->type) {
113  case SPA_TYPE_Struct:
114  {
115  const struct spa_pod *p1, *p2;
116  size_t p1s, p2s;
117 
118  p1 = (const struct spa_pod*)SPA_POD_BODY_CONST(pod1);
119  p1s = SPA_POD_BODY_SIZE(pod1);
120  p2 = (const struct spa_pod*)SPA_POD_BODY_CONST(pod2);
121  p2s = SPA_POD_BODY_SIZE(pod2);
122 
123  while (true) {
124  if (!spa_pod_is_inside(pod1, p1s, p1) ||
125  !spa_pod_is_inside(pod2, p2s, p2))
126  return -EINVAL;
127 
128  if ((res = spa_pod_compare(p1, p2)) != 0)
129  return res;
130 
131  p1 = (const struct spa_pod*)spa_pod_next(p1);
132  p2 = (const struct spa_pod*)spa_pod_next(p2);
133  }
134  break;
135  }
136  case SPA_TYPE_Object:
137  {
138  const struct spa_pod_prop *p1, *p2;
139  const struct spa_pod_object *o1, *o2;
140 
141  o1 = (const struct spa_pod_object*)pod1;
142  o2 = (const struct spa_pod_object*)pod2;
143 
144  p2 = NULL;
145  SPA_POD_OBJECT_FOREACH(o1, p1) {
146  if ((p2 = spa_pod_object_find_prop(o2, p2, p1->key)) == NULL)
147  return 1;
148  if ((res = spa_pod_compare(&p1->value, &p2->value)) != 0)
149  return res;
150  }
151  p1 = NULL;
152  SPA_POD_OBJECT_FOREACH(o2, p2) {
153  if ((p1 = spa_pod_object_find_prop(o1, p1, p2->key)) == NULL)
154  return -1;
155  }
156  break;
157  }
158  case SPA_TYPE_Array:
159  res = spa_pod_memcmp(pod1, pod2);
160  break;
161  default:
162  if (pod1->size != pod2->size)
163  return -EINVAL;
164  if (pod1->size < spa_pod_type_size(pod1->type))
165  return -EINVAL;
167  SPA_POD_BODY(pod1), SPA_POD_BODY(pod2),
168  pod1->size);
169  break;
170  }
171  return res;
172 }
173 
174 SPA_API_POD_COMPARE int spa_pod_compare_is_compatible_flags(uint32_t type, const void *r1,
175  const void *r2, uint32_t size SPA_UNUSED)
176 {
177  switch (type) {
178  case SPA_TYPE_Int:
179  return ((*(int32_t *) r1) & (*(int32_t *) r2)) != 0;
180  case SPA_TYPE_Long:
181  return ((*(int64_t *) r1) & (*(int64_t *) r2)) != 0;
182  default:
183  return -ENOTSUP;
184  }
185  return 0;
186 }
187 
188 
189 SPA_API_POD_COMPARE int spa_pod_compare_is_step_of(uint32_t type, const void *r1,
190  const void *r2, uint32_t size)
191 {
192  switch (type) {
193  case SPA_TYPE_Int:
194  if (*(int32_t *)r2 < 1)
195  return -EINVAL;
196  return *(int32_t *) r1 % *(int32_t *) r2 == 0;
197  case SPA_TYPE_Long:
198  if (*(int64_t *)r2 < 1)
199  return -EINVAL;
200  return *(int64_t *) r1 % *(int64_t *) r2 == 0;
201  case SPA_TYPE_Rectangle:
202  {
203  const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1,
204  *rec2 = (struct spa_rectangle *) r2;
205 
206  if (rec2->width < 1 || rec2->height < 1)
207  return -EINVAL;
208 
209  return (rec1->width % rec2->width == 0 &&
210  rec1->height % rec2->height == 0);
211  }
212  default:
213  return -ENOTSUP;
214  }
215  return 0;
216 }
217 
218 SPA_API_POD_COMPARE int spa_pod_compare_is_in_range(uint32_t type, const void *v,
219  const void *min, const void *max, const void *step, uint32_t size SPA_UNUSED)
220 {
221  if (spa_pod_compare_value(type, v, min, size) < 0 ||
222  spa_pod_compare_value(type, v, max, size) > 0)
223  return 0;
224  if (step != NULL)
225  return spa_pod_compare_is_step_of(type, v, step, size);
226  return 1;
227 }
228 
229 SPA_API_POD_COMPARE int spa_pod_compare_is_valid_choice(uint32_t type, uint32_t size,
230  const void *val, const void *vals, uint32_t n_vals, uint32_t choice)
231 {
232  switch (choice) {
233  case SPA_CHOICE_None:
234  if (spa_pod_compare_value(type, val, vals, size) == 0)
235  return 1;
236  return 0;
237  case SPA_CHOICE_Enum:
238  {
239  const void *next = vals;
240  for (uint32_t i = 1; i < n_vals; i++) {
241  next = SPA_PTROFF(next, size, void);
242  if (spa_pod_compare_value(type, val, next, size) == 0)
243  return 1;
244  }
245  return 0;
246  }
247  case SPA_CHOICE_Range:
248  case SPA_CHOICE_Step:
249  {
250  void *min = SPA_PTROFF(vals,size,void);
251  void *max = SPA_PTROFF(min,size,void);
252  void *step = choice == SPA_CHOICE_Step ? SPA_PTROFF(max,size,void) : NULL;
253  return spa_pod_compare_is_in_range(type, val, min, max, step, size);
254  }
255  case SPA_CHOICE_Flags:
256  return 1;
257  }
258  return 0;
259 }
260 
265 #ifdef __cplusplus
266 }
267 #endif
268 
269 #endif
spa/pod/builder.h
#define SPA_API_POD_COMPARE
Definition: compare.h:34
uint32_t int int res
Definition: core.h:433
SPA_API_POD_COMPARE int spa_pod_compare_is_in_range(uint32_t type, const void *v, const void *min, const void *max, const void *step, uint32_t size 1)
Definition: compare.h:225
SPA_API_POD_COMPARE int spa_pod_compare_is_step_of(uint32_t type, const void *r1, const void *r2, uint32_t size)
Definition: compare.h:196
#define SPA_POD_BODY_CONST(pod)
Definition: pod.h:46
SPA_API_POD_COMPARE int spa_pod_compare(const struct spa_pod *pod1, const struct spa_pod *pod2)
Definition: compare.h:97
SPA_API_POD_ITER void * spa_pod_next(const void *iter)
Definition: iter.h:46
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:229
SPA_API_POD_COMPARE int spa_pod_compare_is_valid_choice(uint32_t type, uint32_t size, const void *val, const void *vals, uint32_t n_vals, uint32_t choice)
Definition: compare.h:236
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:118
#define SPA_POD_BODY(pod)
Definition: pod.h:44
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:254
#define SPA_POD_BODY_SIZE(pod)
Definition: pod.h:31
SPA_API_POD_COMPARE int spa_pod_compare_is_compatible_flags(uint32_t type, const void *r1, const void *r2, uint32_t size 1)
Definition: compare.h:181
SPA_API_POD_BODY uint32_t spa_pod_type_size(uint32_t type)
Definition: body.h:45
SPA_API_POD_ITER bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
Definition: iter.h:38
#define SPA_POD_SIZE(pod)
Definition: pod.h:35
SPA_API_POD_COMPARE int spa_pod_memcmp(const struct spa_pod *a, const struct spa_pod *b)
Definition: compare.h:90
@ SPA_CHOICE_Step
range with step: default, min, max, step
Definition: pod.h:163
@ SPA_CHOICE_None
no choice, first value is current
Definition: pod.h:161
@ SPA_CHOICE_Flags
flags: first value is flags
Definition: pod.h:165
@ SPA_CHOICE_Range
range: default, min, max
Definition: pod.h:162
@ SPA_CHOICE_Enum
list: default, alternative,...
Definition: pod.h:164
@ SPA_TYPE_Int
Definition: type.h:45
@ SPA_TYPE_Rectangle
Definition: type.h:51
@ SPA_TYPE_Long
Definition: type.h:46
@ SPA_TYPE_Bool
Definition: type.h:43
@ SPA_TYPE_Object
Definition: type.h:56
@ SPA_TYPE_Float
Definition: type.h:47
@ SPA_TYPE_Fraction
Definition: type.h:52
@ SPA_TYPE_None
Definition: type.h:42
@ SPA_TYPE_Double
Definition: type.h:48
@ SPA_TYPE_Id
Definition: type.h:44
@ SPA_TYPE_Array
Definition: type.h:54
@ SPA_TYPE_String
Definition: type.h:49
@ SPA_TYPE_Struct
Definition: type.h:55
#define SPA_UNUSED
Definition: defs.h:309
#define spa_return_val_if_fail(expr, val)
Definition: defs.h:460
#define SPA_CMP(a, b)
3-way comparison.
Definition: defs.h:209
#define SPA_PTROFF(ptr_, offset_, type_)
Return the address (buffer + offset) as pointer of type.
Definition: defs.h:222
spa/pod/iter.h
spa/utils/string.h
Definition: defs.h:137
uint32_t num
Definition: defs.h:138
uint32_t denom
Definition: defs.h:139
Definition: pod.h:202
Definition: pod.h:227
uint32_t key
key of property, list of valid keys depends on the object type
Definition: pod.h:228
struct spa_pod value
Definition: pod.h:249
Definition: pod.h:57
uint32_t type
Definition: pod.h:59
uint32_t size
Definition: pod.h:58
Definition: defs.h:116
uint32_t width
Definition: defs.h:117
uint32_t height
Definition: defs.h:118