]> code.delx.au - pulseaudio/blob - src/pulsecore/tagstruct.c
556fe80676dc8a836ac2c02c03a68b1ca3293afe
[pulseaudio] / 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 }