Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2007 Lennart Poettering
5 : :
6 : : PulseAudio is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU Lesser General Public License as
8 : : published by the Free Software Foundation; either version 2.1 of the
9 : : License, or (at your option) any later version.
10 : :
11 : : PulseAudio is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : Lesser General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU Lesser General Public
17 : : License along with PulseAudio; if not, write to the Free Software
18 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 : : USA.
20 : : ***/
21 : :
22 : : #ifdef HAVE_CONFIG_H
23 : : #include <config.h>
24 : : #endif
25 : :
26 : : #include <string.h>
27 : : #include <ctype.h>
28 : :
29 : : #include <pulse/xmalloc.h>
30 : : #include <pulse/utf8.h>
31 : :
32 : : #include <pulsecore/hashmap.h>
33 : : #include <pulsecore/strbuf.h>
34 : : #include <pulsecore/core-util.h>
35 : :
36 : : #include "proplist.h"
37 : :
38 : : struct property {
39 : : char *key;
40 : : void *value;
41 : : size_t nbytes;
42 : : };
43 : :
44 : : #define MAKE_HASHMAP(p) ((pa_hashmap*) (p))
45 : : #define MAKE_PROPLIST(p) ((pa_proplist*) (p))
46 : :
47 : 110 : int pa_proplist_key_valid(const char *key) {
48 : :
49 [ + - ]: 110 : if (!pa_ascii_valid(key))
50 : : return 0;
51 : :
52 [ + - ]: 110 : if (strlen(key) <= 0)
53 : : return 0;
54 : :
55 : 110 : return 1;
56 : : }
57 : :
58 : 42 : static void property_free(struct property *prop) {
59 [ - + ]: 42 : pa_assert(prop);
60 : :
61 : 42 : pa_xfree(prop->key);
62 : 42 : pa_xfree(prop->value);
63 : 42 : pa_xfree(prop);
64 : 42 : }
65 : :
66 : 25 : pa_proplist* pa_proplist_new(void) {
67 : 25 : return MAKE_PROPLIST(pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func));
68 : : }
69 : :
70 : 25 : void pa_proplist_free(pa_proplist* p) {
71 [ - + ]: 25 : pa_assert(p);
72 : :
73 : 25 : pa_proplist_clear(p);
74 : 25 : pa_hashmap_free(MAKE_HASHMAP(p), NULL, NULL);
75 : 25 : }
76 : :
77 : : /** Will accept only valid UTF-8 */
78 : 21 : int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) {
79 : : struct property *prop;
80 : 21 : pa_bool_t add = FALSE;
81 : :
82 [ - + ]: 21 : pa_assert(p);
83 [ - + ]: 21 : pa_assert(key);
84 [ - + ]: 21 : pa_assert(value);
85 : :
86 [ + - ][ + - ]: 21 : if (!pa_proplist_key_valid(key) || !pa_utf8_valid(value))
87 : : return -1;
88 : :
89 [ + - ]: 21 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
90 : 21 : prop = pa_xnew(struct property, 1);
91 : 21 : prop->key = pa_xstrdup(key);
92 : 21 : add = TRUE;
93 : : } else
94 : 0 : pa_xfree(prop->value);
95 : :
96 : 21 : prop->value = pa_xstrdup(value);
97 : 21 : prop->nbytes = strlen(value)+1;
98 : :
99 [ + - ]: 21 : if (add)
100 : 21 : pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
101 : :
102 : : return 0;
103 : : }
104 : :
105 : : /** Will accept only valid UTF-8 */
106 : 13 : static int proplist_setn(pa_proplist *p, const char *key, size_t key_length, const char *value, size_t value_length) {
107 : : struct property *prop;
108 : 13 : pa_bool_t add = FALSE;
109 : : char *k, *v;
110 : :
111 [ - + ]: 13 : pa_assert(p);
112 [ - + ]: 13 : pa_assert(key);
113 [ - + ]: 13 : pa_assert(value);
114 : :
115 : 13 : k = pa_xstrndup(key, key_length);
116 : 13 : v = pa_xstrndup(value, value_length);
117 : :
118 [ + - ][ - + ]: 13 : if (!pa_proplist_key_valid(k) || !pa_utf8_valid(v)) {
119 : 0 : pa_xfree(k);
120 : 0 : pa_xfree(v);
121 : 0 : return -1;
122 : : }
123 : :
124 [ + - ]: 13 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), k))) {
125 : 13 : prop = pa_xnew(struct property, 1);
126 : 13 : prop->key = k;
127 : 13 : add = TRUE;
128 : : } else {
129 : 0 : pa_xfree(prop->value);
130 : 0 : pa_xfree(k);
131 : : }
132 : :
133 : 13 : prop->value = v;
134 : 13 : prop->nbytes = strlen(v)+1;
135 : :
136 [ + - ]: 13 : if (add)
137 : 13 : pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
138 : :
139 : : return 0;
140 : : }
141 : :
142 : : /** Will accept only valid UTF-8 */
143 : 0 : int pa_proplist_setp(pa_proplist *p, const char *pair) {
144 : : const char *t;
145 : :
146 [ # # ]: 0 : pa_assert(p);
147 [ # # ]: 0 : pa_assert(pair);
148 : :
149 [ # # ]: 0 : if (!(t = strchr(pair, '=')))
150 : : return -1;
151 : :
152 : 0 : return proplist_setn(p,
153 : 0 : pair, t - pair,
154 : 0 : t + 1, strchr(pair, 0) - t - 1);
155 : : }
156 : :
157 : 3 : static int proplist_sethex(pa_proplist *p, const char *key, size_t key_length, const char *value, size_t value_length) {
158 : : struct property *prop;
159 : 3 : pa_bool_t add = FALSE;
160 : : char *k, *v;
161 : : uint8_t *d;
162 : : size_t dn;
163 : :
164 [ - + ]: 3 : pa_assert(p);
165 [ - + ]: 3 : pa_assert(key);
166 [ - + ]: 3 : pa_assert(value);
167 : :
168 : 3 : k = pa_xstrndup(key, key_length);
169 : :
170 [ - + ]: 3 : if (!pa_proplist_key_valid(k)) {
171 : 0 : pa_xfree(k);
172 : 0 : return -1;
173 : : }
174 : :
175 : 3 : v = pa_xstrndup(value, value_length);
176 : 3 : d = pa_xmalloc(value_length*2+1);
177 : :
178 [ - + ]: 3 : if ((dn = pa_parsehex(v, d, value_length*2)) == (size_t) -1) {
179 : 0 : pa_xfree(k);
180 : 0 : pa_xfree(v);
181 : 0 : pa_xfree(d);
182 : 0 : return -1;
183 : : }
184 : :
185 : 3 : pa_xfree(v);
186 : :
187 [ + - ]: 3 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), k))) {
188 : 3 : prop = pa_xnew(struct property, 1);
189 : 3 : prop->key = k;
190 : 3 : add = TRUE;
191 : : } else {
192 : 0 : pa_xfree(prop->value);
193 : 0 : pa_xfree(k);
194 : : }
195 : :
196 : 3 : d[dn] = 0;
197 : 3 : prop->value = d;
198 : 3 : prop->nbytes = dn;
199 : :
200 [ + - ]: 3 : if (add)
201 : 3 : pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
202 : :
203 : : return 0;
204 : : }
205 : :
206 : : /** Will accept only valid UTF-8 */
207 : 0 : int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) {
208 : : struct property *prop;
209 : 0 : pa_bool_t add = FALSE;
210 : : va_list ap;
211 : : char *v;
212 : :
213 [ # # ]: 0 : pa_assert(p);
214 [ # # ]: 0 : pa_assert(key);
215 [ # # ]: 0 : pa_assert(format);
216 : :
217 [ # # ][ # # ]: 0 : if (!pa_proplist_key_valid(key) || !pa_utf8_valid(format))
218 : : return -1;
219 : :
220 : 0 : va_start(ap, format);
221 : 0 : v = pa_vsprintf_malloc(format, ap);
222 : 0 : va_end(ap);
223 : :
224 [ # # ]: 0 : if (!pa_utf8_valid(v))
225 : : goto fail;
226 : :
227 [ # # ]: 0 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
228 : 0 : prop = pa_xnew(struct property, 1);
229 : 0 : prop->key = pa_xstrdup(key);
230 : 0 : add = TRUE;
231 : : } else
232 : 0 : pa_xfree(prop->value);
233 : :
234 : 0 : prop->value = v;
235 : 0 : prop->nbytes = strlen(v)+1;
236 : :
237 [ # # ]: 0 : if (add)
238 : 0 : pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
239 : :
240 : : return 0;
241 : :
242 : : fail:
243 : 0 : pa_xfree(v);
244 : 0 : return -1;
245 : : }
246 : :
247 : 5 : int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) {
248 : : struct property *prop;
249 : 5 : pa_bool_t add = FALSE;
250 : :
251 [ - + ]: 5 : pa_assert(p);
252 [ - + ]: 5 : pa_assert(key);
253 [ - + ]: 5 : pa_assert(data || nbytes == 0);
254 : :
255 [ + - ]: 5 : if (!pa_proplist_key_valid(key))
256 : : return -1;
257 : :
258 [ + - ]: 5 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
259 : 5 : prop = pa_xnew(struct property, 1);
260 : 5 : prop->key = pa_xstrdup(key);
261 : 5 : add = TRUE;
262 : : } else
263 : 0 : pa_xfree(prop->value);
264 : :
265 : 5 : prop->value = pa_xmalloc(nbytes+1);
266 [ + - ]: 5 : if (nbytes > 0)
267 : 5 : memcpy(prop->value, data, nbytes);
268 : 5 : ((char*) prop->value)[nbytes] = 0;
269 : 5 : prop->nbytes = nbytes;
270 : :
271 [ + - ]: 5 : if (add)
272 : 5 : pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
273 : :
274 : : return 0;
275 : : }
276 : :
277 : 60 : const char *pa_proplist_gets(pa_proplist *p, const char *key) {
278 : : struct property *prop;
279 : :
280 [ - + ]: 60 : pa_assert(p);
281 [ - + ]: 60 : pa_assert(key);
282 : :
283 [ + - ]: 60 : if (!pa_proplist_key_valid(key))
284 : : return NULL;
285 : :
286 [ + - ]: 60 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
287 : : return NULL;
288 : :
289 [ + - ]: 60 : if (prop->nbytes <= 0)
290 : : return NULL;
291 : :
292 [ + + ]: 60 : if (((char*) prop->value)[prop->nbytes-1] != 0)
293 : : return NULL;
294 : :
295 [ + - ]: 54 : if (strlen((char*) prop->value) != prop->nbytes-1)
296 : : return NULL;
297 : :
298 [ + - ]: 54 : if (!pa_utf8_valid((char*) prop->value))
299 : : return NULL;
300 : :
301 : 60 : return (char*) prop->value;
302 : : }
303 : :
304 : 5 : int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes) {
305 : : struct property *prop;
306 : :
307 [ - + ]: 5 : pa_assert(p);
308 [ - + ]: 5 : pa_assert(key);
309 [ - + ]: 5 : pa_assert(data);
310 [ - + ]: 5 : pa_assert(nbytes);
311 : :
312 [ + - ]: 5 : if (!pa_proplist_key_valid(key))
313 : : return -1;
314 : :
315 [ + - ]: 5 : if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
316 : : return -1;
317 : :
318 : 5 : *data = prop->value;
319 : 5 : *nbytes = prop->nbytes;
320 : :
321 : 5 : return 0;
322 : : }
323 : :
324 : 2 : void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, const pa_proplist *other) {
325 : : struct property *prop;
326 : 2 : void *state = NULL;
327 : :
328 [ - + ]: 2 : pa_assert(p);
329 [ - + ]: 2 : pa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE);
330 [ - + ]: 2 : pa_assert(other);
331 : :
332 [ - + ]: 2 : if (mode == PA_UPDATE_SET)
333 : 2 : pa_proplist_clear(p);
334 : :
335 : : /* MAKE_HASHMAP turns the const pointer into a non-const pointer, but
336 : : * that's ok, because we don't modify the hashmap contents. */
337 [ + + ]: 7 : while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL))) {
338 : :
339 [ + + ][ + + ]: 5 : if (mode == PA_UPDATE_MERGE && pa_proplist_contains(p, prop->key))
340 : 1 : continue;
341 : :
342 [ - + ]: 5 : pa_assert_se(pa_proplist_set(p, prop->key, prop->value, prop->nbytes) == 0);
343 : : }
344 : 2 : }
345 : :
346 : 1 : int pa_proplist_unset(pa_proplist *p, const char *key) {
347 : : struct property *prop;
348 : :
349 [ - + ]: 1 : pa_assert(p);
350 [ - + ]: 1 : pa_assert(key);
351 : :
352 [ + - ]: 1 : if (!pa_proplist_key_valid(key))
353 : : return -1;
354 : :
355 [ + - ]: 1 : if (!(prop = pa_hashmap_remove(MAKE_HASHMAP(p), key)))
356 : : return -2;
357 : :
358 : 1 : property_free(prop);
359 : 1 : return 0;
360 : : }
361 : :
362 : 0 : int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
363 : : const char * const * k;
364 : 0 : int n = 0;
365 : :
366 [ # # ]: 0 : pa_assert(p);
367 [ # # ]: 0 : pa_assert(keys);
368 : :
369 [ # # ]: 0 : for (k = keys; *k; k++)
370 [ # # ]: 0 : if (!pa_proplist_key_valid(*k))
371 : : return -1;
372 : :
373 [ # # ]: 0 : for (k = keys; *k; k++)
374 [ # # ]: 0 : if (pa_proplist_unset(p, *k) >= 0)
375 : 0 : n++;
376 : :
377 : : return n;
378 : : }
379 : :
380 : 46 : const char *pa_proplist_iterate(pa_proplist *p, void **state) {
381 : : struct property *prop;
382 : :
383 [ + + ]: 46 : if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP(p), state, NULL)))
384 : : return NULL;
385 : :
386 : 46 : return prop->key;
387 : : }
388 : :
389 : 6 : char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep) {
390 : : const char *key;
391 : 6 : void *state = NULL;
392 : : pa_strbuf *buf;
393 : :
394 [ - + ]: 6 : pa_assert(p);
395 [ - + ]: 6 : pa_assert(sep);
396 : :
397 : 6 : buf = pa_strbuf_new();
398 : :
399 [ + + ]: 26 : while ((key = pa_proplist_iterate(p, &state))) {
400 : : const char *v;
401 : :
402 [ + + ]: 20 : if (!pa_strbuf_isempty(buf))
403 : 14 : pa_strbuf_puts(buf, sep);
404 : :
405 [ + + ]: 20 : if ((v = pa_proplist_gets(p, key))) {
406 : : const char *t;
407 : :
408 : 15 : pa_strbuf_printf(buf, "%s = \"", key);
409 : :
410 : 15 : for (t = v;;) {
411 : : size_t h;
412 : :
413 [ - + ][ + - ]: 44 : h = strcspn(t, "\"");
[ # # ][ # # ]
414 : :
415 [ + + ]: 22 : if (h > 0)
416 : 16 : pa_strbuf_putsn(buf, t, h);
417 : :
418 : 22 : t += h;
419 : :
420 [ + + ]: 22 : if (*t == 0)
421 : : break;
422 : :
423 [ - + ]: 7 : pa_assert(*t == '"');
424 : 7 : pa_strbuf_puts(buf, "\\\"");
425 : :
426 : 7 : t++;
427 : 7 : }
428 : :
429 : 15 : pa_strbuf_puts(buf, "\"");
430 : : } else {
431 : : const void *value;
432 : : size_t nbytes;
433 : : char *c;
434 : :
435 [ - + ]: 5 : pa_assert_se(pa_proplist_get(p, key, &value, &nbytes) == 0);
436 : 5 : c = pa_xmalloc(nbytes*2+1);
437 : 5 : pa_hexstr((const uint8_t*) value, nbytes, c, nbytes*2+1);
438 : :
439 : 5 : pa_strbuf_printf(buf, "%s = hex:%s", key, c);
440 : 20 : pa_xfree(c);
441 : : }
442 : : }
443 : :
444 : 6 : return pa_strbuf_tostring_free(buf);
445 : : }
446 : :
447 : 6 : char *pa_proplist_to_string(pa_proplist *p) {
448 : : char *s, *t;
449 : :
450 : 6 : s = pa_proplist_to_string_sep(p, "\n");
451 : 6 : t = pa_sprintf_malloc("%s\n", s);
452 : 6 : pa_xfree(s);
453 : :
454 : 6 : return t;
455 : : }
456 : :
457 : 4 : pa_proplist *pa_proplist_from_string(const char *s) {
458 : : enum {
459 : : WHITESPACE,
460 : : KEY,
461 : : AFTER_KEY,
462 : : VALUE_START,
463 : : VALUE_SIMPLE,
464 : : VALUE_DOUBLE_QUOTES,
465 : : VALUE_DOUBLE_QUOTES_ESCAPE,
466 : : VALUE_TICKS,
467 : : VALUE_TICKS_ESCAPED,
468 : : VALUE_HEX
469 : : } state;
470 : :
471 : : pa_proplist *pl;
472 : 4 : const char *p, *key = NULL, *value = NULL;
473 : 4 : size_t key_len = 0, value_len = 0;
474 : :
475 [ - + ]: 4 : pa_assert(s);
476 : :
477 : 4 : pl = pa_proplist_new();
478 : :
479 : 4 : state = WHITESPACE;
480 : :
481 : 4 : for (p = s;; p++) {
482 [ + + + + : 344 : switch (state) {
+ + + + +
+ - ]
483 : :
484 : : case WHITESPACE:
485 [ + + ]: 31 : if (*p == 0)
486 : : goto success;
487 [ + - ]: 27 : else if (*p == '=')
488 : : goto fail;
489 [ + + ]: 27 : else if (!isspace(*p)) {
490 : 16 : key = p;
491 : 16 : state = KEY;
492 : 16 : key_len = 1;
493 : : }
494 : : break;
495 : :
496 : : case KEY:
497 [ + - ]: 93 : if (*p == 0)
498 : : goto fail;
499 [ + + ]: 93 : else if (*p == '=')
500 : : state = VALUE_START;
501 [ + + ]: 88 : else if (isspace(*p))
502 : : state = AFTER_KEY;
503 : : else
504 : 77 : key_len++;
505 : : break;
506 : :
507 : : case AFTER_KEY:
508 [ + - ]: 11 : if (*p == 0)
509 : : goto fail;
510 [ - + ]: 11 : else if (*p == '=')
511 : : state = VALUE_START;
512 [ # # ]: 0 : else if (!isspace(*p))
513 : : goto fail;
514 : : break;
515 : :
516 : : case VALUE_START:
517 [ + - ]: 27 : if (*p == 0)
518 : : goto fail;
519 [ + + ]: 27 : else if (strncmp(p, "hex:", 4) == 0) {
520 : 3 : state = VALUE_HEX;
521 : 3 : value = p+4;
522 : 3 : value_len = 0;
523 : 3 : p += 3;
524 [ + + ]: 24 : } else if (*p == '\'') {
525 : 1 : state = VALUE_TICKS;
526 : 1 : value = p+1;
527 : 1 : value_len = 0;
528 [ + + ]: 23 : } else if (*p == '"') {
529 : 9 : state = VALUE_DOUBLE_QUOTES;
530 : 9 : value = p+1;
531 : 9 : value_len = 0;
532 [ + + ]: 14 : } else if (!isspace(*p)) {
533 : 3 : state = VALUE_SIMPLE;
534 : 3 : value = p;
535 : 3 : value_len = 1;
536 : : }
537 : : break;
538 : :
539 : : case VALUE_SIMPLE:
540 [ + - ][ + + ]: 14 : if (*p == 0 || isspace(*p)) {
541 [ + - ]: 3 : if (proplist_setn(pl, key, key_len, value, value_len) < 0)
542 : : goto fail;
543 : :
544 [ + - ]: 3 : if (*p == 0)
545 : : goto success;
546 : :
547 : : state = WHITESPACE;
548 : : } else
549 : 11 : value_len++;
550 : : break;
551 : :
552 : : case VALUE_DOUBLE_QUOTES:
553 [ + - ]: 97 : if (*p == 0)
554 : : goto fail;
555 [ + + ]: 97 : else if (*p == '"') {
556 : : char *v;
557 : :
558 : 9 : v = pa_unescape(pa_xstrndup(value, value_len));
559 : :
560 [ - + ]: 9 : if (proplist_setn(pl, key, key_len, v, strlen(v)) < 0) {
561 : 0 : pa_xfree(v);
562 : 0 : goto fail;
563 : : }
564 : :
565 : 9 : pa_xfree(v);
566 : 9 : state = WHITESPACE;
567 [ + + ]: 88 : } else if (*p == '\\') {
568 : 7 : state = VALUE_DOUBLE_QUOTES_ESCAPE;
569 : 7 : value_len++;
570 : : } else
571 : 81 : value_len++;
572 : : break;
573 : :
574 : : case VALUE_DOUBLE_QUOTES_ESCAPE:
575 [ + - ]: 7 : if (*p == 0)
576 : : goto fail;
577 : : else {
578 : 7 : state = VALUE_DOUBLE_QUOTES;
579 : 7 : value_len++;
580 : : }
581 : 7 : break;
582 : :
583 : : case VALUE_TICKS:
584 [ + - ]: 7 : if (*p == 0)
585 : : goto fail;
586 [ + + ]: 7 : else if (*p == '\'') {
587 : : char *v;
588 : :
589 : 1 : v = pa_unescape(pa_xstrndup(value, value_len));
590 : :
591 [ - + ]: 1 : if (proplist_setn(pl, key, key_len, v, strlen(v)) < 0) {
592 : 0 : pa_xfree(v);
593 : 0 : goto fail;
594 : : }
595 : :
596 : 1 : pa_xfree(v);
597 : 1 : state = WHITESPACE;
598 [ + - ]: 6 : } else if (*p == '\\') {
599 : 6 : state = VALUE_TICKS_ESCAPED;
600 : 6 : value_len++;
601 : : } else
602 : 0 : value_len++;
603 : : break;
604 : :
605 : : case VALUE_TICKS_ESCAPED:
606 [ + - ]: 6 : if (*p == 0)
607 : : goto fail;
608 : : else {
609 : 6 : state = VALUE_TICKS;
610 : 6 : value_len++;
611 : : }
612 : 6 : break;
613 : :
614 : : case VALUE_HEX:
615 [ + + ]: 51 : if ((*p >= '0' && *p <= '9') ||
616 [ + + ]: 13 : (*p >= 'A' && *p <= 'F') ||
617 : 13 : (*p >= 'a' && *p <= 'f')) {
618 : 48 : value_len++;
619 [ + - ][ + - ]: 3 : } else if (*p == 0 || isspace(*p)) {
620 : :
621 [ + - ]: 3 : if (proplist_sethex(pl, key, key_len, value, value_len) < 0)
622 : : goto fail;
623 : :
624 [ + - ]: 3 : if (*p == 0)
625 : : goto success;
626 : :
627 : : state = WHITESPACE;
628 : : } else
629 : : goto fail;
630 : : break;
631 : : }
632 : 340 : }
633 : :
634 : : success:
635 : : return MAKE_PROPLIST(pl);
636 : :
637 : : fail:
638 : 0 : pa_proplist_free(pl);
639 : 4 : return NULL;
640 : : }
641 : :
642 : 2 : int pa_proplist_contains(pa_proplist *p, const char *key) {
643 [ - + ]: 2 : pa_assert(p);
644 [ - + ]: 2 : pa_assert(key);
645 : :
646 [ + - ]: 2 : if (!pa_proplist_key_valid(key))
647 : : return -1;
648 : :
649 [ + + ]: 2 : if (!(pa_hashmap_get(MAKE_HASHMAP(p), key)))
650 : : return 0;
651 : :
652 : 2 : return 1;
653 : : }
654 : :
655 : 25 : void pa_proplist_clear(pa_proplist *p) {
656 : : struct property *prop;
657 [ + - ]: 25 : pa_assert(p);
658 : :
659 [ + + ]: 66 : while ((prop = pa_hashmap_steal_first(MAKE_HASHMAP(p))))
660 : 41 : property_free(prop);
661 : 25 : }
662 : :
663 : 0 : pa_proplist* pa_proplist_copy(const pa_proplist *p) {
664 : : pa_proplist *copy;
665 : :
666 [ # # ]: 0 : pa_assert_se(copy = pa_proplist_new());
667 : :
668 [ # # ]: 0 : if (p)
669 : 0 : pa_proplist_update(copy, PA_UPDATE_REPLACE, p);
670 : :
671 : 0 : return copy;
672 : : }
673 : :
674 : 0 : unsigned pa_proplist_size(pa_proplist *p) {
675 [ # # ]: 0 : pa_assert(p);
676 : :
677 : 0 : return pa_hashmap_size(MAKE_HASHMAP(p));
678 : : }
679 : :
680 : 0 : int pa_proplist_isempty(pa_proplist *p) {
681 [ # # ]: 0 : pa_assert(p);
682 : :
683 : 0 : return pa_hashmap_isempty(MAKE_HASHMAP(p));
684 : : }
685 : :
686 : 0 : int pa_proplist_equal(pa_proplist *a, pa_proplist *b) {
687 : 0 : const void *key = NULL;
688 : 0 : struct property *a_prop = NULL;
689 : 0 : struct property *b_prop = NULL;
690 : 0 : void *state = NULL;
691 : :
692 [ # # ]: 0 : pa_assert(a);
693 [ # # ]: 0 : pa_assert(b);
694 : :
695 [ # # ]: 0 : if (a == b)
696 : : return 1;
697 : :
698 [ # # ]: 0 : if (pa_proplist_size(a) != pa_proplist_size(b))
699 : : return 0;
700 : :
701 [ # # ]: 0 : while ((a_prop = pa_hashmap_iterate(MAKE_HASHMAP(a), &state, &key))) {
702 [ # # ]: 0 : if (!(b_prop = pa_hashmap_get(MAKE_HASHMAP(b), key)))
703 : : return 0;
704 : :
705 [ # # ]: 0 : if (a_prop->nbytes != b_prop->nbytes)
706 : : return 0;
707 : :
708 [ # # ]: 0 : if (memcmp(a_prop->value, b_prop->value, a_prop->nbytes) != 0)
709 : : return 0;
710 : : }
711 : :
712 : : return 1;
713 : : }
|