]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
forgot to pull the publish_no_reverse change to the example.
[catta] / avahi-common / strlst.c
1 /***
2   This file is part of avahi.
3
4   avahi is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2.1 of the
7   License, or (at your option) any later version.
8
9   avahi is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12   Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with avahi; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <stdarg.h>
26 #include <assert.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "strlst.h"
31 #include "malloc.h"
32 #include "defs.h"
33
34 AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
35     AvahiStringList *n;
36
37     if (!(n = avahi_malloc(sizeof(AvahiStringList) + size)))
38         return NULL;
39
40     n->next = l;
41     n->size = size;
42
43     /* NUL terminate strings, just to make sure */
44     n->text[size] = 0;
45
46     return n;
47 }
48
49 AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
50     AvahiStringList *n;
51
52     assert(size == 0 || text);
53
54     if (!(n = avahi_string_list_add_anonymous(l, size)))
55         return NULL;
56
57     if (size > 0)
58         memcpy(n->text, text, size);
59
60     return n;
61 }
62
63 AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
64     assert(text);
65
66     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
67 }
68
69 int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
70     const uint8_t *c;
71     AvahiStringList *r = NULL;
72
73     assert(data);
74     assert(ret);
75
76     c = data;
77     while (size > 0) {
78         size_t k;
79
80         k = *(c++);
81         size--;
82
83         if (k > size)
84             goto fail; /* Overflow */
85
86         if (k > 0) { /* Ignore empty strings */
87             AvahiStringList *n;
88
89             if (!(n = avahi_string_list_add_arbitrary(r, c, k)))
90                 goto fail; /* OOM */
91
92             r = n;
93         }
94
95         c += k;
96         size -= k;
97     }
98
99     *ret = r;
100
101     return 0;
102
103 fail:
104     avahi_string_list_free(r);
105     return -1;
106 }
107
108 void avahi_string_list_free(AvahiStringList *l) {
109     AvahiStringList *n;
110
111     while (l) {
112         n = l->next;
113         avahi_free(l);
114         l = n;
115     }
116 }
117
118 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
119     AvahiStringList *r = NULL, *n;
120
121     while (l) {
122         n = l->next;
123         l->next = r;
124         r = l;
125         l = n;
126     }
127
128     return r;
129 }
130
131 char* avahi_string_list_to_string(AvahiStringList *l) {
132     AvahiStringList *n;
133     size_t s = 0;
134     char *t, *e;
135
136     for (n = l; n; n = n->next) {
137         if (n != l)
138             s ++;
139
140         s += n->size+2;
141     }
142
143     if (!(t = e = avahi_new(char, s+1)))
144         return NULL;
145
146     l = avahi_string_list_reverse(l);
147
148     for (n = l; n; n = n->next) {
149         if (n != l)
150             *(e++) = ' ';
151
152         *(e++) = '"';
153         strncpy(e, (char*) n->text, n->size);
154         e[n->size] = 0;
155         e = strchr(e, 0);
156         *(e++) = '"';
157
158         assert(e);
159     }
160
161     l = avahi_string_list_reverse(l);
162
163     *e = 0;
164
165     return t;
166 }
167
168 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
169     size_t used = 0;
170
171     if (data) {
172         AvahiStringList *n;
173         uint8_t *c;
174
175         l = avahi_string_list_reverse(l);
176         c = data;
177
178         for (n = l; size > 1 && n; n = n->next) {
179             size_t k;
180
181             if ((k = n->size) == 0)
182                 /* Skip empty strings */
183                 continue;
184
185             if (k > 255)
186                 /* Truncate strings at 255 characters */
187                 k = 255;
188
189             if (k > size-1)
190                 /* Make sure this string fits in */
191                 k = size-1;
192
193             *(c++) = (uint8_t) k;
194             memcpy(c, n->text, k);
195             c += k;
196
197             used += 1 + k;
198             size -= 1 + k;
199         }
200
201         l = avahi_string_list_reverse(l);
202
203         if (used == 0 && size > 0) {
204
205             /* Empty lists are treated specially. To comply with
206              * section 6.1 of the DNS-SD spec, we return a single
207              * empty string (i.e. a NUL byte)*/
208
209             *(uint8_t*) data = 0;
210             used = 1;
211         }
212
213     } else {
214         AvahiStringList *n;
215
216         for (n = l; n; n = n->next) {
217             size_t k;
218
219             if ((k = n->size) == 0)
220                 continue;
221
222             if (k > 255)
223                 k = 255;
224
225             used += 1+k;
226         }
227
228         if (used == 0)
229             used = 1;
230     }
231
232     return used;
233 }
234
235 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
236
237     for (;;) {
238         if (!a && !b)
239             return 1;
240
241         if (!a || !b)
242             return 0;
243
244         if (a->size != b->size)
245             return 0;
246
247         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
248             return 0;
249
250         a = a->next;
251         b = b->next;
252     }
253 }
254
255 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
256     va_list va;
257
258     va_start(va, r);
259     r = avahi_string_list_add_many_va(r, va);
260     va_end(va);
261
262     return r;
263 }
264
265 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
266     const char *txt;
267
268     while ((txt = va_arg(va, const char*)))
269         r = avahi_string_list_add(r, txt);
270
271     return r;
272 }
273
274 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
275     va_list va;
276     AvahiStringList *r = NULL;
277
278     if (txt) {
279         r = avahi_string_list_add(r, txt);
280
281         va_start(va, txt);
282         r = avahi_string_list_add_many_va(r, va);
283         va_end(va);
284     }
285
286     return r;
287 }
288
289 AvahiStringList *avahi_string_list_new_va(va_list va) {
290     return avahi_string_list_add_many_va(NULL, va);
291 }
292
293 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
294     AvahiStringList *r = NULL;
295
296     for (; l; l = l->next)
297         if (!(r = avahi_string_list_add_arbitrary(r, l->text, l->size))) {
298             avahi_string_list_free(r);
299             return NULL;
300         }
301
302     return avahi_string_list_reverse(r);
303 }
304
305 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
306     AvahiStringList *r = NULL;
307     int i;
308
309     assert(array);
310
311     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
312         r = avahi_string_list_add(r, array[i]);
313
314     return r;
315 }
316
317 unsigned avahi_string_list_length(const AvahiStringList *l) {
318     unsigned n = 0;
319
320     for (; l; l = l->next)
321         n++;
322
323     return n;
324 }
325
326 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
327     size_t len = 80;
328     AvahiStringList *r;
329
330     assert(format);
331
332     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
333         return NULL;
334
335     for (;;) {
336         int n;
337         AvahiStringList *nr;
338         va_list va2;
339
340         va_copy(va2, va);
341         n = vsnprintf((char*) r->text, len, format, va2);
342         va_end(va2);
343
344         if (n >= 0 && n < (int) len)
345             break;
346
347         if (n >= 0)
348             len = n+1;
349         else
350             len *= 2;
351
352         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
353             avahi_free(r);
354             return NULL;
355         }
356
357         r = nr;
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 }