]>
code.delx.au - pulseaudio/blob - src/pulsecore/tagstruct.c
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
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
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/winsock.h>
39 #include <pulsecore/macro.h>
41 #include "tagstruct.h"
43 #define MAX_TAG_SIZE (64*1024)
47 size_t length
, allocated
;
53 pa_tagstruct
*pa_tagstruct_new(const uint8_t* data
, size_t length
) {
56 pa_assert(!data
|| (data
&& length
));
58 t
= pa_xnew(pa_tagstruct
, 1);
59 t
->data
= (uint8_t*) data
;
60 t
->allocated
= t
->length
= data
? length
: 0;
67 void pa_tagstruct_free(pa_tagstruct
*t
) {
75 uint8_t* pa_tagstruct_free_data(pa_tagstruct
*t
, size_t *l
) {
79 pa_assert(t
->dynamic
);
88 static void extend(pa_tagstruct
*t
, size_t l
) {
90 pa_assert(t
->dynamic
);
92 if (t
->length
+l
<= t
->allocated
)
95 t
->data
= pa_xrealloc(t
->data
, t
->allocated
= t
->length
+l
+100);
98 void pa_tagstruct_puts(pa_tagstruct
*t
, const char *s
) {
105 t
->data
[t
->length
] = PA_TAG_STRING
;
106 strcpy((char*) (t
->data
+t
->length
+1), s
);
110 t
->data
[t
->length
] = PA_TAG_STRING_NULL
;
115 void pa_tagstruct_putu32(pa_tagstruct
*t
, uint32_t i
) {
119 t
->data
[t
->length
] = PA_TAG_U32
;
121 memcpy(t
->data
+t
->length
+1, &i
, 4);
125 void pa_tagstruct_putu8(pa_tagstruct
*t
, uint8_t c
) {
129 t
->data
[t
->length
] = PA_TAG_U8
;
130 *(t
->data
+t
->length
+1) = c
;
134 void pa_tagstruct_put_sample_spec(pa_tagstruct
*t
, const pa_sample_spec
*ss
) {
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);
149 void pa_tagstruct_put_arbitrary(pa_tagstruct
*t
, const void *p
, size_t length
) {
156 t
->data
[t
->length
] = PA_TAG_ARBITRARY
;
157 tmp
= htonl((uint32_t) length
);
158 memcpy(t
->data
+t
->length
+1, &tmp
, 4);
160 memcpy(t
->data
+t
->length
+5, p
, length
);
161 t
->length
+= 5+length
;
164 void pa_tagstruct_put_boolean(pa_tagstruct
*t
, pa_bool_t b
) {
168 t
->data
[t
->length
] = (uint8_t) (b
? PA_TAG_BOOLEAN_TRUE
: PA_TAG_BOOLEAN_FALSE
);
172 void pa_tagstruct_put_timeval(pa_tagstruct
*t
, const struct timeval
*tv
) {
177 t
->data
[t
->length
] = PA_TAG_TIMEVAL
;
178 tmp
= htonl((uint32_t) tv
->tv_sec
);
179 memcpy(t
->data
+t
->length
+1, &tmp
, 4);
180 tmp
= htonl((uint32_t) tv
->tv_usec
);
181 memcpy(t
->data
+t
->length
+5, &tmp
, 4);
185 void pa_tagstruct_put_usec(pa_tagstruct
*t
, pa_usec_t u
) {
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);
199 void pa_tagstruct_putu64(pa_tagstruct
*t
, uint64_t u
) {
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);
213 void pa_tagstruct_puts64(pa_tagstruct
*t
, int64_t u
) {
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);
227 void pa_tagstruct_put_channel_map(pa_tagstruct
*t
, const pa_channel_map
*map
) {
231 extend(t
, 2 + (size_t) map
->channels
);
233 t
->data
[t
->length
++] = PA_TAG_CHANNEL_MAP
;
234 t
->data
[t
->length
++] = map
->channels
;
236 for (i
= 0; i
< map
->channels
; i
++)
237 t
->data
[t
->length
++] = (uint8_t) map
->map
[i
];
240 void pa_tagstruct_put_cvolume(pa_tagstruct
*t
, const pa_cvolume
*cvolume
) {
245 extend(t
, 2 + cvolume
->channels
* sizeof(pa_volume_t
));
247 t
->data
[t
->length
++] = PA_TAG_CVOLUME
;
248 t
->data
[t
->length
++] = cvolume
->channels
;
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
);
257 void pa_tagstruct_put_volume(pa_tagstruct
*t
, pa_volume_t vol
) {
262 t
->data
[t
->length
] = PA_TAG_VOLUME
;
263 u
= htonl((uint32_t) vol
);
264 memcpy(t
->data
+t
->length
+1, &u
, 4);
268 void pa_tagstruct_put_proplist(pa_tagstruct
*t
, pa_proplist
*p
) {
275 t
->data
[t
->length
++] = PA_TAG_PROPLIST
;
282 if (!(k
= pa_proplist_iterate(p
, &state
)))
285 pa_tagstruct_puts(t
, k
);
286 pa_assert_se(pa_proplist_get(p
, k
, &d
, &l
) >= 0);
287 pa_tagstruct_putu32(t
, (uint32_t) l
);
288 pa_tagstruct_put_arbitrary(t
, d
, l
);
291 pa_tagstruct_puts(t
, NULL
);
294 int pa_tagstruct_gets(pa_tagstruct
*t
, const char **s
) {
302 if (t
->rindex
+1 > t
->length
)
305 if (t
->data
[t
->rindex
] == PA_TAG_STRING_NULL
) {
311 if (t
->rindex
+2 > t
->length
)
314 if (t
->data
[t
->rindex
] != PA_TAG_STRING
)
318 for (n
= 0, c
= (char*) (t
->data
+t
->rindex
+1); t
->rindex
+1+n
< t
->length
; n
++, c
++)
327 *s
= (char*) (t
->data
+t
->rindex
+1);
333 int pa_tagstruct_getu32(pa_tagstruct
*t
, uint32_t *i
) {
337 if (t
->rindex
+5 > t
->length
)
340 if (t
->data
[t
->rindex
] != PA_TAG_U32
)
343 memcpy(i
, t
->data
+t
->rindex
+1, 4);
349 int pa_tagstruct_getu8(pa_tagstruct
*t
, uint8_t *c
) {
353 if (t
->rindex
+2 > t
->length
)
356 if (t
->data
[t
->rindex
] != PA_TAG_U8
)
359 *c
= t
->data
[t
->rindex
+1];
364 int pa_tagstruct_get_sample_spec(pa_tagstruct
*t
, pa_sample_spec
*ss
) {
368 if (t
->rindex
+7 > t
->length
)
371 if (t
->data
[t
->rindex
] != PA_TAG_SAMPLE_SPEC
)
374 ss
->format
= t
->data
[t
->rindex
+1];
375 ss
->channels
= t
->data
[t
->rindex
+2];
376 memcpy(&ss
->rate
, t
->data
+t
->rindex
+3, 4);
377 ss
->rate
= ntohl(ss
->rate
);
383 int pa_tagstruct_get_arbitrary(pa_tagstruct
*t
, const void **p
, size_t length
) {
389 if (t
->rindex
+5+length
> t
->length
)
392 if (t
->data
[t
->rindex
] != PA_TAG_ARBITRARY
)
395 memcpy(&len
, t
->data
+t
->rindex
+1, 4);
396 if (ntohl(len
) != length
)
399 *p
= t
->data
+t
->rindex
+5;
400 t
->rindex
+= 5+length
;
404 int pa_tagstruct_eof(pa_tagstruct
*t
) {
407 return t
->rindex
>= t
->length
;
410 const uint8_t* pa_tagstruct_data(pa_tagstruct
*t
, size_t *l
) {
412 pa_assert(t
->dynamic
);
419 int pa_tagstruct_get_boolean(pa_tagstruct
*t
, pa_bool_t
*b
) {
423 if (t
->rindex
+1 > t
->length
)
426 if (t
->data
[t
->rindex
] == PA_TAG_BOOLEAN_TRUE
)
428 else if (t
->data
[t
->rindex
] == PA_TAG_BOOLEAN_FALSE
)
437 int pa_tagstruct_get_timeval(pa_tagstruct
*t
, struct timeval
*tv
) {
442 if (t
->rindex
+9 > t
->length
)
445 if (t
->data
[t
->rindex
] != PA_TAG_TIMEVAL
)
448 memcpy(&tv
->tv_sec
, t
->data
+t
->rindex
+1, 4);
449 tv
->tv_sec
= (time_t) ntohl((uint32_t) tv
->tv_sec
);
450 memcpy(&tv
->tv_usec
, t
->data
+t
->rindex
+5, 4);
451 tv
->tv_usec
= (suseconds_t
) ntohl((uint32_t) tv
->tv_usec
);
456 int pa_tagstruct_get_usec(pa_tagstruct
*t
, pa_usec_t
*u
) {
462 if (t
->rindex
+9 > t
->length
)
465 if (t
->data
[t
->rindex
] != PA_TAG_USEC
)
468 memcpy(&tmp
, t
->data
+t
->rindex
+1, 4);
469 *u
= (pa_usec_t
) ntohl(tmp
) << 32;
470 memcpy(&tmp
, t
->data
+t
->rindex
+5, 4);
471 *u
|= (pa_usec_t
) ntohl(tmp
);
476 int pa_tagstruct_getu64(pa_tagstruct
*t
, uint64_t *u
) {
482 if (t
->rindex
+9 > t
->length
)
485 if (t
->data
[t
->rindex
] != PA_TAG_U64
)
488 memcpy(&tmp
, t
->data
+t
->rindex
+1, 4);
489 *u
= (uint64_t) ntohl(tmp
) << 32;
490 memcpy(&tmp
, t
->data
+t
->rindex
+5, 4);
491 *u
|= (uint64_t) ntohl(tmp
);
496 int pa_tagstruct_gets64(pa_tagstruct
*t
, int64_t *u
) {
502 if (t
->rindex
+9 > t
->length
)
505 if (t
->data
[t
->rindex
] != PA_TAG_S64
)
508 memcpy(&tmp
, t
->data
+t
->rindex
+1, 4);
509 *u
= (int64_t) ((uint64_t) ntohl(tmp
) << 32);
510 memcpy(&tmp
, t
->data
+t
->rindex
+5, 4);
511 *u
|= (int64_t) ntohl(tmp
);
516 int pa_tagstruct_get_channel_map(pa_tagstruct
*t
, pa_channel_map
*map
) {
522 if (t
->rindex
+2 > t
->length
)
525 if (t
->data
[t
->rindex
] != PA_TAG_CHANNEL_MAP
)
528 if ((map
->channels
= t
->data
[t
->rindex
+1]) > PA_CHANNELS_MAX
)
531 if (t
->rindex
+2+map
->channels
> t
->length
)
534 for (i
= 0; i
< map
->channels
; i
++)
535 map
->map
[i
] = (int8_t) t
->data
[t
->rindex
+ 2 + i
];
537 t
->rindex
+= 2 + (size_t) map
->channels
;
541 int pa_tagstruct_get_cvolume(pa_tagstruct
*t
, pa_cvolume
*cvolume
) {
548 if (t
->rindex
+2 > t
->length
)
551 if (t
->data
[t
->rindex
] != PA_TAG_CVOLUME
)
554 if ((cvolume
->channels
= t
->data
[t
->rindex
+1]) > PA_CHANNELS_MAX
)
557 if (t
->rindex
+2+cvolume
->channels
*sizeof(pa_volume_t
) > t
->length
)
560 for (i
= 0; i
< cvolume
->channels
; i
++) {
561 memcpy(&vol
, t
->data
+ t
->rindex
+ 2 + i
* sizeof(pa_volume_t
), sizeof(pa_volume_t
));
562 cvolume
->values
[i
] = (pa_volume_t
) ntohl(vol
);
565 t
->rindex
+= 2 + cvolume
->channels
* sizeof(pa_volume_t
);
569 int pa_tagstruct_get_volume(pa_tagstruct
*t
, pa_volume_t
*vol
) {
575 if (t
->rindex
+5 > t
->length
)
578 if (t
->data
[t
->rindex
] != PA_TAG_VOLUME
)
581 memcpy(&u
, t
->data
+t
->rindex
+1, 4);
582 *vol
= (pa_volume_t
) ntohl(u
);
588 int pa_tagstruct_get_proplist(pa_tagstruct
*t
, pa_proplist
*p
) {
594 if (t
->rindex
+1 > t
->length
)
597 if (t
->data
[t
->rindex
] != PA_TAG_PROPLIST
)
600 saved_rindex
= t
->rindex
;
608 if (pa_tagstruct_gets(t
, &k
) < 0)
614 if (pa_tagstruct_getu32(t
, &length
) < 0)
617 if (length
> MAX_TAG_SIZE
)
620 if (pa_tagstruct_get_arbitrary(t
, &d
, length
) < 0)
623 if (pa_proplist_set(p
, k
, d
, length
) < 0)
630 t
->rindex
= saved_rindex
;
634 void pa_tagstruct_put(pa_tagstruct
*t
, ...) {
641 int tag
= va_arg(va
, int);
643 if (tag
== PA_TAG_INVALID
)
648 case PA_TAG_STRING_NULL
:
649 pa_tagstruct_puts(t
, va_arg(va
, char*));
653 pa_tagstruct_putu32(t
, va_arg(va
, uint32_t));
657 pa_tagstruct_putu8(t
, (uint8_t) va_arg(va
, int));
661 pa_tagstruct_putu64(t
, va_arg(va
, uint64_t));
664 case PA_TAG_SAMPLE_SPEC
:
665 pa_tagstruct_put_sample_spec(t
, va_arg(va
, pa_sample_spec
*));
668 case PA_TAG_ARBITRARY
: {
669 void *p
= va_arg(va
, void*);
670 size_t size
= va_arg(va
, size_t);
671 pa_tagstruct_put_arbitrary(t
, p
, size
);
675 case PA_TAG_BOOLEAN_TRUE
:
676 case PA_TAG_BOOLEAN_FALSE
:
677 pa_tagstruct_put_boolean(t
, va_arg(va
, int));
681 pa_tagstruct_put_timeval(t
, va_arg(va
, struct timeval
*));
685 pa_tagstruct_put_usec(t
, va_arg(va
, pa_usec_t
));
688 case PA_TAG_CHANNEL_MAP
:
689 pa_tagstruct_put_channel_map(t
, va_arg(va
, pa_channel_map
*));
693 pa_tagstruct_put_cvolume(t
, va_arg(va
, pa_cvolume
*));
697 pa_tagstruct_put_volume(t
, va_arg(va
, pa_volume_t
));
700 case PA_TAG_PROPLIST
:
701 pa_tagstruct_put_proplist(t
, va_arg(va
, pa_proplist
*));
705 pa_assert_not_reached();
712 int pa_tagstruct_get(pa_tagstruct
*t
, ...) {
720 int tag
= va_arg(va
, int);
722 if (tag
== PA_TAG_INVALID
)
727 case PA_TAG_STRING_NULL
:
728 ret
= pa_tagstruct_gets(t
, va_arg(va
, const char**));
732 ret
= pa_tagstruct_getu32(t
, va_arg(va
, uint32_t*));
736 ret
= pa_tagstruct_getu8(t
, va_arg(va
, uint8_t*));
740 ret
= pa_tagstruct_getu64(t
, va_arg(va
, uint64_t*));
743 case PA_TAG_SAMPLE_SPEC
:
744 ret
= pa_tagstruct_get_sample_spec(t
, va_arg(va
, pa_sample_spec
*));
747 case PA_TAG_ARBITRARY
: {
748 const void **p
= va_arg(va
, const void**);
749 size_t size
= va_arg(va
, size_t);
750 ret
= pa_tagstruct_get_arbitrary(t
, p
, size
);
754 case PA_TAG_BOOLEAN_TRUE
:
755 case PA_TAG_BOOLEAN_FALSE
:
756 ret
= pa_tagstruct_get_boolean(t
, va_arg(va
, pa_bool_t
*));
760 ret
= pa_tagstruct_get_timeval(t
, va_arg(va
, struct timeval
*));
764 ret
= pa_tagstruct_get_usec(t
, va_arg(va
, pa_usec_t
*));
767 case PA_TAG_CHANNEL_MAP
:
768 ret
= pa_tagstruct_get_channel_map(t
, va_arg(va
, pa_channel_map
*));
772 ret
= pa_tagstruct_get_cvolume(t
, va_arg(va
, pa_cvolume
*));
776 ret
= pa_tagstruct_get_volume(t
, va_arg(va
, pa_volume_t
*));
779 case PA_TAG_PROPLIST
:
780 ret
= pa_tagstruct_get_proplist(t
, va_arg(va
, pa_proplist
*));
784 pa_assert_not_reached();