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