]> code.delx.au - pulseaudio/blob - src/pulse/proplist.c
add new pa_proplist_setf() API function
[pulseaudio] / src / pulse / proplist.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2007 Lennart Poettering
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation; either version 2.1 of the
11 License, or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29
30 #include <pulse/xmalloc.h>
31 #include <pulse/utf8.h>
32
33 #include <pulsecore/hashmap.h>
34 #include <pulsecore/strbuf.h>
35 #include <pulsecore/core-util.h>
36
37 #include "proplist.h"
38
39 struct property {
40 char *key;
41 void *value;
42 size_t nbytes;
43 };
44
45 #define MAKE_HASHMAP(p) ((pa_hashmap*) (p))
46 #define MAKE_PROPLIST(p) ((pa_proplist*) (p))
47
48 static pa_bool_t property_name_valid(const char *key) {
49
50 if (!pa_utf8_valid(key))
51 return FALSE;
52
53 if (strlen(key) <= 0)
54 return FALSE;
55
56 return TRUE;
57 }
58
59 static void property_free(struct property *prop) {
60 pa_assert(prop);
61
62 pa_xfree(prop->key);
63 pa_xfree(prop->value);
64 pa_xfree(prop);
65 }
66
67 pa_proplist* pa_proplist_new(void) {
68 return MAKE_PROPLIST(pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func));
69 }
70
71 void pa_proplist_free(pa_proplist* p) {
72 pa_assert(p);
73
74 pa_proplist_clear(p);
75 pa_hashmap_free(MAKE_HASHMAP(p), NULL, NULL);
76 }
77
78 /** Will accept only valid UTF-8 */
79 int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) {
80 struct property *prop;
81 pa_bool_t add = FALSE;
82
83 pa_assert(p);
84 pa_assert(key);
85
86 if (!property_name_valid(key) || !pa_utf8_valid(value))
87 return -1;
88
89 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
90 prop = pa_xnew(struct property, 1);
91 prop->key = pa_xstrdup(key);
92 add = TRUE;
93 } else
94 pa_xfree(prop->value);
95
96 prop->value = pa_xstrdup(value);
97 prop->nbytes = strlen(value)+1;
98
99 if (add)
100 pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
101
102 return 0;
103 }
104
105 /** Will accept only valid UTF-8 */
106 int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) {
107 va_list ap;
108 int r;
109 char *t;
110
111 pa_assert(p);
112 pa_assert(key);
113
114 if (!property_name_valid(key) || !pa_utf8_valid(format))
115 return -1;
116
117 va_start(ap, format);
118 t = pa_vsprintf_malloc(format, ap);
119 va_end(ap);
120
121 r = pa_proplist_sets(p, key, t);
122
123 pa_xfree(t);
124 return r;
125 }
126
127 int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) {
128 struct property *prop;
129 pa_bool_t add = FALSE;
130
131 pa_assert(p);
132 pa_assert(key);
133
134 if (!property_name_valid(key))
135 return -1;
136
137 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
138 prop = pa_xnew(struct property, 1);
139 prop->key = pa_xstrdup(key);
140 add = TRUE;
141 } else
142 pa_xfree(prop->value);
143
144 prop->value = pa_xmemdup(data, nbytes);
145 prop->nbytes = nbytes;
146
147 if (add)
148 pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
149
150 return 0;
151 }
152
153 const char *pa_proplist_gets(pa_proplist *p, const char *key) {
154 struct property *prop;
155
156 pa_assert(p);
157 pa_assert(key);
158
159 if (!property_name_valid(key))
160 return NULL;
161
162 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
163 return NULL;
164
165 if (prop->nbytes <= 0)
166 return NULL;
167
168 if (((char*) prop->value)[prop->nbytes-1] != 0)
169 return NULL;
170
171 if (strlen((char*) prop->value) != prop->nbytes-1)
172 return NULL;
173
174 if (!pa_utf8_valid((char*) prop->value))
175 return NULL;
176
177 return (char*) prop->value;
178 }
179
180 int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes) {
181 struct property *prop;
182
183 pa_assert(p);
184 pa_assert(key);
185
186 if (!property_name_valid(key))
187 return -1;
188
189 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
190 return -1;
191
192 *data = prop->value;
193 *nbytes = prop->nbytes;
194
195 return 0;
196 }
197
198 void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, pa_proplist *other) {
199 struct property *prop;
200 void *state = NULL;
201
202 pa_assert(p);
203 pa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE);
204 pa_assert(other);
205
206 if (mode == PA_UPDATE_SET)
207 pa_proplist_clear(p);
208
209 while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL))) {
210
211 if (mode == PA_UPDATE_MERGE && pa_proplist_contains(p, prop->key))
212 continue;
213
214 pa_assert_se(pa_proplist_set(p, prop->key, prop->value, prop->nbytes) == 0);
215 }
216 }
217
218 int pa_proplist_unset(pa_proplist *p, const char *key) {
219 struct property *prop;
220
221 pa_assert(p);
222 pa_assert(key);
223
224 if (!property_name_valid(key))
225 return -1;
226
227 if (!(prop = pa_hashmap_remove(MAKE_HASHMAP(p), key)))
228 return -2;
229
230 property_free(prop);
231 return 0;
232 }
233
234 int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
235 const char * const * k;
236 int n = 0;
237
238 pa_assert(p);
239 pa_assert(keys);
240
241 for (k = keys; *k; k++)
242 if (!property_name_valid(*k))
243 return -1;
244
245 for (k = keys; *k; k++)
246 if (pa_proplist_unset(p, *k) >= 0)
247 n++;
248
249 return n;
250 }
251
252 const char *pa_proplist_iterate(pa_proplist *p, void **state) {
253 struct property *prop;
254
255 if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP(p), state, NULL)))
256 return NULL;
257
258 return prop->key;
259 }
260
261 char *pa_proplist_to_string(pa_proplist *p) {
262 const char *key;
263 void *state = NULL;
264 pa_strbuf *buf;
265
266 pa_assert(p);
267
268 buf = pa_strbuf_new();
269
270 while ((key = pa_proplist_iterate(p, &state))) {
271
272 const char *v;
273
274 if ((v = pa_proplist_gets(p, key)))
275 pa_strbuf_printf(buf, "%s = \"%s\"\n", key, v);
276 else {
277 const void *value;
278 size_t nbytes;
279 char *c;
280
281 pa_assert_se(pa_proplist_get(p, key, &value, &nbytes) == 0);
282 c = pa_xnew(char, nbytes*2+1);
283 pa_hexstr((const uint8_t*) value, nbytes, c, nbytes*2+1);
284
285 pa_strbuf_printf(buf, "%s = hex:%s\n", key, c);
286 pa_xfree(c);
287 }
288 }
289
290 return pa_strbuf_tostring_free(buf);
291 }
292
293 int pa_proplist_contains(pa_proplist *p, const char *key) {
294 pa_assert(p);
295 pa_assert(key);
296
297 if (!property_name_valid(key))
298 return -1;
299
300 if (!(pa_hashmap_get(MAKE_HASHMAP(p), key)))
301 return 0;
302
303 return 1;
304 }
305
306 void pa_proplist_clear(pa_proplist *p) {
307 struct property *prop;
308 pa_assert(p);
309
310 while ((prop = pa_hashmap_steal_first(MAKE_HASHMAP(p))))
311 property_free(prop);
312 }
313
314 pa_proplist* pa_proplist_copy(pa_proplist *template) {
315 pa_proplist *p;
316
317 pa_assert_se(p = pa_proplist_new());
318
319 if (template)
320 pa_proplist_update(p, PA_UPDATE_REPLACE, template);
321
322 return p;
323 }