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