merge 'lennart' 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 struct pa_tagstruct {
46     uint8_t *data;
47     size_t length, allocated;
48     size_t rindex;
49
50     int 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(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, int b) {
165     pa_assert(t);
166
167     extend(t, 1);
168     t->data[t->length] = 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(tv->tv_sec);
179     memcpy(t->data+t->length+1, &tmp, 4);
180     tmp = htonl(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 + 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 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
258     int error = 0;
259     size_t n;
260     char *c;
261
262     pa_assert(t);
263     pa_assert(s);
264
265     if (t->rindex+1 > t->length)
266         return -1;
267
268     if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
269         t->rindex++;
270         *s = NULL;
271         return 0;
272     }
273
274     if (t->rindex+2 > t->length)
275         return -1;
276
277     if (t->data[t->rindex] != PA_TAG_STRING)
278         return -1;
279
280     error = 1;
281     for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
282         if (!*c) {
283             error = 0;
284             break;
285         }
286
287     if (error)
288         return -1;
289
290     *s = (char*) (t->data+t->rindex+1);
291
292     t->rindex += n+2;
293     return 0;
294 }
295
296 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
297     pa_assert(t);
298     pa_assert(i);
299
300     if (t->rindex+5 > t->length)
301         return -1;
302
303     if (t->data[t->rindex] != PA_TAG_U32)
304         return -1;
305
306     memcpy(i, t->data+t->rindex+1, 4);
307     *i = ntohl(*i);
308     t->rindex += 5;
309     return 0;
310 }
311
312 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
313     pa_assert(t);
314     pa_assert(c);
315
316     if (t->rindex+2 > t->length)
317         return -1;
318
319     if (t->data[t->rindex] != PA_TAG_U8)
320         return -1;
321
322     *c = t->data[t->rindex+1];
323     t->rindex +=2;
324     return 0;
325 }
326
327 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
328     pa_assert(t);
329     pa_assert(ss);
330
331     if (t->rindex+7 > t->length)
332         return -1;
333
334     if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
335         return -1;
336
337     ss->format = t->data[t->rindex+1];
338     ss->channels = t->data[t->rindex+2];
339     memcpy(&ss->rate, t->data+t->rindex+3, 4);
340     ss->rate = ntohl(ss->rate);
341
342     t->rindex += 7;
343     return 0;
344 }
345
346 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
347     uint32_t len;
348
349     pa_assert(t);
350     pa_assert(p);
351
352     if (t->rindex+5+length > t->length)
353         return -1;
354
355     if (t->data[t->rindex] != PA_TAG_ARBITRARY)
356         return -1;
357
358     memcpy(&len, t->data+t->rindex+1, 4);
359     if (ntohl(len) != length)
360         return -1;
361
362     *p = t->data+t->rindex+5;
363     t->rindex += 5+length;
364     return 0;
365 }
366
367 int pa_tagstruct_eof(pa_tagstruct*t) {
368     pa_assert(t);
369
370     return t->rindex >= t->length;
371 }
372
373 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
374     pa_assert(t);
375     pa_assert(t->dynamic);
376     pa_assert(l);
377
378     *l = t->length;
379     return t->data;
380 }
381
382 int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
383     pa_assert(t);
384     pa_assert(b);
385
386     if (t->rindex+1 > t->length)
387         return -1;
388
389     if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
390         *b = 1;
391     else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
392         *b = 0;
393     else
394         return -1;
395
396     t->rindex +=1;
397     return 0;
398 }
399
400 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
401
402     pa_assert(t);
403     pa_assert(tv);
404
405     if (t->rindex+9 > t->length)
406         return -1;
407
408     if (t->data[t->rindex] != PA_TAG_TIMEVAL)
409         return -1;
410
411     memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
412     tv->tv_sec = ntohl(tv->tv_sec);
413     memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
414     tv->tv_usec = ntohl(tv->tv_usec);
415     t->rindex += 9;
416     return 0;
417 }
418
419 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
420     uint32_t tmp;
421
422     pa_assert(t);
423     pa_assert(u);
424
425     if (t->rindex+9 > t->length)
426         return -1;
427
428     if (t->data[t->rindex] != PA_TAG_USEC)
429         return -1;
430
431     memcpy(&tmp, t->data+t->rindex+1, 4);
432     *u = (pa_usec_t) ntohl(tmp) << 32;
433     memcpy(&tmp, t->data+t->rindex+5, 4);
434     *u |= (pa_usec_t) ntohl(tmp);
435     t->rindex +=9;
436     return 0;
437 }
438
439 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
440     uint32_t tmp;
441
442     pa_assert(t);
443     pa_assert(u);
444
445     if (t->rindex+9 > t->length)
446         return -1;
447
448     if (t->data[t->rindex] != PA_TAG_U64)
449         return -1;
450
451     memcpy(&tmp, t->data+t->rindex+1, 4);
452     *u = (uint64_t) ntohl(tmp) << 32;
453     memcpy(&tmp, t->data+t->rindex+5, 4);
454     *u |= (uint64_t) ntohl(tmp);
455     t->rindex +=9;
456     return 0;
457 }
458
459 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
460     uint32_t tmp;
461
462     pa_assert(t);
463     pa_assert(u);
464
465     if (t->rindex+9 > t->length)
466         return -1;
467
468     if (t->data[t->rindex] != PA_TAG_S64)
469         return -1;
470
471     memcpy(&tmp, t->data+t->rindex+1, 4);
472     *u = (int64_t) ((uint64_t) ntohl(tmp) << 32);
473     memcpy(&tmp, t->data+t->rindex+5, 4);
474     *u |= (int64_t) ntohl(tmp);
475     t->rindex +=9;
476     return 0;
477 }
478
479 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
480     unsigned i;
481
482     pa_assert(t);
483     pa_assert(map);
484
485     if (t->rindex+2 > t->length)
486         return -1;
487
488     if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
489         return -1;
490
491     if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
492         return -1;
493
494     if (t->rindex+2+map->channels > t->length)
495         return -1;
496
497     for (i = 0; i < map->channels; i ++)
498         map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
499
500     t->rindex += 2 + map->channels;
501     return 0;
502 }
503
504 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
505     unsigned i;
506     pa_volume_t vol;
507
508     pa_assert(t);
509     pa_assert(cvolume);
510
511     if (t->rindex+2 > t->length)
512         return -1;
513
514     if (t->data[t->rindex] != PA_TAG_CVOLUME)
515         return -1;
516
517     if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
518         return -1;
519
520     if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
521         return -1;
522
523     for (i = 0; i < cvolume->channels; i ++) {
524         memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
525         cvolume->values[i] = (pa_volume_t) ntohl(vol);
526     }
527
528     t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
529     return 0;
530 }
531
532 void pa_tagstruct_put(pa_tagstruct *t, ...) {
533     va_list va;
534     pa_assert(t);
535
536     va_start(va, t);
537
538     for (;;) {
539         int tag = va_arg(va, int);
540
541         if (tag == PA_TAG_INVALID)
542             break;
543
544         switch (tag) {
545             case PA_TAG_STRING:
546             case PA_TAG_STRING_NULL:
547                 pa_tagstruct_puts(t, va_arg(va, char*));
548                 break;
549
550             case PA_TAG_U32:
551                 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
552                 break;
553
554             case PA_TAG_U8:
555                 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
556                 break;
557
558             case PA_TAG_U64:
559                 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
560                 break;
561
562             case PA_TAG_SAMPLE_SPEC:
563                 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
564                 break;
565
566             case PA_TAG_ARBITRARY: {
567                 void *p = va_arg(va, void*);
568                 size_t size = va_arg(va, size_t);
569                 pa_tagstruct_put_arbitrary(t, p, size);
570                 break;
571             }
572
573             case PA_TAG_BOOLEAN_TRUE:
574             case PA_TAG_BOOLEAN_FALSE:
575                 pa_tagstruct_put_boolean(t, va_arg(va, int));
576                 break;
577
578             case PA_TAG_TIMEVAL:
579                 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
580                 break;
581
582             case PA_TAG_USEC:
583                 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
584                 break;
585
586             case PA_TAG_CHANNEL_MAP:
587                 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
588                 break;
589
590             case PA_TAG_CVOLUME:
591                 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
592                 break;
593
594             default:
595                 pa_assert_not_reached();
596         }
597     }
598
599     va_end(va);
600 }
601
602 int pa_tagstruct_get(pa_tagstruct *t, ...) {
603     va_list va;
604     int ret = 0;
605
606     pa_assert(t);
607
608     va_start(va, t);
609     while (ret == 0) {
610         int tag = va_arg(va, int);
611
612         if (tag == PA_TAG_INVALID)
613             break;
614
615         switch (tag) {
616             case PA_TAG_STRING:
617             case PA_TAG_STRING_NULL:
618                 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
619                 break;
620
621             case PA_TAG_U32:
622                 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
623                 break;
624
625             case PA_TAG_U8:
626                 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
627                 break;
628
629             case PA_TAG_U64:
630                 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
631                 break;
632
633             case PA_TAG_SAMPLE_SPEC:
634                 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
635                 break;
636
637             case PA_TAG_ARBITRARY: {
638                 const void **p = va_arg(va, const void**);
639                 size_t size = va_arg(va, size_t);
640                 ret = pa_tagstruct_get_arbitrary(t, p, size);
641                 break;
642             }
643
644             case PA_TAG_BOOLEAN_TRUE:
645             case PA_TAG_BOOLEAN_FALSE:
646                 ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
647                 break;
648
649             case PA_TAG_TIMEVAL:
650                 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
651                 break;
652
653             case PA_TAG_USEC:
654                 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
655                 break;
656
657             case PA_TAG_CHANNEL_MAP:
658                 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
659                 break;
660
661             case PA_TAG_CVOLUME:
662                 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
663                 break;
664
665             default:
666                 pa_assert_not_reached();
667         }
668
669     }
670
671     va_end(va);
672     return ret;
673 }