commit glitch-free work
[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, 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 }