4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
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.
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.
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
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
38 #include <pulse/xmalloc.h>
40 #include <pulsecore/winsock.h>
41 #include <pulsecore/macro.h>
43 #include "tagstruct.h"
45 #define MAX_TAG_SIZE (64*1024)
49 size_t length, allocated;
55 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
58 pa_assert(!data || (data && length));
60 t = pa_xnew(pa_tagstruct, 1);
61 t->data = (uint8_t*) data;
62 t->allocated = t->length = data ? length : 0;
69 void pa_tagstruct_free(pa_tagstruct*t) {
77 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
81 pa_assert(t->dynamic);
90 static void extend(pa_tagstruct*t, size_t l) {
92 pa_assert(t->dynamic);
94 if (t->length+l <= t->allocated)
97 t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
100 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
107 t->data[t->length] = PA_TAG_STRING;
108 strcpy((char*) (t->data+t->length+1), s);
112 t->data[t->length] = PA_TAG_STRING_NULL;
117 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
121 t->data[t->length] = PA_TAG_U32;
123 memcpy(t->data+t->length+1, &i, 4);
127 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
131 t->data[t->length] = PA_TAG_U8;
132 *(t->data+t->length+1) = c;
136 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
143 t->data[t->length] = PA_TAG_SAMPLE_SPEC;
144 t->data[t->length+1] = (uint8_t) ss->format;
145 t->data[t->length+2] = ss->channels;
146 rate = htonl(ss->rate);
147 memcpy(t->data+t->length+3, &rate, 4);
151 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
158 t->data[t->length] = PA_TAG_ARBITRARY;
160 memcpy(t->data+t->length+1, &tmp, 4);
162 memcpy(t->data+t->length+5, p, length);
163 t->length += 5+length;
166 void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b) {
170 t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE;
174 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
179 t->data[t->length] = PA_TAG_TIMEVAL;
180 tmp = htonl(tv->tv_sec);
181 memcpy(t->data+t->length+1, &tmp, 4);
182 tmp = htonl(tv->tv_usec);
183 memcpy(t->data+t->length+5, &tmp, 4);
187 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
193 t->data[t->length] = PA_TAG_USEC;
194 tmp = htonl((uint32_t) (u >> 32));
195 memcpy(t->data+t->length+1, &tmp, 4);
196 tmp = htonl((uint32_t) u);
197 memcpy(t->data+t->length+5, &tmp, 4);
201 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
207 t->data[t->length] = PA_TAG_U64;
208 tmp = htonl((uint32_t) (u >> 32));
209 memcpy(t->data+t->length+1, &tmp, 4);
210 tmp = htonl((uint32_t) u);
211 memcpy(t->data+t->length+5, &tmp, 4);
215 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
221 t->data[t->length] = PA_TAG_S64;
222 tmp = htonl((uint32_t) ((uint64_t) u >> 32));
223 memcpy(t->data+t->length+1, &tmp, 4);
224 tmp = htonl((uint32_t) ((uint64_t) u));
225 memcpy(t->data+t->length+5, &tmp, 4);
229 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
233 extend(t, 2 + map->channels);
235 t->data[t->length++] = PA_TAG_CHANNEL_MAP;
236 t->data[t->length++] = map->channels;
238 for (i = 0; i < map->channels; i ++)
239 t->data[t->length++] = (uint8_t) map->map[i];
242 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
247 extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
249 t->data[t->length++] = PA_TAG_CVOLUME;
250 t->data[t->length++] = cvolume->channels;
252 for (i = 0; i < cvolume->channels; i ++) {
253 vol = htonl(cvolume->values[i]);
254 memcpy(t->data + t->length, &vol, sizeof(pa_volume_t));
255 t->length += sizeof(pa_volume_t);
259 void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p) {
266 t->data[t->length++] = PA_TAG_PROPLIST;
273 if (!(k = pa_proplist_iterate(p, &state)))
276 pa_tagstruct_puts(t, k);
277 pa_assert_se(pa_proplist_get(p, k, &d, &l) >= 0);
278 pa_tagstruct_putu32(t, (uint32_t) l);
279 pa_tagstruct_put_arbitrary(t, d, l);
282 pa_tagstruct_puts(t, NULL);
285 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
293 if (t->rindex+1 > t->length)
296 if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
302 if (t->rindex+2 > t->length)
305 if (t->data[t->rindex] != PA_TAG_STRING)
309 for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
318 *s = (char*) (t->data+t->rindex+1);
324 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
328 if (t->rindex+5 > t->length)
331 if (t->data[t->rindex] != PA_TAG_U32)
334 memcpy(i, t->data+t->rindex+1, 4);
340 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
344 if (t->rindex+2 > t->length)
347 if (t->data[t->rindex] != PA_TAG_U8)
350 *c = t->data[t->rindex+1];
355 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
359 if (t->rindex+7 > t->length)
362 if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
365 ss->format = t->data[t->rindex+1];
366 ss->channels = t->data[t->rindex+2];
367 memcpy(&ss->rate, t->data+t->rindex+3, 4);
368 ss->rate = ntohl(ss->rate);
374 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
380 if (t->rindex+5+length > t->length)
383 if (t->data[t->rindex] != PA_TAG_ARBITRARY)
386 memcpy(&len, t->data+t->rindex+1, 4);
387 if (ntohl(len) != length)
390 *p = t->data+t->rindex+5;
391 t->rindex += 5+length;
395 int pa_tagstruct_eof(pa_tagstruct*t) {
398 return t->rindex >= t->length;
401 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
403 pa_assert(t->dynamic);
410 int pa_tagstruct_get_boolean(pa_tagstruct*t, pa_bool_t *b) {
414 if (t->rindex+1 > t->length)
417 if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
419 else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
428 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
433 if (t->rindex+9 > t->length)
436 if (t->data[t->rindex] != PA_TAG_TIMEVAL)
439 memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
440 tv->tv_sec = ntohl(tv->tv_sec);
441 memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
442 tv->tv_usec = ntohl(tv->tv_usec);
447 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
453 if (t->rindex+9 > t->length)
456 if (t->data[t->rindex] != PA_TAG_USEC)
459 memcpy(&tmp, t->data+t->rindex+1, 4);
460 *u = (pa_usec_t) ntohl(tmp) << 32;
461 memcpy(&tmp, t->data+t->rindex+5, 4);
462 *u |= (pa_usec_t) ntohl(tmp);
467 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
473 if (t->rindex+9 > t->length)
476 if (t->data[t->rindex] != PA_TAG_U64)
479 memcpy(&tmp, t->data+t->rindex+1, 4);
480 *u = (uint64_t) ntohl(tmp) << 32;
481 memcpy(&tmp, t->data+t->rindex+5, 4);
482 *u |= (uint64_t) ntohl(tmp);
487 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
493 if (t->rindex+9 > t->length)
496 if (t->data[t->rindex] != PA_TAG_S64)
499 memcpy(&tmp, t->data+t->rindex+1, 4);
500 *u = (int64_t) ((uint64_t) ntohl(tmp) << 32);
501 memcpy(&tmp, t->data+t->rindex+5, 4);
502 *u |= (int64_t) ntohl(tmp);
507 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
513 if (t->rindex+2 > t->length)
516 if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
519 if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
522 if (t->rindex+2+map->channels > t->length)
525 for (i = 0; i < map->channels; i ++)
526 map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
528 t->rindex += 2 + map->channels;
532 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
539 if (t->rindex+2 > t->length)
542 if (t->data[t->rindex] != PA_TAG_CVOLUME)
545 if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
548 if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
551 for (i = 0; i < cvolume->channels; i ++) {
552 memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
553 cvolume->values[i] = (pa_volume_t) ntohl(vol);
556 t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
560 int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p) {
566 if (t->rindex+1 > t->length)
569 if (t->data[t->rindex] != PA_TAG_PROPLIST)
572 saved_rindex = t->rindex;
580 if (pa_tagstruct_gets(t, &k) < 0)
586 if (pa_tagstruct_getu32(t, &length) < 0)
589 if (length > MAX_TAG_SIZE)
592 if (pa_tagstruct_get_arbitrary(t, &d, length) < 0)
595 if (pa_proplist_set(p, k, d, length) < 0)
602 t->rindex = saved_rindex;
606 void pa_tagstruct_put(pa_tagstruct *t, ...) {
613 int tag = va_arg(va, int);
615 if (tag == PA_TAG_INVALID)
620 case PA_TAG_STRING_NULL:
621 pa_tagstruct_puts(t, va_arg(va, char*));
625 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
629 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
633 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
636 case PA_TAG_SAMPLE_SPEC:
637 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
640 case PA_TAG_ARBITRARY: {
641 void *p = va_arg(va, void*);
642 size_t size = va_arg(va, size_t);
643 pa_tagstruct_put_arbitrary(t, p, size);
647 case PA_TAG_BOOLEAN_TRUE:
648 case PA_TAG_BOOLEAN_FALSE:
649 pa_tagstruct_put_boolean(t, va_arg(va, int));
653 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
657 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
660 case PA_TAG_CHANNEL_MAP:
661 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
665 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
668 case PA_TAG_PROPLIST:
669 pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
672 pa_assert_not_reached();
679 int pa_tagstruct_get(pa_tagstruct *t, ...) {
687 int tag = va_arg(va, int);
689 if (tag == PA_TAG_INVALID)
694 case PA_TAG_STRING_NULL:
695 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
699 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
703 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
707 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
710 case PA_TAG_SAMPLE_SPEC:
711 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
714 case PA_TAG_ARBITRARY: {
715 const void **p = va_arg(va, const void**);
716 size_t size = va_arg(va, size_t);
717 ret = pa_tagstruct_get_arbitrary(t, p, size);
721 case PA_TAG_BOOLEAN_TRUE:
722 case PA_TAG_BOOLEAN_FALSE:
723 ret = pa_tagstruct_get_boolean(t, va_arg(va, pa_bool_t*));
727 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
731 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
734 case PA_TAG_CHANNEL_MAP:
735 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
739 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
742 case PA_TAG_PROPLIST:
743 ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
746 pa_assert_not_reached();