]> code.delx.au - pulseaudio/blob - src/pulse/proplist.c
commit glitch-free work
[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 int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) {
106 struct property *prop;
107 pa_bool_t add = FALSE;
108
109 pa_assert(p);
110 pa_assert(key);
111
112 if (!property_name_valid(key))
113 return -1;
114
115 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key))) {
116 prop = pa_xnew(struct property, 1);
117 prop->key = pa_xstrdup(key);
118 add = TRUE;
119 } else
120 pa_xfree(prop->value);
121
122 prop->value = pa_xmemdup(data, nbytes);
123 prop->nbytes = nbytes;
124
125 if (add)
126 pa_hashmap_put(MAKE_HASHMAP(p), prop->key, prop);
127
128 return 0;
129 }
130
131 const char *pa_proplist_gets(pa_proplist *p, const char *key) {
132 struct property *prop;
133
134 pa_assert(p);
135 pa_assert(key);
136
137 if (!property_name_valid(key))
138 return NULL;
139
140 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
141 return NULL;
142
143 if (prop->nbytes <= 0)
144 return NULL;
145
146 if (((char*) prop->value)[prop->nbytes-1] != 0)
147 return NULL;
148
149 if (strlen((char*) prop->value) != prop->nbytes-1)
150 return NULL;
151
152 if (!pa_utf8_valid((char*) prop->value))
153 return NULL;
154
155 return (char*) prop->value;
156 }
157
158 int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes) {
159 struct property *prop;
160
161 pa_assert(p);
162 pa_assert(key);
163
164 if (!property_name_valid(key))
165 return -1;
166
167 if (!(prop = pa_hashmap_get(MAKE_HASHMAP(p), key)))
168 return -1;
169
170 *data = prop->value;
171 *nbytes = prop->nbytes;
172
173 return 0;
174 }
175
176 void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, pa_proplist *other) {
177 struct property *prop;
178 void *state = NULL;
179
180 pa_assert(p);
181 pa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE);
182 pa_assert(other);
183
184 if (mode == PA_UPDATE_SET)
185 pa_proplist_clear(p);
186
187 while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL))) {
188
189 if (mode == PA_UPDATE_MERGE && pa_proplist_contains(p, prop->key))
190 continue;
191
192 pa_assert_se(pa_proplist_set(p, prop->key, prop->value, prop->nbytes) == 0);
193 }
194 }
195
196 int pa_proplist_unset(pa_proplist *p, const char *key) {
197 struct property *prop;
198
199 pa_assert(p);
200 pa_assert(key);
201
202 if (!property_name_valid(key))
203 return -1;
204
205 if (!(prop = pa_hashmap_remove(MAKE_HASHMAP(p), key)))
206 return -2;
207
208 property_free(prop);
209 return 0;
210 }
211
212 int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
213 const char * const * k;
214 int n = 0;
215
216 pa_assert(p);
217 pa_assert(keys);
218
219 for (k = keys; *k; k++)
220 if (!property_name_valid(*k))
221 return -1;
222
223 for (k = keys; *k; k++)
224 if (pa_proplist_unset(p, *k) >= 0)
225 n++;
226
227 return n;
228 }
229
230 const char *pa_proplist_iterate(pa_proplist *p, void **state) {
231 struct property *prop;
232
233 if (!(prop = pa_hashmap_iterate(MAKE_HASHMAP(p), state, NULL)))
234 return NULL;
235
236 return prop->key;
237 }
238
239 char *pa_proplist_to_string(pa_proplist *p) {
240 const char *key;
241 void *state = NULL;
242 pa_strbuf *buf;
243
244 pa_assert(p);
245
246 buf = pa_strbuf_new();
247
248 while ((key = pa_proplist_iterate(p, &state))) {
249
250 const char *v;
251
252 if ((v = pa_proplist_gets(p, key)))
253 pa_strbuf_printf(buf, "%s = \"%s\"\n", key, v);
254 else {
255 const void *value;
256 size_t nbytes;
257 char *c;
258
259 pa_assert_se(pa_proplist_get(p, key, &value, &nbytes) == 0);
260 c = pa_xnew(char, nbytes*2+1);
261 pa_hexstr((const uint8_t*) value, nbytes, c, nbytes*2+1);
262
263 pa_strbuf_printf(buf, "%s = hex:%s\n", key, c);
264 pa_xfree(c);
265 }
266 }
267
268 return pa_strbuf_tostring_free(buf);
269 }
270
271 int pa_proplist_contains(pa_proplist *p, const char *key) {
272 pa_assert(p);
273 pa_assert(key);
274
275 if (!property_name_valid(key))
276 return -1;
277
278 if (!(pa_hashmap_get(MAKE_HASHMAP(p), key)))
279 return 0;
280
281 return 1;
282 }
283
284 void pa_proplist_clear(pa_proplist *p) {
285 struct property *prop;
286 pa_assert(p);
287
288 while ((prop = pa_hashmap_steal_first(MAKE_HASHMAP(p))))
289 property_free(prop);
290 }
291
292 pa_proplist* pa_proplist_copy(pa_proplist *template) {
293 pa_proplist *p;
294
295 pa_assert_se(p = pa_proplist_new());
296
297 if (template)
298 pa_proplist_update(p, PA_UPDATE_REPLACE, template);
299
300 return p;
301 }