]> code.delx.au - pulseaudio/blob - polyp/tagstruct.c
676f67ded6043fd607a6a5381b4bb19d9d629492
[pulseaudio] / polyp / tagstruct.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio 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.
10
11 polypaudio 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.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/time.h>
30 #include <assert.h>
31 #include <stdarg.h>
32
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
35 #endif
36
37 #include "winsock.h"
38
39 #include "tagstruct.h"
40 #include "xmalloc.h"
41
42
43 struct pa_tagstruct {
44 uint8_t *data;
45 size_t length, allocated;
46 size_t rindex;
47
48 int dynamic;
49 };
50
51 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
52 pa_tagstruct*t;
53
54 assert(!data || (data && length));
55
56 t = pa_xmalloc(sizeof(pa_tagstruct));
57 t->data = (uint8_t*) data;
58 t->allocated = t->length = data ? length : 0;
59 t->rindex = 0;
60 t->dynamic = !data;
61 return t;
62 }
63
64 void pa_tagstruct_free(pa_tagstruct*t) {
65 assert(t);
66 if (t->dynamic)
67 pa_xfree(t->data);
68 pa_xfree(t);
69 }
70
71 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
72 uint8_t *p;
73 assert(t && t->dynamic && l);
74 p = t->data;
75 *l = t->length;
76 pa_xfree(t);
77 return p;
78 }
79
80 static void extend(pa_tagstruct*t, size_t l) {
81 assert(t && t->dynamic);
82
83 if (t->length+l <= t->allocated)
84 return;
85
86 t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
87 }
88
89
90 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
91 size_t l;
92 assert(t);
93 if (s) {
94 l = strlen(s)+2;
95 extend(t, l);
96 t->data[t->length] = PA_TAG_STRING;
97 strcpy((char*) (t->data+t->length+1), s);
98 t->length += l;
99 } else {
100 extend(t, 1);
101 t->data[t->length] = PA_TAG_STRING_NULL;
102 t->length += 1;
103 }
104 }
105
106 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
107 assert(t);
108 extend(t, 5);
109 t->data[t->length] = PA_TAG_U32;
110 i = htonl(i);
111 memcpy(t->data+t->length+1, &i, 4);
112 t->length += 5;
113 }
114
115 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
116 assert(t);
117 extend(t, 2);
118 t->data[t->length] = PA_TAG_U8;
119 *(t->data+t->length+1) = c;
120 t->length += 2;
121 }
122
123 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
124 uint32_t rate;
125 assert(t && ss);
126 extend(t, 7);
127 t->data[t->length] = PA_TAG_SAMPLE_SPEC;
128 t->data[t->length+1] = (uint8_t) ss->format;
129 t->data[t->length+2] = ss->channels;
130 rate = htonl(ss->rate);
131 memcpy(t->data+t->length+3, &rate, 4);
132 t->length += 7;
133 }
134
135 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
136 uint32_t tmp;
137 assert(t && p);
138
139 extend(t, 5+length);
140 t->data[t->length] = PA_TAG_ARBITRARY;
141 tmp = htonl(length);
142 memcpy(t->data+t->length+1, &tmp, 4);
143 if (length)
144 memcpy(t->data+t->length+5, p, length);
145 t->length += 5+length;
146 }
147
148 void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) {
149 assert(t);
150 extend(t, 1);
151 t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE;
152 t->length += 1;
153 }
154
155 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
156 uint32_t tmp;
157 assert(t);
158 extend(t, 9);
159 t->data[t->length] = PA_TAG_TIMEVAL;
160 tmp = htonl(tv->tv_sec);
161 memcpy(t->data+t->length+1, &tmp, 4);
162 tmp = htonl(tv->tv_usec);
163 memcpy(t->data+t->length+5, &tmp, 4);
164 t->length += 9;
165 }
166
167 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
168 uint32_t tmp;
169 assert(t);
170 extend(t, 9);
171 t->data[t->length] = PA_TAG_USEC;
172 tmp = htonl((uint32_t) (u >> 32));
173 memcpy(t->data+t->length+1, &tmp, 4);
174 tmp = htonl((uint32_t) u);
175 memcpy(t->data+t->length+5, &tmp, 4);
176 t->length += 9;
177 }
178
179 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
180 uint32_t tmp;
181 assert(t);
182 extend(t, 9);
183 t->data[t->length] = PA_TAG_U64;
184 tmp = htonl((uint32_t) (u >> 32));
185 memcpy(t->data+t->length+1, &tmp, 4);
186 tmp = htonl((uint32_t) u);
187 memcpy(t->data+t->length+5, &tmp, 4);
188 t->length += 9;
189 }
190
191 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
192 unsigned i;
193
194 assert(t);
195 extend(t, 2 + map->channels);
196
197 t->data[t->length++] = PA_TAG_CHANNEL_MAP;
198 t->data[t->length++] = map->channels;
199
200 for (i = 0; i < map->channels; i ++)
201 t->data[t->length++] = (uint8_t) map->map[i];
202 }
203
204 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
205 unsigned i;
206 pa_volume_t vol;
207
208 assert(t);
209 extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
210
211 t->data[t->length++] = PA_TAG_CVOLUME;
212 t->data[t->length++] = cvolume->channels;
213
214 for (i = 0; i < cvolume->channels; i ++) {
215 vol = htonl(cvolume->values[i]);
216 memcpy(t->data + t->length, &vol, sizeof(pa_volume_t));
217 t->length += sizeof(pa_volume_t);
218 }
219 }
220
221 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
222 int error = 0;
223 size_t n;
224 char *c;
225 assert(t && s);
226
227 if (t->rindex+1 > t->length)
228 return -1;
229
230 if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
231 t->rindex++;
232 *s = NULL;
233 return 0;
234 }
235
236 if (t->rindex+2 > t->length)
237 return -1;
238
239 if (t->data[t->rindex] != PA_TAG_STRING)
240 return -1;
241
242 error = 1;
243 for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
244 if (!*c) {
245 error = 0;
246 break;
247 }
248
249 if (error)
250 return -1;
251
252 *s = (char*) (t->data+t->rindex+1);
253
254 t->rindex += n+2;
255 return 0;
256 }
257
258 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
259 assert(t && i);
260
261 if (t->rindex+5 > t->length)
262 return -1;
263
264 if (t->data[t->rindex] != PA_TAG_U32)
265 return -1;
266
267 memcpy(i, t->data+t->rindex+1, 4);
268 *i = ntohl(*i);
269 t->rindex += 5;
270 return 0;
271 }
272
273 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
274 assert(t && c);
275
276 if (t->rindex+2 > t->length)
277 return -1;
278
279 if (t->data[t->rindex] != PA_TAG_U8)
280 return -1;
281
282 *c = t->data[t->rindex+1];
283 t->rindex +=2;
284 return 0;
285 }
286
287 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
288 assert(t && ss);
289
290 if (t->rindex+7 > t->length)
291 return -1;
292
293 if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
294 return -1;
295
296 ss->format = t->data[t->rindex+1];
297 ss->channels = t->data[t->rindex+2];
298 memcpy(&ss->rate, t->data+t->rindex+3, 4);
299 ss->rate = ntohl(ss->rate);
300
301 if (!pa_sample_spec_valid(ss))
302 return -1;
303
304 t->rindex += 7;
305 return 0;
306 }
307
308 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
309 uint32_t len;
310 assert(t && p);
311
312 if (t->rindex+5+length > t->length)
313 return -1;
314
315 if (t->data[t->rindex] != PA_TAG_ARBITRARY)
316 return -1;
317
318 memcpy(&len, t->data+t->rindex+1, 4);
319 if (ntohl(len) != length)
320 return -1;
321
322 *p = t->data+t->rindex+5;
323 t->rindex += 5+length;
324 return 0;
325 }
326
327 int pa_tagstruct_eof(pa_tagstruct*t) {
328 assert(t);
329 return t->rindex >= t->length;
330 }
331
332 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
333 assert(t && t->dynamic && l);
334 *l = t->length;
335 return t->data;
336 }
337
338 int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
339 assert(t && b);
340
341 if (t->rindex+1 > t->length)
342 return -1;
343
344 if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
345 *b = 1;
346 else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
347 *b = 0;
348 else
349 return -1;
350
351 t->rindex +=1;
352 return 0;
353 }
354
355 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
356
357 if (t->rindex+9 > t->length)
358 return -1;
359
360 if (t->data[t->rindex] != PA_TAG_TIMEVAL)
361 return -1;
362
363 memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
364 tv->tv_sec = ntohl(tv->tv_sec);
365 memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
366 tv->tv_usec = ntohl(tv->tv_usec);
367 t->rindex += 9;
368 return 0;
369
370 }
371
372 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
373 uint32_t tmp;
374 assert(t && u);
375
376 if (t->rindex+9 > t->length)
377 return -1;
378
379 if (t->data[t->rindex] != PA_TAG_USEC)
380 return -1;
381
382 memcpy(&tmp, t->data+t->rindex+1, 4);
383 *u = (pa_usec_t) ntohl(tmp) << 32;
384 memcpy(&tmp, t->data+t->rindex+5, 4);
385 *u |= (pa_usec_t) ntohl(tmp);
386 t->rindex +=9;
387 return 0;
388 }
389
390 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
391 uint32_t tmp;
392 assert(t && u);
393
394 if (t->rindex+9 > t->length)
395 return -1;
396
397 if (t->data[t->rindex] != PA_TAG_U64)
398 return -1;
399
400 memcpy(&tmp, t->data+t->rindex+1, 4);
401 *u = (pa_usec_t) ntohl(tmp) << 32;
402 memcpy(&tmp, t->data+t->rindex+5, 4);
403 *u |= (pa_usec_t) ntohl(tmp);
404 t->rindex +=9;
405 return 0;
406 }
407
408 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
409 unsigned i;
410
411 assert(t);
412 assert(map);
413
414 if (t->rindex+2 > t->length)
415 return -1;
416
417 if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
418 return -1;
419
420 if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
421 return -1;
422
423 if (t->rindex+2+map->channels > t->length)
424 return -1;
425
426 for (i = 0; i < map->channels; i ++)
427 map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
428
429 if (!pa_channel_map_valid(map))
430 return -1;
431
432 t->rindex += 2 + map->channels;
433 return 0;
434 }
435
436 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
437 unsigned i;
438 pa_volume_t vol;
439
440 assert(t);
441 assert(cvolume);
442
443 if (t->rindex+2 > t->length)
444 return -1;
445
446 if (t->data[t->rindex] != PA_TAG_CVOLUME)
447 return -1;
448
449 if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
450 return -1;
451
452 if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
453 return -1;
454
455 for (i = 0; i < cvolume->channels; i ++) {
456 memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
457 cvolume->values[i] = (pa_volume_t) ntohl(vol);
458 }
459
460 if (!pa_cvolume_valid(cvolume))
461 return -1;
462
463 t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
464 return 0;
465 }
466
467 void pa_tagstruct_put(pa_tagstruct *t, ...) {
468 va_list va;
469 assert(t);
470
471 va_start(va, t);
472
473 for (;;) {
474 int tag = va_arg(va, int);
475
476 if (tag == PA_TAG_INVALID)
477 break;
478
479 switch (tag) {
480 case PA_TAG_STRING:
481 case PA_TAG_STRING_NULL:
482 pa_tagstruct_puts(t, va_arg(va, char*));
483 break;
484
485 case PA_TAG_U32:
486 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
487 break;
488
489 case PA_TAG_U8:
490 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
491 break;
492
493 case PA_TAG_U64:
494 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
495 break;
496
497 case PA_TAG_SAMPLE_SPEC:
498 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
499 break;
500
501 case PA_TAG_ARBITRARY: {
502 void *p = va_arg(va, void*);
503 size_t size = va_arg(va, size_t);
504 pa_tagstruct_put_arbitrary(t, p, size);
505 break;
506 }
507
508 case PA_TAG_BOOLEAN_TRUE:
509 case PA_TAG_BOOLEAN_FALSE:
510 pa_tagstruct_put_boolean(t, va_arg(va, int));
511 break;
512
513 case PA_TAG_TIMEVAL:
514 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
515 break;
516
517 case PA_TAG_USEC:
518 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
519 break;
520
521 case PA_TAG_CHANNEL_MAP:
522 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
523 break;
524
525 case PA_TAG_CVOLUME:
526 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
527 break;
528
529 default:
530 abort();
531 }
532 }
533
534 va_end(va);
535 }
536
537 int pa_tagstruct_get(pa_tagstruct *t, ...) {
538 va_list va;
539 int ret = 0;
540
541 assert(t);
542
543 va_start(va, t);
544 while (ret == 0) {
545 int tag = va_arg(va, int);
546
547 if (tag == PA_TAG_INVALID)
548 break;
549
550 switch (tag) {
551 case PA_TAG_STRING:
552 case PA_TAG_STRING_NULL:
553 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
554 break;
555
556 case PA_TAG_U32:
557 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
558 break;
559
560 case PA_TAG_U8:
561 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
562 break;
563
564 case PA_TAG_U64:
565 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
566 break;
567
568 case PA_TAG_SAMPLE_SPEC:
569 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
570 break;
571
572 case PA_TAG_ARBITRARY: {
573 const void **p = va_arg(va, const void**);
574 size_t size = va_arg(va, size_t);
575 ret = pa_tagstruct_get_arbitrary(t, p, size);
576 break;
577 }
578
579 case PA_TAG_BOOLEAN_TRUE:
580 case PA_TAG_BOOLEAN_FALSE:
581 ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
582 break;
583
584 case PA_TAG_TIMEVAL:
585 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
586 break;
587
588 case PA_TAG_USEC:
589 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
590 break;
591
592 case PA_TAG_CHANNEL_MAP:
593 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
594 break;
595
596 case PA_TAG_CVOLUME:
597 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
598 break;
599
600
601 default:
602 abort();
603 }
604
605 }
606
607 va_end(va);
608 return ret;
609 }