• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 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, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/time.h>
28 #include <stdarg.h>
29 
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
32 #endif
33 
34 #include <pulse/xmalloc.h>
35 
36 #include <pulsecore/socket.h>
37 #include <pulsecore/macro.h>
38 #include <pulsecore/flist.h>
39 
40 #include "tagstruct.h"
41 
42 #define MAX_TAG_SIZE (64*1024)
43 #define MAX_APPENDED_SIZE 128
44 #define GROW_TAG_SIZE 100
45 
46 struct pa_tagstruct {
47     uint8_t *data;
48     size_t length, allocated;
49     size_t rindex;
50 
51     enum {
52         PA_TAGSTRUCT_FIXED, /* The tagstruct does not own the data, buffer was provided by caller. */
53         PA_TAGSTRUCT_DYNAMIC, /* Buffer owned by tagstruct, data must be freed. */
54         PA_TAGSTRUCT_APPENDED, /* Data points to appended buffer, used for small tagstructs. Will change to dynamic if needed. */
55     } type;
56     union {
57         uint8_t appended[MAX_APPENDED_SIZE];
58     } per_type;
59 };
60 
61 PA_STATIC_FLIST_DECLARE(tagstructs, 0, pa_xfree);
62 
pa_tagstruct_new(void)63 pa_tagstruct *pa_tagstruct_new(void) {
64     pa_tagstruct*t;
65 
66     if (!(t = pa_flist_pop(PA_STATIC_FLIST_GET(tagstructs))))
67         t = pa_xnew(pa_tagstruct, 1);
68     t->data = t->per_type.appended;
69     t->allocated = MAX_APPENDED_SIZE;
70     t->length = t->rindex = 0;
71     t->type = PA_TAGSTRUCT_APPENDED;
72 
73     return t;
74 }
75 
pa_tagstruct_new_fixed(const uint8_t * data,size_t length)76 pa_tagstruct *pa_tagstruct_new_fixed(const uint8_t* data, size_t length) {
77     pa_tagstruct*t;
78 
79     pa_assert(data && length);
80 
81     if (!(t = pa_flist_pop(PA_STATIC_FLIST_GET(tagstructs))))
82         t = pa_xnew(pa_tagstruct, 1);
83     t->data = (uint8_t*) data;
84     t->allocated = t->length = length;
85     t->rindex = 0;
86     t->type = PA_TAGSTRUCT_FIXED;
87 
88     return t;
89 }
90 
pa_tagstruct_free(pa_tagstruct * t)91 void pa_tagstruct_free(pa_tagstruct*t) {
92     pa_assert(t);
93 
94     if (t->type == PA_TAGSTRUCT_DYNAMIC)
95         pa_xfree(t->data);
96     if (pa_flist_push(PA_STATIC_FLIST_GET(tagstructs), t) < 0)
97         pa_xfree(t);
98 }
99 
extend(pa_tagstruct * t,size_t l)100 static inline void extend(pa_tagstruct*t, size_t l) {
101     pa_assert(t);
102     pa_assert(t->type != PA_TAGSTRUCT_FIXED);
103 
104     if (t->length+l <= t->allocated)
105         return;
106 
107     if (t->type == PA_TAGSTRUCT_DYNAMIC)
108         t->data = pa_xrealloc(t->data, t->allocated = t->length + l + GROW_TAG_SIZE);
109     else if (t->type == PA_TAGSTRUCT_APPENDED) {
110         t->type = PA_TAGSTRUCT_DYNAMIC;
111         t->data = pa_xmalloc(t->allocated = t->length + l + GROW_TAG_SIZE);
112         memcpy(t->data, t->per_type.appended, t->length);
113     }
114 }
115 
write_u8(pa_tagstruct * t,uint8_t u)116 static void write_u8(pa_tagstruct *t, uint8_t u) {
117     extend(t, 1);
118     t->data[t->length++] = u;
119 }
120 
read_u8(pa_tagstruct * t,uint8_t * u)121 static int read_u8(pa_tagstruct *t, uint8_t *u) {
122     if (t->rindex + 1 > t->length)
123         return -1;
124 
125     *u = t->data[t->rindex++];
126     return 0;
127 }
128 
write_u32(pa_tagstruct * t,uint32_t u)129 static void write_u32(pa_tagstruct *t, uint32_t u) {
130     extend(t, 4);
131     u = htonl(u);
132     memcpy(t->data + t->length, &u, 4);
133     t->length += 4;
134 }
135 
read_u32(pa_tagstruct * t,uint32_t * u)136 static int read_u32(pa_tagstruct *t, uint32_t *u) {
137     if (t->rindex + 4 > t->length)
138         return -1;
139 
140     memcpy(u, t->data + t->rindex, 4);
141     *u = ntohl(*u);
142     t->rindex += 4;
143 
144     return 0;
145 }
146 
write_u64(pa_tagstruct * t,uint64_t u)147 static void write_u64(pa_tagstruct *t, uint64_t u) {
148     write_u32(t, u >> 32);
149     write_u32(t, u);
150 }
151 
read_u64(pa_tagstruct * t,uint64_t * u)152 static int read_u64(pa_tagstruct *t, uint64_t *u) {
153     uint32_t tmp;
154 
155     if (read_u32(t, &tmp) < 0)
156         return -1;
157 
158     *u = ((uint64_t) tmp) << 32;
159 
160     if (read_u32(t, &tmp) < 0)
161         return -1;
162 
163     *u |= tmp;
164     return 0;
165 }
166 
read_s64(pa_tagstruct * t,int64_t * u)167 static int read_s64(pa_tagstruct *t, int64_t *u) {
168     uint32_t tmp;
169 
170     if (read_u32(t, &tmp) < 0)
171         return -1;
172 
173     *u = (int64_t) (((uint64_t) tmp) << 32);
174 
175     if (read_u32(t, &tmp) < 0)
176         return -1;
177 
178     *u |= (int64_t) tmp;
179     return 0;
180 }
181 
write_arbitrary(pa_tagstruct * t,const void * p,size_t len)182 static void write_arbitrary(pa_tagstruct *t, const void *p, size_t len) {
183     extend(t, len);
184 
185     if (len > 0)
186         memcpy(t->data + t->length, p, len);
187 
188     t->length += len;
189 }
190 
read_arbitrary(pa_tagstruct * t,const void ** p,size_t length)191 static int read_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
192     if (t->rindex + length > t->length)
193         return -1;
194 
195     *p = t->data + t->rindex;
196     t->rindex += length;
197     return 0;
198 }
199 
pa_tagstruct_puts(pa_tagstruct * t,const char * s)200 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
201     size_t l;
202     pa_assert(t);
203 
204     if (s) {
205         write_u8(t, PA_TAG_STRING);
206         l = strlen(s)+1;
207         write_arbitrary(t, s, l);
208     } else
209         write_u8(t, PA_TAG_STRING_NULL);
210 }
211 
pa_tagstruct_putu32(pa_tagstruct * t,uint32_t i)212 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
213     pa_assert(t);
214 
215     write_u8(t, PA_TAG_U32);
216     write_u32(t, i);
217 }
218 
pa_tagstruct_putu8(pa_tagstruct * t,uint8_t c)219 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
220     pa_assert(t);
221 
222     write_u8(t, PA_TAG_U8);
223     write_u8(t, c);
224 }
225 
pa_tagstruct_put_sample_spec(pa_tagstruct * t,const pa_sample_spec * ss)226 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
227     pa_assert(t);
228     pa_assert(ss);
229 
230     write_u8(t, PA_TAG_SAMPLE_SPEC);
231     write_u8(t, ss->format);
232     write_u8(t, ss->channels);
233     write_u32(t, ss->rate);
234 }
235 
pa_tagstruct_put_arbitrary(pa_tagstruct * t,const void * p,size_t length)236 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
237     pa_assert(t);
238     pa_assert(p);
239 
240     write_u8(t, PA_TAG_ARBITRARY);
241     write_u32(t, length);
242     write_arbitrary(t, p, length);
243 }
244 
pa_tagstruct_put_boolean(pa_tagstruct * t,bool b)245 void pa_tagstruct_put_boolean(pa_tagstruct*t, bool b) {
246     pa_assert(t);
247 
248     write_u8(t, b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE);
249 }
250 
pa_tagstruct_put_timeval(pa_tagstruct * t,const struct timeval * tv)251 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
252     pa_assert(t);
253 
254     write_u8(t, PA_TAG_TIMEVAL);
255     write_u32(t, tv->tv_sec);
256     write_u32(t, tv->tv_usec);
257 }
258 
pa_tagstruct_put_usec(pa_tagstruct * t,pa_usec_t u)259 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
260     pa_assert(t);
261 
262     write_u8(t, PA_TAG_USEC);
263     write_u64(t, u);
264 }
265 
pa_tagstruct_putu64(pa_tagstruct * t,uint64_t u)266 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
267     pa_assert(t);
268 
269     write_u8(t, PA_TAG_U64);
270     write_u64(t, u);
271 }
272 
pa_tagstruct_puts64(pa_tagstruct * t,int64_t u)273 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
274     pa_assert(t);
275 
276     write_u8(t, PA_TAG_S64);
277     write_u64(t, u);
278 }
279 
pa_tagstruct_put_channel_map(pa_tagstruct * t,const pa_channel_map * map)280 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
281     unsigned i;
282 
283     pa_assert(t);
284     pa_assert(map);
285 
286     write_u8(t, PA_TAG_CHANNEL_MAP);
287     write_u8(t, map->channels);
288 
289     for (i = 0; i < map->channels; i ++)
290         write_u8(t, map->map[i]);
291 }
292 
pa_tagstruct_put_cvolume(pa_tagstruct * t,const pa_cvolume * cvolume)293 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
294     unsigned i;
295 
296     pa_assert(t);
297     pa_assert(cvolume);
298 
299     write_u8(t, PA_TAG_CVOLUME);
300     write_u8(t, cvolume->channels);
301 
302     for (i = 0; i < cvolume->channels; i ++)
303         write_u32(t, cvolume->values[i]);
304 }
305 
pa_tagstruct_put_volume(pa_tagstruct * t,pa_volume_t vol)306 void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t vol) {
307     pa_assert(t);
308 
309     write_u8(t, PA_TAG_VOLUME);
310     write_u32(t, vol);
311 }
312 
pa_tagstruct_put_proplist(pa_tagstruct * t,const pa_proplist * p)313 void pa_tagstruct_put_proplist(pa_tagstruct *t, const pa_proplist *p) {
314     void *state = NULL;
315     pa_assert(t);
316     pa_assert(p);
317 
318     write_u8(t, PA_TAG_PROPLIST);
319 
320     for (;;) {
321         const char *k;
322         const void *d;
323         size_t l;
324 
325         if (!(k = pa_proplist_iterate(p, &state)))
326             break;
327 
328         pa_tagstruct_puts(t, k);
329         pa_assert_se(pa_proplist_get(p, k, &d, &l) >= 0);
330         pa_tagstruct_putu32(t, (uint32_t) l);
331         pa_tagstruct_put_arbitrary(t, d, l);
332     }
333 
334     pa_tagstruct_puts(t, NULL);
335 }
336 
pa_tagstruct_put_format_info(pa_tagstruct * t,const pa_format_info * f)337 void pa_tagstruct_put_format_info(pa_tagstruct *t, const pa_format_info *f) {
338     pa_assert(t);
339     pa_assert(f);
340 
341     write_u8(t, PA_TAG_FORMAT_INFO);
342     pa_tagstruct_putu8(t, (uint8_t) f->encoding);
343     pa_tagstruct_put_proplist(t, f->plist);
344 }
345 
read_tag(pa_tagstruct * t,uint8_t type)346 static int read_tag(pa_tagstruct *t, uint8_t type) {
347     if (t->rindex + 1 > t->length)
348         return -1;
349 
350     if (t->data[t->rindex] != type)
351         return -1;
352 
353     t->rindex++;
354 
355     return 0;
356 }
357 
pa_tagstruct_gets(pa_tagstruct * t,const char ** s)358 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
359     int error = 0;
360     size_t n;
361     char *c;
362 
363     pa_assert(t);
364     pa_assert(s);
365 
366     if (t->rindex+1 > t->length)
367         return -1;
368 
369     if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
370         t->rindex++;
371         *s = NULL;
372         return 0;
373     }
374 
375     if (read_tag(t, PA_TAG_STRING) < 0)
376         return -1;
377 
378     if (t->rindex + 1 > t->length)
379         return -1;
380 
381     error = 1;
382     for (n = 0, c = (char*) (t->data + t->rindex); t->rindex + n < t->length; n++, c++)
383         if (!*c) {
384             error = 0;
385             break;
386         }
387 
388     if (error)
389         return -1;
390 
391     *s = (char*) (t->data + t->rindex);
392 
393     t->rindex += n + 1;
394     return 0;
395 }
396 
pa_tagstruct_getu32(pa_tagstruct * t,uint32_t * i)397 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
398     pa_assert(t);
399     pa_assert(i);
400 
401     if (read_tag(t, PA_TAG_U32) < 0)
402         return -1;
403 
404     return read_u32(t, i);
405 }
406 
pa_tagstruct_getu8(pa_tagstruct * t,uint8_t * c)407 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
408     pa_assert(t);
409     pa_assert(c);
410 
411     if (read_tag(t, PA_TAG_U8) < 0)
412         return -1;
413 
414     return read_u8(t, c);
415 }
416 
pa_tagstruct_get_sample_spec(pa_tagstruct * t,pa_sample_spec * ss)417 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
418     uint8_t tmp;
419 
420     pa_assert(t);
421     pa_assert(ss);
422 
423     if (read_tag(t, PA_TAG_SAMPLE_SPEC) < 0)
424         return -1;
425 
426     if (read_u8(t, &tmp) < 0)
427         return -1;
428 
429     ss->format = tmp;
430 
431     if (read_u8(t, &ss->channels) < 0)
432         return -1;
433 
434     return read_u32(t, &ss->rate);
435 }
436 
pa_tagstruct_get_arbitrary(pa_tagstruct * t,const void ** p,size_t length)437 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
438     uint32_t len;
439 
440     pa_assert(t);
441     pa_assert(p);
442 
443     if (read_tag(t, PA_TAG_ARBITRARY) < 0)
444         return -1;
445 
446     if (read_u32(t, &len) < 0 || len != length)
447         return -1;
448 
449     return read_arbitrary(t, p, length);
450 }
451 
pa_tagstruct_eof(pa_tagstruct * t)452 int pa_tagstruct_eof(pa_tagstruct*t) {
453     pa_assert(t);
454 
455     return t->rindex >= t->length;
456 }
457 
pa_tagstruct_data(pa_tagstruct * t,size_t * l)458 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
459     pa_assert(t);
460     pa_assert(l);
461 
462     *l = t->length;
463     return t->data;
464 }
465 
pa_tagstruct_get_boolean(pa_tagstruct * t,bool * b)466 int pa_tagstruct_get_boolean(pa_tagstruct*t, bool *b) {
467     pa_assert(t);
468     pa_assert(b);
469 
470     if (t->rindex+1 > t->length)
471         return -1;
472 
473     if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
474         *b = true;
475     else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
476         *b = false;
477     else
478         return -1;
479 
480     t->rindex +=1;
481     return 0;
482 }
483 
pa_tagstruct_get_timeval(pa_tagstruct * t,struct timeval * tv)484 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
485     uint32_t tmp;
486 
487     pa_assert(t);
488     pa_assert(tv);
489 
490     if (read_tag(t, PA_TAG_TIMEVAL) < 0)
491         return -1;
492 
493     if (read_u32(t, &tmp) < 0)
494         return -1;
495 
496     tv->tv_sec = tmp;
497 
498     if (read_u32(t, &tmp) < 0)
499         return -1;
500 
501     tv->tv_usec = tmp;
502 
503     return 0;
504 }
505 
pa_tagstruct_get_usec(pa_tagstruct * t,pa_usec_t * u)506 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
507     pa_assert(t);
508     pa_assert(u);
509 
510     if (read_tag(t, PA_TAG_USEC) < 0)
511         return -1;
512 
513     return read_u64(t, u);
514 }
515 
pa_tagstruct_getu64(pa_tagstruct * t,uint64_t * u)516 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
517     pa_assert(t);
518     pa_assert(u);
519 
520     if (read_tag(t, PA_TAG_U64) < 0)
521         return -1;
522 
523     return read_u64(t, u);
524 }
525 
pa_tagstruct_gets64(pa_tagstruct * t,int64_t * u)526 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
527     pa_assert(t);
528     pa_assert(u);
529 
530     if (read_tag(t, PA_TAG_S64) < 0)
531         return -1;
532 
533     return read_s64(t, u);
534 }
535 
pa_tagstruct_get_channel_map(pa_tagstruct * t,pa_channel_map * map)536 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
537     unsigned i;
538 
539     pa_assert(t);
540     pa_assert(map);
541 
542     if (read_tag(t, PA_TAG_CHANNEL_MAP) < 0)
543         return -1;
544 
545     if (read_u8(t, &map->channels) < 0 || map->channels > PA_CHANNELS_MAX)
546         return -1;
547 
548     for (i = 0; i < map->channels; i ++) {
549         uint8_t tmp;
550 
551         if (read_u8(t, &tmp) < 0)
552             return -1;
553 
554         map->map[i] = tmp;
555     }
556 
557     return 0;
558 }
559 
pa_tagstruct_get_cvolume(pa_tagstruct * t,pa_cvolume * cvolume)560 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
561     unsigned i;
562 
563     pa_assert(t);
564     pa_assert(cvolume);
565 
566     if (read_tag(t, PA_TAG_CVOLUME) < 0)
567         return -1;
568 
569     if (read_u8(t, &cvolume->channels) < 0 || cvolume->channels > PA_CHANNELS_MAX)
570         return -1;
571 
572     for (i = 0; i < cvolume->channels; i ++) {
573         if (read_u32(t, &cvolume->values[i]) < 0)
574             return -1;
575     }
576 
577     return 0;
578 }
579 
pa_tagstruct_get_volume(pa_tagstruct * t,pa_volume_t * vol)580 int pa_tagstruct_get_volume(pa_tagstruct*t, pa_volume_t *vol) {
581     pa_assert(t);
582     pa_assert(vol);
583 
584     if (read_tag(t, PA_TAG_VOLUME) < 0)
585         return -1;
586 
587     return read_u32(t, vol);
588 }
589 
pa_tagstruct_get_proplist(pa_tagstruct * t,pa_proplist * p)590 int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p) {
591     pa_assert(t);
592 
593     if (read_tag(t, PA_TAG_PROPLIST) < 0)
594         return -1;
595 
596     for (;;) {
597         const char *k;
598         const void *d;
599         uint32_t length;
600 
601         if (pa_tagstruct_gets(t, &k) < 0)
602             return -1;
603 
604         if (!k)
605             break;
606 
607         if (!pa_proplist_key_valid(k))
608             return -1;
609 
610         if (pa_tagstruct_getu32(t, &length) < 0)
611             return -1;
612 
613         if (length > MAX_TAG_SIZE)
614             return -1;
615 
616         if (pa_tagstruct_get_arbitrary(t, &d, length) < 0)
617             return -1;
618 
619         if (p)
620             pa_assert_se(pa_proplist_set(p, k, d, length) >= 0);
621     }
622 
623     return 0;
624 }
625 
pa_tagstruct_get_format_info(pa_tagstruct * t,pa_format_info * f)626 int pa_tagstruct_get_format_info(pa_tagstruct *t, pa_format_info *f) {
627     uint8_t encoding;
628 
629     pa_assert(t);
630     pa_assert(f);
631 
632     if (read_tag(t, PA_TAG_FORMAT_INFO) < 0)
633         return -1;
634 
635     if (pa_tagstruct_getu8(t, &encoding) < 0)
636         return -1;
637 
638     f->encoding = encoding;
639 
640     return pa_tagstruct_get_proplist(t, f->plist);
641 }
642 
pa_tagstruct_put(pa_tagstruct * t,...)643 void pa_tagstruct_put(pa_tagstruct *t, ...) {
644     va_list va;
645     pa_assert(t);
646 
647     va_start(va, t);
648 
649     for (;;) {
650         int tag = va_arg(va, int);
651 
652         if (tag == PA_TAG_INVALID)
653             break;
654 
655         switch (tag) {
656             case PA_TAG_STRING:
657             case PA_TAG_STRING_NULL:
658                 pa_tagstruct_puts(t, va_arg(va, char*));
659                 break;
660 
661             case PA_TAG_U32:
662                 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
663                 break;
664 
665             case PA_TAG_U8:
666                 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
667                 break;
668 
669             case PA_TAG_U64:
670                 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
671                 break;
672 
673             case PA_TAG_SAMPLE_SPEC:
674                 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
675                 break;
676 
677             case PA_TAG_ARBITRARY: {
678                 void *p = va_arg(va, void*);
679                 size_t size = va_arg(va, size_t);
680                 pa_tagstruct_put_arbitrary(t, p, size);
681                 break;
682             }
683 
684             case PA_TAG_BOOLEAN_TRUE:
685             case PA_TAG_BOOLEAN_FALSE:
686                 pa_tagstruct_put_boolean(t, va_arg(va, int));
687                 break;
688 
689             case PA_TAG_TIMEVAL:
690                 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
691                 break;
692 
693             case PA_TAG_USEC:
694                 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
695                 break;
696 
697             case PA_TAG_CHANNEL_MAP:
698                 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
699                 break;
700 
701             case PA_TAG_CVOLUME:
702                 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
703                 break;
704 
705             case PA_TAG_VOLUME:
706                 pa_tagstruct_put_volume(t, va_arg(va, pa_volume_t));
707                 break;
708 
709             case PA_TAG_PROPLIST:
710                 pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
711                 break;
712 
713             default:
714                 pa_assert_not_reached();
715         }
716     }
717 
718     va_end(va);
719 }
720 
pa_tagstruct_get(pa_tagstruct * t,...)721 int pa_tagstruct_get(pa_tagstruct *t, ...) {
722     va_list va;
723     int ret = 0;
724 
725     pa_assert(t);
726 
727     va_start(va, t);
728     while (ret == 0) {
729         int tag = va_arg(va, int);
730 
731         if (tag == PA_TAG_INVALID)
732             break;
733 
734         switch (tag) {
735             case PA_TAG_STRING:
736             case PA_TAG_STRING_NULL:
737                 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
738                 break;
739 
740             case PA_TAG_U32:
741                 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
742                 break;
743 
744             case PA_TAG_U8:
745                 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
746                 break;
747 
748             case PA_TAG_U64:
749                 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
750                 break;
751 
752             case PA_TAG_SAMPLE_SPEC:
753                 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
754                 break;
755 
756             case PA_TAG_ARBITRARY: {
757                 const void **p = va_arg(va, const void**);
758                 size_t size = va_arg(va, size_t);
759                 ret = pa_tagstruct_get_arbitrary(t, p, size);
760                 break;
761             }
762 
763             case PA_TAG_BOOLEAN_TRUE:
764             case PA_TAG_BOOLEAN_FALSE:
765                 ret = pa_tagstruct_get_boolean(t, va_arg(va, bool*));
766                 break;
767 
768             case PA_TAG_TIMEVAL:
769                 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
770                 break;
771 
772             case PA_TAG_USEC:
773                 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
774                 break;
775 
776             case PA_TAG_CHANNEL_MAP:
777                 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
778                 break;
779 
780             case PA_TAG_CVOLUME:
781                 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
782                 break;
783 
784             case PA_TAG_VOLUME:
785                 ret = pa_tagstruct_get_volume(t, va_arg(va, pa_volume_t *));
786                 break;
787 
788             case PA_TAG_PROPLIST:
789                 ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
790                 break;
791 
792             default:
793                 pa_assert_not_reached();
794         }
795 
796     }
797 
798     va_end(va);
799     return ret;
800 }
801