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