merge glitch-free branch back into trunk
[platform/upstream/pulseaudio.git] / 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 }