Add copyright notices to all relevant files. (based on svn log)
[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 <assert.h>
33 #include <stdarg.h>
34
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
37 #endif
38
39 #include "winsock.h"
40
41 #include <pulse/xmalloc.h>
42
43 #include "tagstruct.h"
44
45
46 struct pa_tagstruct {
47     uint8_t *data;
48     size_t length, allocated;
49     size_t rindex;
50
51     int dynamic;
52 };
53
54 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
55     pa_tagstruct*t;
56
57     assert(!data || (data && length));
58
59     t = pa_xmalloc(sizeof(pa_tagstruct));
60     t->data = (uint8_t*) data;
61     t->allocated = t->length = data ? length : 0;
62     t->rindex = 0;
63     t->dynamic = !data;
64     return t;
65 }
66
67 void pa_tagstruct_free(pa_tagstruct*t) {
68     assert(t);
69     if (t->dynamic)
70         pa_xfree(t->data);
71     pa_xfree(t);
72 }
73
74 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
75     uint8_t *p;
76     assert(t && t->dynamic && l);
77     p = t->data;
78     *l = t->length;
79     pa_xfree(t);
80     return p;
81 }
82
83 static void extend(pa_tagstruct*t, size_t l) {
84     assert(t);
85     assert(t->dynamic);
86
87     if (t->length+l <= t->allocated)
88         return;
89
90     t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
91 }
92
93 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
94     size_t l;
95     assert(t);
96     if (s) {
97         l = strlen(s)+2;
98         extend(t, l);
99         t->data[t->length] = PA_TAG_STRING;
100         strcpy((char*) (t->data+t->length+1), s);
101         t->length += l;
102     } else {
103         extend(t, 1);
104         t->data[t->length] = PA_TAG_STRING_NULL;
105         t->length += 1;
106     }
107 }
108
109 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
110     assert(t);
111     extend(t, 5);
112     t->data[t->length] = PA_TAG_U32;
113     i = htonl(i);
114     memcpy(t->data+t->length+1, &i, 4);
115     t->length += 5;
116 }
117
118 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
119     assert(t);
120     extend(t, 2);
121     t->data[t->length] = PA_TAG_U8;
122     *(t->data+t->length+1) = c;
123     t->length += 2;
124 }
125
126 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
127     uint32_t rate;
128     assert(t && ss);
129     extend(t, 7);
130     t->data[t->length] = PA_TAG_SAMPLE_SPEC;
131     t->data[t->length+1] = (uint8_t) ss->format;
132     t->data[t->length+2] = ss->channels;
133     rate = htonl(ss->rate);
134     memcpy(t->data+t->length+3, &rate, 4);
135     t->length += 7;
136 }
137
138 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
139     uint32_t tmp;
140     assert(t && p);
141
142     extend(t, 5+length);
143     t->data[t->length] = PA_TAG_ARBITRARY;
144     tmp = htonl(length);
145     memcpy(t->data+t->length+1, &tmp, 4);
146     if (length)
147         memcpy(t->data+t->length+5, p, length);
148     t->length += 5+length;
149 }
150
151 void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) {
152     assert(t);
153     extend(t, 1);
154     t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE;
155     t->length += 1;
156 }
157
158 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
159     uint32_t tmp;
160     assert(t);
161     extend(t, 9);
162     t->data[t->length] = PA_TAG_TIMEVAL;
163     tmp = htonl(tv->tv_sec);
164     memcpy(t->data+t->length+1, &tmp, 4);
165     tmp = htonl(tv->tv_usec);
166     memcpy(t->data+t->length+5, &tmp, 4);
167     t->length += 9;
168 }
169
170 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
171     uint32_t tmp;
172     assert(t);
173     extend(t, 9);
174     t->data[t->length] = PA_TAG_USEC;
175     tmp = htonl((uint32_t) (u >> 32));
176     memcpy(t->data+t->length+1, &tmp, 4);
177     tmp = htonl((uint32_t) u);
178     memcpy(t->data+t->length+5, &tmp, 4);
179     t->length += 9;
180 }
181
182 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
183     uint32_t tmp;
184     assert(t);
185     extend(t, 9);
186     t->data[t->length] = PA_TAG_U64;
187     tmp = htonl((uint32_t) (u >> 32));
188     memcpy(t->data+t->length+1, &tmp, 4);
189     tmp = htonl((uint32_t) u);
190     memcpy(t->data+t->length+5, &tmp, 4);
191     t->length += 9;
192 }
193
194 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
195     uint32_t tmp;
196     assert(t);
197     extend(t, 9);
198     t->data[t->length] = PA_TAG_S64;
199     tmp = htonl((uint32_t) ((uint64_t) u >> 32));
200     memcpy(t->data+t->length+1, &tmp, 4);
201     tmp = htonl((uint32_t) ((uint64_t) u));
202     memcpy(t->data+t->length+5, &tmp, 4);
203     t->length += 9;
204 }
205
206 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
207     unsigned i;
208
209     assert(t);
210     extend(t, 2 + map->channels);
211
212     t->data[t->length++] = PA_TAG_CHANNEL_MAP;
213     t->data[t->length++] = map->channels;
214
215     for (i = 0; i < map->channels; i ++)
216         t->data[t->length++] = (uint8_t) map->map[i];
217 }
218
219 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
220     unsigned i;
221     pa_volume_t vol;
222
223     assert(t);
224     extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
225
226     t->data[t->length++] = PA_TAG_CVOLUME;
227     t->data[t->length++] = cvolume->channels;
228
229     for (i = 0; i < cvolume->channels; i ++) {
230         vol = htonl(cvolume->values[i]);
231         memcpy(t->data + t->length, &vol, sizeof(pa_volume_t));
232         t->length += sizeof(pa_volume_t);
233     }
234 }
235
236 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
237     int error = 0;
238     size_t n;
239     char *c;
240     assert(t && s);
241
242     if (t->rindex+1 > t->length)
243         return -1;
244
245     if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
246         t->rindex++;
247         *s = NULL;
248         return 0;
249     }
250
251     if (t->rindex+2 > t->length)
252         return -1;
253
254     if (t->data[t->rindex] != PA_TAG_STRING)
255         return -1;
256
257     error = 1;
258     for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
259         if (!*c) {
260             error = 0;
261             break;
262         }
263
264     if (error)
265         return -1;
266
267     *s = (char*) (t->data+t->rindex+1);
268
269     t->rindex += n+2;
270     return 0;
271 }
272
273 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
274     assert(t && i);
275
276     if (t->rindex+5 > t->length)
277         return -1;
278
279     if (t->data[t->rindex] != PA_TAG_U32)
280         return -1;
281
282     memcpy(i, t->data+t->rindex+1, 4);
283     *i = ntohl(*i);
284     t->rindex += 5;
285     return 0;
286 }
287
288 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
289     assert(t && c);
290
291     if (t->rindex+2 > t->length)
292         return -1;
293
294     if (t->data[t->rindex] != PA_TAG_U8)
295         return -1;
296
297     *c = t->data[t->rindex+1];
298     t->rindex +=2;
299     return 0;
300 }
301
302 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
303     assert(t && ss);
304
305     if (t->rindex+7 > t->length)
306         return -1;
307
308     if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
309         return -1;
310
311     ss->format = t->data[t->rindex+1];
312     ss->channels = t->data[t->rindex+2];
313     memcpy(&ss->rate, t->data+t->rindex+3, 4);
314     ss->rate = ntohl(ss->rate);
315
316     t->rindex += 7;
317     return 0;
318 }
319
320 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
321     uint32_t len;
322     assert(t && p);
323
324     if (t->rindex+5+length > t->length)
325         return -1;
326
327     if (t->data[t->rindex] != PA_TAG_ARBITRARY)
328         return -1;
329
330     memcpy(&len, t->data+t->rindex+1, 4);
331     if (ntohl(len) != length)
332         return -1;
333
334     *p = t->data+t->rindex+5;
335     t->rindex += 5+length;
336     return 0;
337 }
338
339 int pa_tagstruct_eof(pa_tagstruct*t) {
340     assert(t);
341     return t->rindex >= t->length;
342 }
343
344 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
345     assert(t && t->dynamic && l);
346     *l = t->length;
347     return t->data;
348 }
349
350 int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
351     assert(t && b);
352
353     if (t->rindex+1 > t->length)
354         return -1;
355
356     if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
357         *b = 1;
358     else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
359         *b = 0;
360     else
361         return -1;
362
363     t->rindex +=1;
364     return 0;
365 }
366
367 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
368
369     if (t->rindex+9 > t->length)
370         return -1;
371
372     if (t->data[t->rindex] != PA_TAG_TIMEVAL)
373         return -1;
374
375     memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
376     tv->tv_sec = ntohl(tv->tv_sec);
377     memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
378     tv->tv_usec = ntohl(tv->tv_usec);
379     t->rindex += 9;
380     return 0;
381 }
382
383 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
384     uint32_t tmp;
385     assert(t && u);
386
387     if (t->rindex+9 > t->length)
388         return -1;
389
390     if (t->data[t->rindex] != PA_TAG_USEC)
391         return -1;
392
393     memcpy(&tmp, t->data+t->rindex+1, 4);
394     *u = (pa_usec_t) ntohl(tmp) << 32;
395     memcpy(&tmp, t->data+t->rindex+5, 4);
396     *u |= (pa_usec_t) ntohl(tmp);
397     t->rindex +=9;
398     return 0;
399 }
400
401 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
402     uint32_t tmp;
403     assert(t && u);
404
405     if (t->rindex+9 > t->length)
406         return -1;
407
408     if (t->data[t->rindex] != PA_TAG_U64)
409         return -1;
410
411     memcpy(&tmp, t->data+t->rindex+1, 4);
412     *u = (uint64_t) ntohl(tmp) << 32;
413     memcpy(&tmp, t->data+t->rindex+5, 4);
414     *u |= (uint64_t) ntohl(tmp);
415     t->rindex +=9;
416     return 0;
417 }
418
419 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
420     uint32_t tmp;
421     assert(t && u);
422
423     if (t->rindex+9 > t->length)
424         return -1;
425
426     if (t->data[t->rindex] != PA_TAG_S64)
427         return -1;
428
429     memcpy(&tmp, t->data+t->rindex+1, 4);
430     *u = (int64_t) ((uint64_t) ntohl(tmp) << 32);
431     memcpy(&tmp, t->data+t->rindex+5, 4);
432     *u |= (int64_t) ntohl(tmp);
433     t->rindex +=9;
434     return 0;
435 }
436
437 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
438     unsigned i;
439
440     assert(t);
441     assert(map);
442
443     if (t->rindex+2 > t->length)
444         return -1;
445
446     if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
447         return -1;
448
449     if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
450         return -1;
451
452     if (t->rindex+2+map->channels > t->length)
453         return -1;
454
455     for (i = 0; i < map->channels; i ++)
456         map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
457
458     t->rindex += 2 + map->channels;
459     return 0;
460 }
461
462 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
463     unsigned i;
464     pa_volume_t vol;
465
466     assert(t);
467     assert(cvolume);
468
469     if (t->rindex+2 > t->length)
470         return -1;
471
472     if (t->data[t->rindex] != PA_TAG_CVOLUME)
473         return -1;
474
475     if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
476         return -1;
477
478     if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
479         return -1;
480
481     for (i = 0; i < cvolume->channels; i ++) {
482         memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
483         cvolume->values[i] = (pa_volume_t) ntohl(vol);
484     }
485
486     t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
487     return 0;
488 }
489
490 void pa_tagstruct_put(pa_tagstruct *t, ...) {
491     va_list va;
492     assert(t);
493
494     va_start(va, t);
495
496     for (;;) {
497         int tag = va_arg(va, int);
498
499         if (tag == PA_TAG_INVALID)
500             break;
501
502         switch (tag) {
503             case PA_TAG_STRING:
504             case PA_TAG_STRING_NULL:
505                 pa_tagstruct_puts(t, va_arg(va, char*));
506                 break;
507
508             case PA_TAG_U32:
509                 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
510                 break;
511
512             case PA_TAG_U8:
513                 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
514                 break;
515
516             case PA_TAG_U64:
517                 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
518                 break;
519
520             case PA_TAG_SAMPLE_SPEC:
521                 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
522                 break;
523
524             case PA_TAG_ARBITRARY: {
525                 void *p = va_arg(va, void*);
526                 size_t size = va_arg(va, size_t);
527                 pa_tagstruct_put_arbitrary(t, p, size);
528                 break;
529             }
530
531             case PA_TAG_BOOLEAN_TRUE:
532             case PA_TAG_BOOLEAN_FALSE:
533                 pa_tagstruct_put_boolean(t, va_arg(va, int));
534                 break;
535
536             case PA_TAG_TIMEVAL:
537                 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
538                 break;
539
540             case PA_TAG_USEC:
541                 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
542                 break;
543
544             case PA_TAG_CHANNEL_MAP:
545                 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
546                 break;
547
548             case PA_TAG_CVOLUME:
549                 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
550                 break;
551
552             default:
553                 abort();
554         }
555     }
556
557     va_end(va);
558 }
559
560 int pa_tagstruct_get(pa_tagstruct *t, ...) {
561     va_list va;
562     int ret = 0;
563
564     assert(t);
565
566     va_start(va, t);
567     while (ret == 0) {
568         int tag = va_arg(va, int);
569
570         if (tag == PA_TAG_INVALID)
571             break;
572
573         switch (tag) {
574             case PA_TAG_STRING:
575             case PA_TAG_STRING_NULL:
576                 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
577                 break;
578
579             case PA_TAG_U32:
580                 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
581                 break;
582
583             case PA_TAG_U8:
584                 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
585                 break;
586
587             case PA_TAG_U64:
588                 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
589                 break;
590
591             case PA_TAG_SAMPLE_SPEC:
592                 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
593                 break;
594
595             case PA_TAG_ARBITRARY: {
596                 const void **p = va_arg(va, const void**);
597                 size_t size = va_arg(va, size_t);
598                 ret = pa_tagstruct_get_arbitrary(t, p, size);
599                 break;
600             }
601
602             case PA_TAG_BOOLEAN_TRUE:
603             case PA_TAG_BOOLEAN_FALSE:
604                 ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
605                 break;
606
607             case PA_TAG_TIMEVAL:
608                 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
609                 break;
610
611             case PA_TAG_USEC:
612                 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
613                 break;
614
615             case PA_TAG_CHANNEL_MAP:
616                 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
617                 break;
618
619             case PA_TAG_CVOLUME:
620                 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
621                 break;
622
623
624             default:
625                 abort();
626         }
627
628     }
629
630     va_end(va);
631     return ret;
632 }