]> code.delx.au - pulseaudio/blob - src/pulse/proplist.c
Merge dead branch 'lockfree'
[pulseaudio] / src / pulse / proplist.c
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
28 #include <pulse/xmalloc.h>
29 #include <pulse/utf8.h>
30
31 #include <pulsecore/hashmap.h>
32 #include <pulsecore/strbuf.h>
33 #include <pulsecore/core-util.h>
34
35 #include "proplist.h"
36
37 struct property {
38 char *key;
39 void *value;
40 size_t nbytes;
41 };
42
43 #define MAKE_HASHMAP(p) ((pa_hashmap*) (p))
44 #define MAKE_PROPLIST(p) ((pa_proplist*) (p))
45
46 static pa_bool_t property_name_valid(const char *key) {
47
48 if (!pa_utf8_valid(key))
49 return FALSE;
50
51 if (strlen(key) <= 0)
52 return FALSE;
53
54 return TRUE;
55 }
56
57 static void property_free(struct property *prop) {
58 pa_assert(prop);
59
60 pa_xfree(prop->key);
61 pa_xfree(prop->value);
62 pa_xfree(prop);
63 }
64
65 pa_proplist* pa_proplist_new(void) {
66 return MAKE_PROPLIST(pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func));
67 }
68
69 void pa_proplist_free(pa_proplist* p) {
70 pa_assert(p);
71
72 pa_proplist_clear(p);
73 pa_hashmap_free(MAKE_HASHMAP(p), NULL, NULL);
74 }
75
76 /** Will accept only valid UTF-8 */
77 int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) {
78 struct property *prop;
79 pa_bool_t add = FALSE;
80
81 pa_assert(p);
82 pa_assert(key);
83
84 if (!property_name_valid(key) || !pa_utf8_valid(value))
85 return -1;
86
87 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
88 prop = pa_xnew(struct property, 1);
89 prop->key = pa_xstrdup(key);
90 add = TRUE;
91 } else
92 pa_xfree(prop->value);
93
94 prop->value = pa_xstrdup(value);
95 prop->nbytes = strlen(value)+1;
96
97 if (add)
98 pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
99
100 return 0;
101 }
102
103 /** Will accept only valid UTF-8 */
104 int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) {
105 va_list ap;
106 int r;
107 char *t;
108
109 pa_assert(p);
110 pa_assert(key);
111
112 if (!property_name_valid(key) || !pa_utf8_valid(format))
113 return -1;
114
115 va_start(ap, format);
116 t = pa_vsprintf_malloc(format, ap);
117 va_end(ap);
118
119 r = pa_proplist_sets(p, key, t);
120
121 pa_xfree(t);
122 return r;
123 }
124
125 int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) {
126 struct property *prop;
127 pa_bool_t add = FALSE;
128
129 pa_assert(p);
130 pa_assert(key);
131
132 if (!property_name_valid(key))
133 return -1;
134
135 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
136 prop = pa_xnew(struct property, 1);
137 prop->key = pa_xstrdup(key);
138 add = TRUE;
139 } else
140 pa_xfree(prop->value);
141
142 prop->value = pa_xmemdup(data, nbytes);
143 prop->nbytes = nbytes;
144
145 if (add)
146 pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
147
148 return 0;
149 }
150
151 const char *pa_proplist_gets(pa_proplist *p, const char *key) {
152 struct property *prop;
153
154 pa_assert(p);
155 pa_assert(key);
156
157 if (!property_name_valid(key))
158 return NULL;
159
160 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
161 return NULL;
162
163 if (prop->nbytes <= 0)
164 return NULL;
165
166 if (((char*) prop->value)[prop->nbytes-1] != 0)
167 return NULL;
168
169 if (strlen((char*) prop->value) != prop->nbytes-1)
170 return NULL;
171
172 if (!pa_utf8_valid((char*) prop->value))
173 return NULL;
174
175 return (char*) prop->value;
176 }
177
178 int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes) {
179 struct property *prop;
180
181 pa_assert(p);
182 pa_assert(key);
183
184 if (!property_name_valid(key))
185 return -1;
186
187 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
188 return -1;
189
190 *data = prop->value;
191 *nbytes = prop->nbytes;
192
193 return 0;
194 }
195
196 void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, pa_proplist *other) {
197 struct property *prop;
198 void *state = NULL;
199
200 pa_assert(p);
201 pa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE);
202 pa_assert(other);
203
204 if (mode == PA_UPDATE_SET)
205 pa_proplist_clear(p);
206
207 while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL))) {
208
209 if (mode == PA_UPDATE_MERGE && pa_proplist_contains(p, prop->key))
210 continue;
211
212 pa_assert_se(pa_proplist_set(p, prop->key, prop->value, prop->nbytes) == 0);
213 }
214 }
215
216 int pa_proplist_unset(pa_proplist *p, const char *key) {
217 struct property *prop;
218
219 pa_assert(p);
220 pa_assert(key);
221
222 if (!property_name_valid(key))
223 return -1;
224
225 if (!(prop = pa_hashmap_remove(MAKE_HASHMAP(p), key)))
226 return -2;
227
228 property_free(prop);
229 return 0;
230 }
231
232 int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
233 const char * const * k;
234 int n = 0;
235
236 pa_assert(p);
237 pa_assert(keys);
238
239 for (k = keys; *k; k++)
240 if (!property_name_valid(*k))
241 return -1;
242
243 for (k = keys; *k; k++)
244 if (pa_proplist_unset(p, *k) >= 0)
245 n++;
246
247 return n;
248 }
249
250 const char *pa_proplist_iterate(pa_proplist *p, void **state) {
251 struct property *prop;
252
253 if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP(p), state, NULL)))
254 return NULL;
255
256 return prop->key;
257 }
258
259 char *pa_proplist_to_string(pa_proplist *p) {
260 const char *key;
261 void *state = NULL;
262 pa_strbuf *buf;
263
264 pa_assert(p);
265
266 buf = pa_strbuf_new();
267
268 while ((key = pa_proplist_iterate(p, &state))) {
269
270 const char *v;
271
272 if ((v = pa_proplist_gets(p, key)))
273 pa_strbuf_printf(buf, "%s = \"%s\"\n", key, v);
274 else {
275 const void *value;
276 size_t nbytes;
277 char *c;
278
279 pa_assert_se(pa_proplist_get(p, key, &value, &nbytes) == 0);
280 c = pa_xnew(char, nbytes*2+1);
281 pa_hexstr((const uint8_t*) value, nbytes, c, nbytes*2+1);
282
283 pa_strbuf_printf(buf, "%s = hex:%s\n", key, c);
284 pa_xfree(c);
285 }
286 }
287
288 return pa_strbuf_tostring_free(buf);
289 }
290
291 int pa_proplist_contains(pa_proplist *p, const char *key) {
292 pa_assert(p);
293 pa_assert(key);
294
295 if (!property_name_valid(key))
296 return -1;
297
298 if (!(pa_hashmap_get(MAKE_HASHMAP(p), key)))
299 return 0;
300
301 return 1;
302 }
303
304 void pa_proplist_clear(pa_proplist *p) {
305 struct property *prop;
306 pa_assert(p);
307
308 while ((prop = pa_hashmap_steal_first(MAKE_HASHMAP(p))))
309 property_free(prop);
310 }
311
312 pa_proplist* pa_proplist_copy(pa_proplist *template) {
313 pa_proplist *p;
314
315 pa_assert_se(p = pa_proplist_new());
316
317 if (template)
318 pa_proplist_update(p, PA_UPDATE_REPLACE, template);
319
320 return p;
321 }