]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
* split dbus-protocol.c in multiple sources files
[catta] / avahi-common / strlst.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   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   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; 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 <stdarg.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "strlst.h"
33 #include "malloc.h"
34 #include "defs.h"
35
36 AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
37     AvahiStringList *n;
38
39     if (!(n = avahi_malloc(sizeof(AvahiStringList) + size)))
40         return NULL;
41     
42     n->next = l;
43     n->size = size;
44
45     /* NUL terminate strings, just to make sure */
46     n->text[size] = 0;
47
48     return n;
49 }
50
51 AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
52     AvahiStringList *n;
53
54     assert(text);
55
56     if (!(n = avahi_string_list_add_anonymous(l, size)))
57         return NULL;
58
59     if (size > 0)
60         memcpy(n->text, text, size);
61
62     return n;
63 }
64
65 AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
66     assert(text);
67
68     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
69 }
70
71 int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
72     const uint8_t *c;
73     AvahiStringList *r;
74     
75     assert(data);
76     assert(ret);
77
78     r = NULL;
79
80     c = data;
81     while (size > 0) {
82         size_t k;
83         
84         k = *(c++);
85         size--;
86
87         if (k > size)
88             goto fail; /* Overflow */
89
90         if (k > 0) { /* Ignore empty strings */
91             AvahiStringList *n;
92
93             if (!(n = avahi_string_list_add_arbitrary(r, c, k)))  
94                 goto fail; /* OOM */
95
96             r = n;
97         }
98             
99         c += k;
100         size -= k;
101     }
102
103     *ret = r;
104     
105     return 0;
106
107 fail:
108     avahi_string_list_free(*ret);
109     return -1;
110 }
111
112 void avahi_string_list_free(AvahiStringList *l) {
113     AvahiStringList *n;
114
115     while (l) {
116         n = l->next;
117         avahi_free(l);
118         l = n;
119     }
120 }
121
122 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
123     AvahiStringList *r = NULL, *n;
124
125     while (l) {
126         n = l->next;
127         l->next = r;
128         r = l;
129         l = n;
130     }
131
132     return r;
133 }
134
135 char* avahi_string_list_to_string(AvahiStringList *l) {
136     AvahiStringList *n;
137     size_t s = 0;
138     char *t, *e;
139
140     for (n = l; n; n = n->next) {
141         if (n != l)
142             s ++;
143
144         s += n->size+2;
145     }
146
147     if (!(t = e = avahi_new(char, s+1)))
148         return NULL;
149
150     l = avahi_string_list_reverse(l);
151     
152     for (n = l; n; n = n->next) {
153         if (n != l)
154             *(e++) = ' ';
155
156         *(e++) = '"';
157         strncpy(e, (char*) n->text, n->size);
158         e[n->size] = 0;
159         e = strchr(e, 0);
160         *(e++) = '"';
161
162         assert(e);
163     }
164
165     l = avahi_string_list_reverse(l);
166     
167     *e = 0;
168
169     return t;
170 }
171
172 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
173     size_t used = 0;
174
175     if (data) {
176     
177         if (l) {
178             uint8_t *c;
179             AvahiStringList *n;
180         
181             l = avahi_string_list_reverse(l);
182             c = data;
183             
184             for (n = l; n; n = n->next) {
185                 size_t k;
186                 if (size < 1)
187                     break;
188                 
189                 k = n->size;
190                 if (k > 255)
191                     k = 255;
192                 
193                 if (k > size-1)
194                     k = size-1;
195                 
196                 *(c++) = k;
197                 memcpy(c, n->text, k);
198                 c += k;
199                 
200                 used += 1+ k;
201             }
202         
203             l = avahi_string_list_reverse(l);
204             
205         } else {
206
207             /* Empty lists are treated specially. To comply with
208              * section 6.1 of the DNS-SD spec, we return a single
209              * empty string (i.e. a NUL byte)*/
210
211             if (size > 0) {
212                 *(uint8_t*) data = 0;
213                 used = 1;
214             }
215             
216         }
217             
218     } else {
219         AvahiStringList *n;
220
221         if (!l)
222             used = 1;
223         else {
224
225             for (n = l; n; n = n->next) {
226                 size_t k;
227                 
228                 k = n->size;
229                 if (k > 255)
230                     k = 255;
231                 
232                 used += 1+k;
233             }
234         }
235     }
236
237     return used;
238 }
239
240 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
241
242     for (;;) {
243         if (!a && !b)
244             return 1;
245
246         if (!a || !b)
247             return 0;
248
249         if (a->size != b->size)
250             return 0;
251
252         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
253             return 0;
254
255         a = a->next;
256         b = b->next;
257     }
258 }
259
260 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
261     va_list va;
262
263     va_start(va, r);
264     r = avahi_string_list_add_many_va(r, va);
265     va_end(va);
266     
267     return r;
268 }
269
270 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
271     const char *txt;
272
273     while ((txt = va_arg(va, const char*)))
274         r = avahi_string_list_add(r, txt);
275
276     return r;
277 }
278
279 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
280     va_list va;
281     AvahiStringList *r = NULL;
282
283     if (txt) {
284         r = avahi_string_list_add(r, txt);
285
286         va_start(va, txt);
287         r = avahi_string_list_add_many_va(r, va);
288         va_end(va);
289     }
290
291     return r;
292 }
293
294 AvahiStringList *avahi_string_list_new_va(va_list va) {
295     return avahi_string_list_add_many_va(NULL, va);
296 }
297
298 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
299     AvahiStringList *r = NULL;
300
301     for (; l; l = l->next)
302         r = avahi_string_list_add_arbitrary(r, l->text, l->size);
303
304     return avahi_string_list_reverse(r);
305 }
306
307 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
308     AvahiStringList *r = NULL;
309     int i;
310
311     assert(array);
312
313     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
314         r = avahi_string_list_add(r, array[i]);
315
316     return r;
317 }
318
319 unsigned avahi_string_list_length(const AvahiStringList *l) {
320     unsigned n = 0;
321
322     for (; l; l = l->next)
323         n++;
324
325     return n;
326 }
327
328 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
329     size_t len = 80;
330     AvahiStringList *r;
331     
332     assert(format);
333
334     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
335         return NULL;
336
337     for (;;) {
338         int n;
339         AvahiStringList *nr;
340         
341         n = vsnprintf((char*) r->text, len+1, format, va);
342
343         if (n >= 0 && n < (int) len)
344             break;
345
346         if (n >= 0)
347             len = n+1;
348         else
349             len *= 2;
350
351         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
352             avahi_free(r);
353             return NULL;
354         }
355
356         r = nr;
357     }
358
359     
360     r->next = l;
361     r->size = strlen((char*) r->text); 
362
363     return r;
364 }
365
366 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
367     va_list va;
368     
369     assert(format);
370
371     va_start(va, format);
372     l  = avahi_string_list_add_vprintf(l, format, va);
373     va_end(va);
374
375     return l;    
376 }
377
378 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
379     size_t n;
380     
381     assert(key);
382     n = strlen(key);
383
384     for (; l; l = l->next) {
385         if (strcasecmp((char*) l->text, key) == 0)
386             return l;
387
388         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
389             return l;
390     }
391
392     return NULL;
393 }
394
395 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
396     assert(key);
397
398     if (value)
399         return avahi_string_list_add_printf(l, "%s=%s", key, value);
400     else
401         return avahi_string_list_add(l, key);
402 }
403
404 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
405     size_t n;
406     assert(key);
407
408     if (!value)
409         return avahi_string_list_add(l, key);
410
411     n = strlen(key);
412     
413     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
414         return NULL;
415
416     memcpy(l->text, key, n);
417     l->text[n] = '=';
418     memcpy(l->text + n + 1, value, size);
419
420     return l;
421 }
422
423 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
424     char *e;
425     
426     assert(l);
427
428     if (!(e = memchr(l->text, '=', l->size))) {
429
430         if (key) 
431             if (!(*key = avahi_strdup((char*) l->text)))
432                 return -1;
433
434         if (value)
435             *value = NULL;
436
437         if (size)
438             *size = 0;
439
440     } else {
441         size_t n;
442
443         if (key)
444             if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
445                 return -1;
446
447         e++; /* Advance after '=' */
448         
449         n = l->size - (e - (char*) l->text);
450         
451         if (value) {
452
453             if (!(*value = avahi_memdup(e, n+1))) {
454                 if (key)
455                     avahi_free(*key);
456                 return -1;
457             }
458
459             (*value)[n] = 0;
460         }
461
462         if (size)
463             *size = n;
464     }
465
466     return 0;
467 }
468
469 AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
470     assert(l);
471     return l->next;
472 }
473
474 uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
475     assert(l);
476     return l->text;
477 }
478
479 size_t avahi_string_list_get_size(AvahiStringList *l) {
480     assert(l);
481     return l->size;
482 }
483
484 uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
485     AvahiStringList *f;
486     char *value = NULL, *end = NULL;
487     uint32_t ret;
488     
489     if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
490         return AVAHI_SERVICE_COOKIE_INVALID;
491
492     if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
493         return AVAHI_SERVICE_COOKIE_INVALID;
494
495     ret = (uint32_t) strtoll(value, &end, 0);
496
497     if (*value && end && *end != 0) {
498         avahi_free(value);
499         return AVAHI_SERVICE_COOKIE_INVALID;
500     }
501
502     avahi_free(value);
503     
504     return ret;
505 }