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