]>
code.delx.au - pulseaudio/blob - src/pulsecore/tagstruct.c
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
, int 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
, int *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
;
579 if (pa_tagstruct_gets(t
, &k
) < 0)
585 if (pa_tagstruct_getu32(t
, &length
) < 0)
588 if (length
> MAX_TAG_SIZE
)
591 d
= pa_xmalloc(length
);
593 if (pa_tagstruct_get_arbitrary(t
, d
, length
) < 0)
596 if (pa_proplist_set(p
, k
, d
, length
) < 0) {
607 t
->rindex
= saved_rindex
;
611 void pa_tagstruct_put(pa_tagstruct
*t
, ...) {
618 int tag
= va_arg(va
, int);
620 if (tag
== PA_TAG_INVALID
)
625 case PA_TAG_STRING_NULL
:
626 pa_tagstruct_puts(t
, va_arg(va
, char*));
630 pa_tagstruct_putu32(t
, va_arg(va
, uint32_t));
634 pa_tagstruct_putu8(t
, (uint8_t) va_arg(va
, int));
638 pa_tagstruct_putu64(t
, va_arg(va
, uint64_t));
641 case PA_TAG_SAMPLE_SPEC
:
642 pa_tagstruct_put_sample_spec(t
, va_arg(va
, pa_sample_spec
*));
645 case PA_TAG_ARBITRARY
: {
646 void *p
= va_arg(va
, void*);
647 size_t size
= va_arg(va
, size_t);
648 pa_tagstruct_put_arbitrary(t
, p
, size
);
652 case PA_TAG_BOOLEAN_TRUE
:
653 case PA_TAG_BOOLEAN_FALSE
:
654 pa_tagstruct_put_boolean(t
, va_arg(va
, int));
658 pa_tagstruct_put_timeval(t
, va_arg(va
, struct timeval
*));
662 pa_tagstruct_put_usec(t
, va_arg(va
, pa_usec_t
));
665 case PA_TAG_CHANNEL_MAP
:
666 pa_tagstruct_put_channel_map(t
, va_arg(va
, pa_channel_map
*));
670 pa_tagstruct_put_cvolume(t
, va_arg(va
, pa_cvolume
*));
673 case PA_TAG_PROPLIST
:
674 pa_tagstruct_put_proplist(t
, va_arg(va
, pa_proplist
*));
677 pa_assert_not_reached();
684 int pa_tagstruct_get(pa_tagstruct
*t
, ...) {
692 int tag
= va_arg(va
, int);
694 if (tag
== PA_TAG_INVALID
)
699 case PA_TAG_STRING_NULL
:
700 ret
= pa_tagstruct_gets(t
, va_arg(va
, const char**));
704 ret
= pa_tagstruct_getu32(t
, va_arg(va
, uint32_t*));
708 ret
= pa_tagstruct_getu8(t
, va_arg(va
, uint8_t*));
712 ret
= pa_tagstruct_getu64(t
, va_arg(va
, uint64_t*));
715 case PA_TAG_SAMPLE_SPEC
:
716 ret
= pa_tagstruct_get_sample_spec(t
, va_arg(va
, pa_sample_spec
*));
719 case PA_TAG_ARBITRARY
: {
720 const void **p
= va_arg(va
, const void**);
721 size_t size
= va_arg(va
, size_t);
722 ret
= pa_tagstruct_get_arbitrary(t
, p
, size
);
726 case PA_TAG_BOOLEAN_TRUE
:
727 case PA_TAG_BOOLEAN_FALSE
:
728 ret
= pa_tagstruct_get_boolean(t
, va_arg(va
, int*));
732 ret
= pa_tagstruct_get_timeval(t
, va_arg(va
, struct timeval
*));
736 ret
= pa_tagstruct_get_usec(t
, va_arg(va
, pa_usec_t
*));
739 case PA_TAG_CHANNEL_MAP
:
740 ret
= pa_tagstruct_get_channel_map(t
, va_arg(va
, pa_channel_map
*));
744 ret
= pa_tagstruct_get_cvolume(t
, va_arg(va
, pa_cvolume
*));
747 case PA_TAG_PROPLIST
:
748 ret
= pa_tagstruct_get_proplist(t
, va_arg(va
, pa_proplist
*));
751 pa_assert_not_reached();