4 This file is part of PulseAudio.
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.
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.
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
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
39 #include <pulse/xmalloc.h>
41 #include "tagstruct.h"
46 size_t length, allocated;
52 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
55 assert(!data || (data && length));
57 t = pa_xmalloc(sizeof(pa_tagstruct));
58 t->data = (uint8_t*) data;
59 t->allocated = t->length = data ? length : 0;
65 void pa_tagstruct_free(pa_tagstruct*t) {
72 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
74 assert(t && t->dynamic && l);
81 static void extend(pa_tagstruct*t, size_t l) {
85 if (t->length+l <= t->allocated)
88 t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
91 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
97 t->data[t->length] = PA_TAG_STRING;
98 strcpy((char*) (t->data+t->length+1), s);
102 t->data[t->length] = PA_TAG_STRING_NULL;
107 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
110 t->data[t->length] = PA_TAG_U32;
112 memcpy(t->data+t->length+1, &i, 4);
116 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
119 t->data[t->length] = PA_TAG_U8;
120 *(t->data+t->length+1) = c;
124 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
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);
136 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
141 t->data[t->length] = PA_TAG_ARBITRARY;
143 memcpy(t->data+t->length+1, &tmp, 4);
145 memcpy(t->data+t->length+5, p, length);
146 t->length += 5+length;
149 void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) {
152 t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE;
156 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
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);
168 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
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);
180 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
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);
192 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
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);
204 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
208 extend(t, 2 + map->channels);
210 t->data[t->length++] = PA_TAG_CHANNEL_MAP;
211 t->data[t->length++] = map->channels;
213 for (i = 0; i < map->channels; i ++)
214 t->data[t->length++] = (uint8_t) map->map[i];
217 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
222 extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
224 t->data[t->length++] = PA_TAG_CVOLUME;
225 t->data[t->length++] = cvolume->channels;
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);
234 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
240 if (t->rindex+1 > t->length)
243 if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
249 if (t->rindex+2 > t->length)
252 if (t->data[t->rindex] != PA_TAG_STRING)
256 for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
265 *s = (char*) (t->data+t->rindex+1);
271 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
274 if (t->rindex+5 > t->length)
277 if (t->data[t->rindex] != PA_TAG_U32)
280 memcpy(i, t->data+t->rindex+1, 4);
286 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
289 if (t->rindex+2 > t->length)
292 if (t->data[t->rindex] != PA_TAG_U8)
295 *c = t->data[t->rindex+1];
300 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
303 if (t->rindex+7 > t->length)
306 if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
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);
318 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
322 if (t->rindex+5+length > t->length)
325 if (t->data[t->rindex] != PA_TAG_ARBITRARY)
328 memcpy(&len, t->data+t->rindex+1, 4);
329 if (ntohl(len) != length)
332 *p = t->data+t->rindex+5;
333 t->rindex += 5+length;
337 int pa_tagstruct_eof(pa_tagstruct*t) {
339 return t->rindex >= t->length;
342 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
343 assert(t && t->dynamic && l);
348 int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
351 if (t->rindex+1 > t->length)
354 if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
356 else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
365 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
367 if (t->rindex+9 > t->length)
370 if (t->data[t->rindex] != PA_TAG_TIMEVAL)
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);
381 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
385 if (t->rindex+9 > t->length)
388 if (t->data[t->rindex] != PA_TAG_USEC)
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);
399 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
403 if (t->rindex+9 > t->length)
406 if (t->data[t->rindex] != PA_TAG_U64)
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);
417 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
421 if (t->rindex+9 > t->length)
424 if (t->data[t->rindex] != PA_TAG_S64)
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);
435 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
441 if (t->rindex+2 > t->length)
444 if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
447 if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
450 if (t->rindex+2+map->channels > t->length)
453 for (i = 0; i < map->channels; i ++)
454 map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
456 t->rindex += 2 + map->channels;
460 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
467 if (t->rindex+2 > t->length)
470 if (t->data[t->rindex] != PA_TAG_CVOLUME)
473 if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
476 if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
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);
484 t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
488 void pa_tagstruct_put(pa_tagstruct *t, ...) {
495 int tag = va_arg(va, int);
497 if (tag == PA_TAG_INVALID)
502 case PA_TAG_STRING_NULL:
503 pa_tagstruct_puts(t, va_arg(va, char*));
507 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
511 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
515 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
518 case PA_TAG_SAMPLE_SPEC:
519 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
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);
529 case PA_TAG_BOOLEAN_TRUE:
530 case PA_TAG_BOOLEAN_FALSE:
531 pa_tagstruct_put_boolean(t, va_arg(va, int));
535 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
539 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
542 case PA_TAG_CHANNEL_MAP:
543 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
547 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
558 int pa_tagstruct_get(pa_tagstruct *t, ...) {
566 int tag = va_arg(va, int);
568 if (tag == PA_TAG_INVALID)
573 case PA_TAG_STRING_NULL:
574 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
578 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
582 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
586 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
589 case PA_TAG_SAMPLE_SPEC:
590 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
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);
600 case PA_TAG_BOOLEAN_TRUE:
601 case PA_TAG_BOOLEAN_FALSE:
602 ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
606 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
610 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
613 case PA_TAG_CHANNEL_MAP:
614 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
618 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));