]> code.delx.au - pulseaudio/blob - src/pulsecore/tagstruct.c
commit glitch-free work
[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, int 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, int *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 = 1;
419 else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
420 *b = 0;
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
574 for (;;) {
575 const char *k;
576 void *d;
577 uint32_t length;
578
579 if (pa_tagstruct_gets(t, &k) < 0)
580 goto fail;
581
582 if (!k)
583 break;
584
585 if (pa_tagstruct_getu32(t, &length) < 0)
586 goto fail;
587
588 if (length > MAX_TAG_SIZE)
589 goto fail;
590
591 d = pa_xmalloc(length);
592
593 if (pa_tagstruct_get_arbitrary(t, d, length) < 0)
594 goto fail;
595
596 if (pa_proplist_set(p, k, d, length) < 0) {
597 pa_xfree(d);
598 goto fail;
599 }
600
601 pa_xfree(d);
602 }
603
604 return 0;
605
606 fail:
607 t->rindex = saved_rindex;
608 return -1;
609 }
610
611 void pa_tagstruct_put(pa_tagstruct *t, ...) {
612 va_list va;
613 pa_assert(t);
614
615 va_start(va, t);
616
617 for (;;) {
618 int tag = va_arg(va, int);
619
620 if (tag == PA_TAG_INVALID)
621 break;
622
623 switch (tag) {
624 case PA_TAG_STRING:
625 case PA_TAG_STRING_NULL:
626 pa_tagstruct_puts(t, va_arg(va, char*));
627 break;
628
629 case PA_TAG_U32:
630 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
631 break;
632
633 case PA_TAG_U8:
634 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
635 break;
636
637 case PA_TAG_U64:
638 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
639 break;
640
641 case PA_TAG_SAMPLE_SPEC:
642 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
643 break;
644
645 case PA_TAG_ARBITRARY: {
646 void *p = va_arg(va, void*);
647 size_t size = va_arg(va, size_t);
648 pa_tagstruct_put_arbitrary(t, p, size);
649 break;
650 }
651
652 case PA_TAG_BOOLEAN_TRUE:
653 case PA_TAG_BOOLEAN_FALSE:
654 pa_tagstruct_put_boolean(t, va_arg(va, int));
655 break;
656
657 case PA_TAG_TIMEVAL:
658 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
659 break;
660
661 case PA_TAG_USEC:
662 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
663 break;
664
665 case PA_TAG_CHANNEL_MAP:
666 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
667 break;
668
669 case PA_TAG_CVOLUME:
670 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
671 break;
672
673 case PA_TAG_PROPLIST:
674 pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
675
676 default:
677 pa_assert_not_reached();
678 }
679 }
680
681 va_end(va);
682 }
683
684 int pa_tagstruct_get(pa_tagstruct *t, ...) {
685 va_list va;
686 int ret = 0;
687
688 pa_assert(t);
689
690 va_start(va, t);
691 while (ret == 0) {
692 int tag = va_arg(va, int);
693
694 if (tag == PA_TAG_INVALID)
695 break;
696
697 switch (tag) {
698 case PA_TAG_STRING:
699 case PA_TAG_STRING_NULL:
700 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
701 break;
702
703 case PA_TAG_U32:
704 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
705 break;
706
707 case PA_TAG_U8:
708 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
709 break;
710
711 case PA_TAG_U64:
712 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
713 break;
714
715 case PA_TAG_SAMPLE_SPEC:
716 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
717 break;
718
719 case PA_TAG_ARBITRARY: {
720 const void **p = va_arg(va, const void**);
721 size_t size = va_arg(va, size_t);
722 ret = pa_tagstruct_get_arbitrary(t, p, size);
723 break;
724 }
725
726 case PA_TAG_BOOLEAN_TRUE:
727 case PA_TAG_BOOLEAN_FALSE:
728 ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
729 break;
730
731 case PA_TAG_TIMEVAL:
732 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
733 break;
734
735 case PA_TAG_USEC:
736 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
737 break;
738
739 case PA_TAG_CHANNEL_MAP:
740 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
741 break;
742
743 case PA_TAG_CVOLUME:
744 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
745 break;
746
747 case PA_TAG_PROPLIST:
748 ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
749
750 default:
751 pa_assert_not_reached();
752 }
753
754 }
755
756 va_end(va);
757 return ret;
758 }