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