CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

message.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2004 Steve Harris
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * $Id$
15 */
16
17 #include <stdarg.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22
23 #ifdef WIN32
24 #include <winsock2.h>
25 #include <ws2tcpip.h>
26 #else
27 #include <netinet/in.h>
28 #endif
29
30 #include "lo_types_internal.h"
31 #include "lo_internal.h"
32 #include "lo/lo.h"
33
34 #define LO_DEF_TYPE_SIZE 8
35 #define LO_DEF_DATA_SIZE 8
36
37 static char lo_numerical_types[] = {
38 LO_INT32,
39 LO_FLOAT,
40 LO_INT64,
41 LO_DOUBLE,
42 '\0'
43 };
44
45 static char lo_string_types[] = {
46 LO_STRING,
47 LO_SYMBOL,
48 '\0'
49 };
50
51 static int lo_message_add_typechar(lo_message m, char t);
52 static void *lo_message_add_data(lo_message m, size_t s);
53 void lo_arg_pp_internal(lo_type type, void *data, int bigendian);
54
55 // Used for calculating new sizes when expanding message data buffers.
56 // Note that log(x)/0.69315 = log2(x): this simply finds the next
57 // highest power of 2.
58 #if 1
59 #define lo_pow2_over(a,b) \
60 a = ((b > a) ? (a << ((int)((log(((double)b/(double)a))/0.69315)+1))) : a);
61 #else
62 #define lo_pow2_over(a,b) \
63 while (b > a) {a *= 2;}
64 #endif
65
66 lo_message lo_message_new()
67 {
68 lo_message m = malloc(sizeof(struct _lo_message));
69 if (!m) {
70 return m;
71 }
72
73 m->types = calloc(LO_DEF_TYPE_SIZE, sizeof(char));
74 m->types[0] = ',';
75 m->types[1] = '\0';
76 m->typelen = 1;
77 m->typesize = LO_DEF_TYPE_SIZE;
78 m->data = NULL;
79 m->datalen = 0;
80 m->datasize = 0;
81 m->source = NULL;
82 m->argv = NULL;
83 m->ts = LO_TT_IMMEDIATE;
84
85 return m;
86 }
87
88 void lo_message_free(lo_message m)
89 {
90 if (m) {
91 free(m->types);
92 free(m->data);
93 free(m->argv);
94 }
95 free(m);
96 }
97
98 /* Don't call lo_message_add_varargs_internal directly, use
99 * lo_message_add_varargs, a macro wrapping this function with
100 * appropriate values for file and line */
101
102 int lo_message_add_varargs_internal(lo_message msg, const char *types,
103 va_list ap, const char *file, int line)
104 {
105 int count = 0;
106 int i;
107 int64_t i64;
108 float f;
109 char *s;
110 lo_blob b;
111 uint8_t *m;
112 lo_timetag tt;
113 double d;
114 int ret = 0;
115
116 while (types && *types) {
117 count++;
118 i=0;
119 i64=0;
120 f=0;
121 s=0;
122 b=0;
123 m=0;
124 d=0;
125 switch (*types++) {
126
127 case LO_INT32:
128 i = va_arg(ap, int32_t);
129 lo_message_add_int32(msg, i);
130 break;
131
132 case LO_FLOAT:
133 f = (float)va_arg(ap, double);
134 lo_message_add_float(msg, f);
135 break;
136
137 case LO_STRING:
138 s = va_arg(ap, char *);
139 #ifdef __GNUC__
140 if (s == (char *)LO_MARKER_A) {
141 fprintf(stderr, "liblo error: lo_send or lo_message_add called with "
142 "invalid string pointer for arg %d, probably arg mismatch\n"
143 "at %s:%d, exiting.\n", count, file, line);
144 }
145 #endif
146 lo_message_add_string(msg, s);
147 break;
148
149 case LO_BLOB:
150 b = va_arg(ap, lo_blob);
151 lo_message_add_blob(msg, b);
152 break;
153
154 case LO_INT64:
155 i64 = va_arg(ap, int64_t);
156 lo_message_add_int64(msg, i64);
157 break;
158
159 case LO_TIMETAG:
160 tt = va_arg(ap, lo_timetag);
161 lo_message_add_timetag(msg, tt);
162 break;
163
164 case LO_DOUBLE:
165 d = va_arg(ap, double);
166 lo_message_add_double(msg, d);
167 break;
168
169 case LO_SYMBOL:
170 s = va_arg(ap, char *);
171 #ifdef __GNUC__
172 if (s == (char *)LO_MARKER_A) {
173 fprintf(stderr, "liblo error: lo_send or lo_message_add called with "
174 "invalid symbol pointer for arg %d, probably arg mismatch\n"
175 "at %s:%d, exiting.\n", count, file, line);
176 va_end(ap);
177 return -2;
178 }
179 #endif
180 lo_message_add_symbol(msg, s);
181 break;
182
183 case LO_CHAR:
184 i = va_arg(ap, int);
185 lo_message_add_char(msg, i);
186 break;
187
188 case LO_MIDI:
189 m = va_arg(ap, uint8_t *);
190 lo_message_add_midi(msg, m);
191 break;
192
193 case LO_TRUE:
194 lo_message_add_true(msg);
195 break;
196
197 case LO_FALSE:
198 lo_message_add_false(msg);
199 break;
200
201 case LO_NIL:
202 lo_message_add_nil(msg);
203 break;
204
205 case LO_INFINITUM:
206 lo_message_add_infinitum(msg);
207 break;
208
209 default:
210 ret = -1; // unknown type
211 fprintf(stderr, "liblo warning: unknown type '%c' at %s:%d\n",
212 *(types-1), file, line);
213 break;
214 }
215 }
216 #ifdef __GNUC__
217 i = va_arg(ap, uint32_t);
218 if (i != LO_MARKER_A) {
219 ret = -2; // bad format/args
220 fprintf(stderr, "liblo error: lo_send, lo_message_add, or lo_message_add_varargs called with "
221 "mismatching types and data at\n%s:%d, exiting.\n", file, line);
222 va_end(ap);
223 return ret;
224 }
225 i = va_arg(ap, uint32_t);
226 if (i != LO_MARKER_B) {
227 ret = -2; // bad format/args
228 fprintf(stderr, "liblo error: lo_send, lo_message_add, or lo_message_add_varargs called with "
229 "mismatching types and data at\n%s:%d, exiting.\n", file, line);
230 }
231 #endif
232 va_end(ap);
233
234 return ret;
235 }
236
237 /* Don't call lo_message_add_internal directly, use lo_message_add,
238 * a macro wrapping this function with appropriate values for file and line */
239
240 #ifdef __GNUC__
241 int lo_message_add_internal(lo_message msg, const char *file, const int line,
242 const char *types, ...)
243 #else
244 int lo_message_add(lo_message msg, const char *types, ...)
245 #endif
246 {
247 va_list ap;
248 int ret = 0;
249
250 #ifndef __GNUC__
251 const char *file = "";
252 const int line = 0;
253 #endif
254
255 va_start(ap, types);
256 ret = lo_message_add_varargs_internal(msg, types, ap, file, line);
257
258 return ret;
259 }
260
261 int lo_message_add_int32(lo_message m, int32_t a)
262 {
263 lo_pcast32 b;
264 int32_t *nptr = lo_message_add_data(m, sizeof(a));
265 if (!nptr) return -1;
266 b.i = a;
267
268 if (lo_message_add_typechar(m, LO_INT32))
269 return -1;
270 *nptr = b.nl;
271 return 0;
272 }
273
274 int lo_message_add_float(lo_message m, float a)
275 {
276 lo_pcast32 b;
277 int32_t *nptr = lo_message_add_data(m, sizeof(a));
278 if (!nptr) return -1;
279 b.f = a;
280
281 if (lo_message_add_typechar(m, LO_FLOAT))
282 return -1;
283 *nptr = b.nl;
284 return 0;
285 }
286
287 int lo_message_add_string(lo_message m, const char *a)
288 {
289 const int size = lo_strsize(a);
290 char *nptr = lo_message_add_data(m, size);
291 if (!nptr) return -1;
292
293 if (lo_message_add_typechar(m, LO_STRING))
294 return -1;
295 strncpy(nptr, a, size);
296 return 0;
297 }
298
299 int lo_message_add_blob(lo_message m, lo_blob a)
300 {
301 const uint32_t size = lo_blobsize(a);
302 const uint32_t dsize = lo_blob_datasize(a);
303 char *nptr = lo_message_add_data(m, size);
304 if (!nptr) return -1;
305
306 if (lo_message_add_typechar(m, LO_BLOB))
307 return -1;
308 memset(nptr + size - 4, 0, 4);
309
310 memcpy(nptr, &dsize, sizeof(dsize));
311 memcpy(nptr + sizeof(int32_t), lo_blob_dataptr(a), lo_blob_datasize(a));
312 return 0;
313 }
314
315 int lo_message_add_int64(lo_message m, int64_t a)
316 {
317 lo_pcast64 b;
318 uint64_t *nptr = lo_message_add_data(m, sizeof(a));
319 if (!nptr) return -1;
320 b.i = a;
321
322 if (lo_message_add_typechar(m, LO_INT64))
323 return -1;
324 *nptr = b.nl;
325 return 0;
326 }
327
328 int lo_message_add_timetag(lo_message m, lo_timetag a)
329 {
330 lo_pcast64 b;
331 uint64_t *nptr = lo_message_add_data(m, sizeof(a));
332 if (!nptr) return -1;
333 b.tt = a;
334
335 if (lo_message_add_typechar(m, LO_TIMETAG))
336 return -1;
337 *nptr = b.nl;
338 return 0;
339 }
340
341 int lo_message_add_double(lo_message m, double a)
342 {
343 lo_pcast64 b;
344 uint64_t *nptr = lo_message_add_data(m, sizeof(a));
345 if (!nptr) return -1;
346 b.f = a;
347
348 if (lo_message_add_typechar(m, LO_DOUBLE))
349 return -1;
350 *nptr = b.nl;
351 return 0;
352 }
353
354 int lo_message_add_symbol(lo_message m, const char *a)
355 {
356 const int size = lo_strsize(a);
357 char *nptr = lo_message_add_data(m, size);
358 if (!nptr) return -1;
359
360 if (lo_message_add_typechar(m, LO_SYMBOL))
361 return -1;
362 strncpy(nptr, a, size);
363 return 0;
364 }
365
366 int lo_message_add_char(lo_message m, char a)
367 {
368 lo_pcast32 b;
369 int32_t *nptr = lo_message_add_data(m, sizeof(int32_t));
370 if (!nptr) return -1;
371
372 b.c = a;
373
374 if (lo_message_add_typechar(m, LO_CHAR))
375 return -1;
376 *nptr = b.nl;
377 return 0;
378 }
379
380 int lo_message_add_midi(lo_message m, uint8_t a[4])
381 {
382 char *nptr = lo_message_add_data(m, 4);
383 if (!nptr) return -1;
384
385 if (lo_message_add_typechar(m, LO_MIDI))
386 return -1;
387
388 memcpy(nptr, a, sizeof(a));
389 return 0;
390 }
391
392 int lo_message_add_true(lo_message m)
393 {
394 return lo_message_add_typechar(m, LO_TRUE);
395 }
396
397 int lo_message_add_false(lo_message m)
398 {
399 return lo_message_add_typechar(m, LO_FALSE);
400 }
401
402 int lo_message_add_nil(lo_message m)
403 {
404 return lo_message_add_typechar(m, LO_NIL);
405 }
406
407 int lo_message_add_infinitum(lo_message m)
408 {
409 return lo_message_add_typechar(m, LO_INFINITUM);
410 }
411
412 static int lo_message_add_typechar(lo_message m, char t)
413 {
414 if (m->typelen + 1 >= m->typesize) {
415 int new_typesize = m->typesize * 2;
416 char *new_types = 0;
417 if (!new_typesize)
418 new_typesize = LO_DEF_TYPE_SIZE;
419 new_types = realloc(m->types, new_typesize);
420 if (!new_types) return -1;
421 m->types = new_types;
422 m->typesize = new_typesize;
423 }
424 m->types[m->typelen] = t;
425 m->typelen++;
426 m->types[m->typelen] = '\0';
427 if (m->argv) {
428 free(m->argv);
429 m->argv = NULL;
430 }
431 return 0;
432 }
433
434 static void *lo_message_add_data(lo_message m, size_t s)
435 {
436 uint32_t old_dlen = m->datalen;
437 int new_datasize = m->datasize;
438 int new_datalen = m->datalen + s;
439 void *new_data = 0;
440
441 if (!new_datasize)
442 new_datasize = LO_DEF_DATA_SIZE;
443
444 lo_pow2_over(new_datasize, new_datalen);
445 new_data = realloc(m->data, new_datasize);
446 if (!new_data)
447 return 0;
448
449 m->datalen = new_datalen;
450 m->datasize = new_datasize;
451 m->data = new_data;
452
453 if (m->argv) {
454 free(m->argv);
455 m->argv = NULL;
456 }
457
458 return (void*)((char*)m->data + old_dlen);
459 }
460
461 int lo_strsize(const char *s)
462 {
463 return 4 * (strlen(s) / 4 + 1);
464 }
465
466 size_t lo_arg_size(lo_type type, void *data)
467 {
468 switch (type) {
469 case LO_TRUE:
470 case LO_FALSE:
471 case LO_NIL:
472 case LO_INFINITUM:
473 return 0;
474
475 case LO_INT32:
476 case LO_FLOAT:
477 case LO_MIDI:
478 case LO_CHAR:
479 return 4;
480
481 case LO_INT64:
482 case LO_TIMETAG:
483 case LO_DOUBLE:
484 return 8;
485
486 case LO_STRING:
487 case LO_SYMBOL:
488 return lo_strsize((char *)data);
489
490 case LO_BLOB:
491 return lo_blobsize((lo_blob)data);
492
493 default:
494 fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__);
495 return 0;
496 }
497
498 return 0;
499 }
500
501 char *lo_get_path(void *data, ssize_t size)
502 {
503 ssize_t result = lo_validate_string(data, size);
504 return (result >= 4) ? (char *)data : NULL;
505 }
506
507 ssize_t lo_validate_string(void *data, ssize_t size)
508 {
509 ssize_t i = 0, len = 0;
510 char *pos = data;
511
512 if (size < 0) {
513 return -LO_ESIZE; // invalid size
514 }
515 for (i = 0; i < size; ++i) {
516 if (pos[i] == '\0') {
517 len = 4 * (i / 4 + 1);
518 break;
519 }
520 }
521 if (0 == len) {
522 return -LO_ETERM; // string not terminated
523 }
524 if (len > size) {
525 return -LO_ESIZE; // would overflow buffer
526 }
527 for (; i < len; ++i) {
528 if (pos[i] != '\0') {
529 return -LO_EPAD; // non-zero char found in pad area
530 }
531 }
532 return len;
533 }
534
535
536 ssize_t lo_validate_blob(void *data, ssize_t size)
537 {
538 ssize_t i, end, len;
539 uint32_t dsize;
540 char *pos = (char *)data;
541
542 if (size < 0) {
543 return -LO_ESIZE; // invalid size
544 }
545 dsize = lo_otoh32(*(uint32_t*)data);
546 if (dsize > LO_MAX_MSG_SIZE) { // avoid int overflow in next step
547 return -LO_ESIZE;
548 }
549 end = sizeof(uint32_t) + dsize; // end of data
550 len = 4 * (end / 4 + 1); // full padded size
551 if (len > size) {
552 return -LO_ESIZE; // would overflow buffer
553 }
554 for (i = end; i < len; ++i) {
555 if (pos[i] != '\0') {
556 return -LO_EPAD; // non-zero char found in pad area
557 }
558 }
559 return len;
560 }
561
562
563 ssize_t lo_validate_bundle(void *data, ssize_t size)
564 {
565 ssize_t len = 0, remain = size;
566 char *pos = data;
567 uint32_t elem_len;
568
569 len = lo_validate_string(data, size);
570 if (len < 0) {
571 return -LO_ESIZE; // invalid size
572 }
573 if (0 != strcmp(data, "#bundle")) {
574 return -LO_EINVALIDBUND; // not a bundle
575 }
576 pos += len;
577 remain -= len;
578
579 // time tag
580 if (remain < 8) {
581 return -LO_ESIZE;
582 }
583 pos += 8;
584 remain -= 8;
585
586 while (remain >= 4) {
587 elem_len = lo_otoh32(*((uint32_t *)pos));
588 pos += 4;
589 remain -= 4;
590 if (elem_len > remain) {
591 return -LO_ESIZE;
592 }
593 pos += elem_len;
594 remain -= elem_len;
595 }
596 if (0 != remain) {
597 return -LO_ESIZE;
598 }
599 return size;
600 }
601
602
603 ssize_t lo_validate_arg(lo_type type, void *data, ssize_t size)
604 {
605 if (size < 0) {
606 return -1;
607 }
608 switch (type) {
609 case LO_TRUE:
610 case LO_FALSE:
611 case LO_NIL:
612 case LO_INFINITUM:
613 return 0;
614
615 case LO_INT32:
616 case LO_FLOAT:
617 case LO_MIDI:
618 case LO_CHAR:
619 return size >= 4 ? 4 : -LO_ESIZE;
620
621 case LO_INT64:
622 case LO_TIMETAG:
623 case LO_DOUBLE:
624 return size >= 8 ? 8 : -LO_ESIZE;
625
626 case LO_STRING:
627 case LO_SYMBOL:
628 return lo_validate_string((char *)data, size);
629
630 case LO_BLOB:
631 return lo_validate_blob((lo_blob)data, size);
632
633 default:
634 return -LO_EINVALIDTYPE;
635 }
636 return -LO_INT_ERR;
637 }
638
639 /* convert endianness of arg pointed to by data from network to host */
640 void lo_arg_host_endian(lo_type type, void *data)
641 {
642 switch (type) {
643 case LO_INT32:
644 case LO_FLOAT:
645 case LO_BLOB:
646 case LO_CHAR:
647 *(int32_t *)data = lo_otoh32(*(int32_t *)data);
648 break;
649
650 case LO_INT64:
651 case LO_TIMETAG:
652 case LO_DOUBLE:
653 *(int64_t *)data = lo_otoh64(*(int64_t *)data);
654 break;
655
656 case LO_STRING:
657 case LO_SYMBOL:
658 case LO_MIDI:
659 case LO_TRUE:
660 case LO_FALSE:
661 case LO_NIL:
662 case LO_INFINITUM:
663 /* these are fine */
664 break;
665
666 default:
667 fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n",
668 type, __FILE__, __LINE__);
669 break;
670 }
671 }
672
673 /* convert endianness of arg pointed to by data from host to network */
674 void lo_arg_network_endian(lo_type type, void *data)
675 {
676 switch (type) {
677 case LO_INT32:
678 case LO_FLOAT:
679 case LO_BLOB:
680 case LO_CHAR:
681 *(int32_t *)data = lo_htoo32(*(int32_t *)data);
682 break;
683
684 case LO_INT64:
685 case LO_TIMETAG:
686 case LO_DOUBLE:
687 *(int64_t *)data = lo_htoo64(*(int64_t *)data);
688 break;
689
690 case LO_STRING:
691 case LO_SYMBOL:
692 case LO_MIDI:
693 case LO_TRUE:
694 case LO_FALSE:
695 case LO_NIL:
696 case LO_INFINITUM:
697 /* these are fine */
698 break;
699
700 default:
701 fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n",
702 type, __FILE__, __LINE__);
703 break;
704 }
705 }
706
707 lo_address lo_message_get_source(lo_message m)
708 {
709 return m->source;
710 }
711
712 lo_timetag lo_message_get_timestamp(lo_message m)
713 {
714 return m->ts;
715 }
716
717 size_t lo_message_length(lo_message m, const char *path)
718 {
719 return lo_strsize(path) + lo_strsize(m->types) + m->datalen;
720 }
721
722 int lo_message_get_argc(lo_message m)
723 {
724 return m->typelen - 1;
725 }
726
727 lo_arg **lo_message_get_argv(lo_message m)
728 {
729 int i, argc;
730 char *types, *ptr;
731 lo_arg **argv;
732
733 if (NULL != m->argv) { return m->argv; }
734
735 i = 0;
736 argc = m->typelen - 1;
737 types = m->types + 1;
738 ptr = m->data;
739
740 argv = calloc(argc, sizeof(lo_arg *));
741 for (i = 0; i < argc; ++i) {
742 size_t len = lo_arg_size(types[i], ptr);
743 argv[i] = len ? (lo_arg*)ptr : NULL;
744 ptr += len;
745 }
746 m->argv = argv;
747 return argv;
748 }
749
750 char *lo_message_get_types(lo_message m)
751 {
752 return m->types + 1;
753 }
754
755 void *lo_message_serialise(lo_message m, const char *path, void *to,
756 size_t *size)
757 {
758 int i, argc;
759 char *types, *ptr;
760 size_t s = lo_message_length(m, path);
761
762 if (size) {
763 *size = s;
764 }
765
766 if (!to) {
767 to = calloc(1, s);
768 }
769 memset((char*)to + lo_strsize(path) - 4, 0, 4); // ensure zero-padding
770 strcpy(to, path);
771 memset((char*)to + lo_strsize(path) + lo_strsize(m->types) - 4, 0, 4);
772 strcpy((char*)to + lo_strsize(path), m->types);
773
774 types = m->types + 1;
775 ptr = (char*)to + lo_strsize(path) + lo_strsize(m->types);
776 memcpy(ptr, m->data, m->datalen);
777
778 i = 0;
779 argc = m->typelen - 1;
780 for (i = 0; i < argc; ++i) {
781 size_t len = lo_arg_size(types[i], ptr);
782 lo_arg_network_endian(types[i], ptr);
783 ptr += len;
784 }
785 return to;
786 }
787
788
789 lo_message lo_message_deserialise(void *data, size_t size, int *result)
790 {
791 lo_message msg = NULL;
792 char *types = NULL, *ptr = NULL;
793 int i = 0, argc = 0, remain = size, res = 0, len;
794
795 if (remain <= 0) { res = LO_ESIZE; goto fail; }
796
797 msg = malloc(sizeof(struct _lo_message));
798 if (!msg) { res = LO_EALLOC; goto fail; }
799
800 msg->types = NULL;
801 msg->typelen = 0;
802 msg->typesize = 0;
803 msg->data = NULL;
804 msg->datalen = 0;
805 msg->datasize = 0;
806 msg->source = NULL;
807 msg->argv = NULL;
808 msg->ts = LO_TT_IMMEDIATE;
809
810 // path
811 len = lo_validate_string(data, remain);
812 if (len < 0) {
813 res = LO_EINVALIDPATH; // invalid path string
814 goto fail;
815 }
816 remain -= len;
817
818 // types
819 if (remain <= 0) {
820 res = LO_ENOTYPE; // no type tag string
821 goto fail;
822 }
823 types = (char*)data + len;
824 len = lo_validate_string(types, remain);
825 if (len < 0) {
826 res = LO_EINVALIDTYPE; // invalid type tag string
827 goto fail;
828 }
829 if (types[0] != ',') {
830 res = LO_EBADTYPE; // type tag string missing initial comma
831 goto fail;
832 }
833 remain -= len;
834
835 msg->typelen = strlen(types);
836 msg->typesize = len;
837 msg->types = malloc(msg->typesize);
838 if (NULL == msg->types) { res = LO_EALLOC; goto fail; }
839 memcpy(msg->types, types, msg->typesize);
840
841 // args
842 msg->data = malloc(remain);
843 if (NULL == msg->data) { res = LO_EALLOC; goto fail; }
844 memcpy(msg->data, types + len, remain);
845 msg->datalen = msg->datasize = remain;
846 ptr = msg->data;
847
848 ++types;
849 argc = msg->typelen - 1;
850 if (argc) {
851 msg->argv = calloc(argc, sizeof(lo_arg *));
852 if (NULL == msg->argv) { res = LO_EALLOC; goto fail; }
853 }
854
855 for (i = 0; remain >= 0 && i < argc; ++i) {
856 len = lo_validate_arg((lo_type)types[i], ptr, remain);
857 if (len < 0) {
858 res = LO_EINVALIDARG; // invalid argument
859 goto fail;
860 }
861 lo_arg_host_endian((lo_type)types[i], ptr);
862 msg->argv[i] = len ? (lo_arg*)ptr : NULL;
863 remain -= len;
864 ptr += len;
865 }
866 if (0 != remain || i != argc) {
867 res = LO_ESIZE; // size/argument mismatch
868 goto fail;
869 }
870
871 if (result) { *result = res; }
872 return msg;
873
874 fail:
875 if (msg) { lo_message_free(msg); }
876 if (result) { *result = res; }
877 return NULL;
878 }
879
880 void lo_message_pp(lo_message m)
881 {
882 void *d = m->data;
883 void *end = (char*)m->data + m->datalen;
884 int i;
885
886 printf("%s ", m->types);
887 for (i = 1; m->types[i]; i++) {
888 if (i > 1) {
889 printf(" ");
890 }
891
892 lo_arg_pp_internal(m->types[i], d, 1);
893 d = (char*)d + lo_arg_size(m->types[i], d);
894 }
895 putchar('\n');
896 if (d != end) {
897 fprintf(stderr, "liblo warning: type and data do not match (off by %d) in message %p\n",
898 abs((char*)d - (char*)end), m);
899 }
900 }
901
902 void lo_arg_pp(lo_type type, void *data)
903 {
904 lo_arg_pp_internal(type, data, 0);
905 }
906
907 void lo_arg_pp_internal(lo_type type, void *data, int bigendian)
908 {
909 lo_pcast32 val32;
910 lo_pcast64 val64;
911 int size;
912 int i;
913
914 size = lo_arg_size(type, data);
915 if (size == 4 || type == LO_BLOB) {
916 if (bigendian) {
917 val32.nl = lo_otoh32(*(int32_t *)data);
918 } else {
919 val32.nl = *(int32_t *)data;
920 }
921 } else if (size == 8) {
922 if (bigendian) {
923 val64.nl = lo_otoh64(*(int64_t *)data);
924 } else {
925 val64.nl = *(int64_t *)data;
926 }
927 }
928
929 switch (type) {
930 case LO_INT32:
931 printf("%d", val32.i);
932 break;
933
934 case LO_FLOAT:
935 printf("%f", val32.f);
936 break;
937
938 case LO_STRING:
939 printf("\"%s\"", (char *)data);
940 break;
941
942 case LO_BLOB:
943 printf("[");
944 if (val32.i > 12) {
945 printf("%d byte blob", val32.i);
946 } else {
947 printf("%db ", val32.i);
948 for (i=0; i<val32.i; i++) {
949 printf("0x%02x", *((char *)(data) + 4 + i));
950 if (i+1 < val32.i) printf(" ");
951 }
952 }
953 printf("]");
954 break;
955
956 case LO_INT64:
957 printf("%lld", (long long int)val64.i);
958 break;
959
960 case LO_TIMETAG:
961 printf("%08x.%08x", val64.tt.sec, val64.tt.frac);
962 break;
963
964 case LO_DOUBLE:
965 printf("%f", val64.f);
966 break;
967
968 case LO_SYMBOL:
969 printf("'%s", (char *)data);
970 break;
971
972 case LO_CHAR:
973 printf("'%c'", (char)val32.c);
974 break;
975
976 case LO_MIDI:
977 printf("MIDI [");
978 for (i=0; i<4; i++) {
979 printf("0x%02x", *((uint8_t *)(data) + i));
980 if (i+1 < 4) printf(" ");
981 }
982 printf("]");
983 break;
984
985 case LO_TRUE:
986 printf("#T");
987 break;
988
989 case LO_FALSE:
990 printf("#F");
991 break;
992
993 case LO_NIL:
994 printf("Nil");
995 break;
996
997 case LO_INFINITUM:
998 printf("Infinitum");
999 break;
1000
1001 default:
1002 fprintf(stderr, "liblo warning: unhandled type: %c\n", type);
1003 break;
1004 }
1005 }
1006
1007 int lo_is_numerical_type(lo_type a)
1008 {
1009 return strchr(lo_numerical_types, a) != 0;
1010 }
1011
1012 int lo_is_string_type(lo_type a)
1013 {
1014 return strchr(lo_string_types, a) != 0;
1015 }
1016
1017 int lo_coerce(lo_type type_to, lo_arg *to, lo_type type_from, lo_arg *from)
1018 {
1019 if (type_to == type_from) {
1020 memcpy(to, from, lo_arg_size(type_from, from));
1021
1022 return 1;
1023 }
1024
1025 if (lo_is_string_type(type_to) && lo_is_string_type(type_from)) {
1026 strcpy((char *)to, (char *)from);
1027
1028 return 1;
1029 }
1030
1031 if (lo_is_numerical_type(type_to) && lo_is_numerical_type(type_from)) {
1032 switch (type_to) {
1033 case LO_INT32:
1034 to->i = (uint32_t)lo_hires_val(type_from, from);
1035 break;
1036
1037 case LO_INT64:
1038 to->i64 = (uint64_t)lo_hires_val(type_from, from);
1039 break;
1040
1041 case LO_FLOAT:
1042 to->f = (float)lo_hires_val(type_from, from);
1043 break;
1044
1045 case LO_DOUBLE:
1046 to->d = (double)lo_hires_val(type_from, from);
1047 break;
1048
1049 default:
1050 fprintf(stderr, "liblo: bad coercion: %c -> %c\n", type_from,
1051 type_to);
1052 return 0;
1053 }
1054 return 1;
1055 }
1056
1057 return 0;
1058 }
1059
1060 lo_hires lo_hires_val(lo_type type, lo_arg *p)
1061 {
1062 switch (type) {
1063 case LO_INT32:
1064 return p->i;
1065 case LO_INT64:
1066 return p->h;
1067 case LO_FLOAT:
1068 return p->f;
1069 case LO_DOUBLE:
1070 return p->d;
1071 default:
1072 fprintf(stderr, "liblo: hires val requested of non numerical type '%c' at %s:%d\n", type, __FILE__, __LINE__);
1073 break;
1074 }
1075
1076 return 0.0l;
1077 }
1078
1079
1080
1081 /* vi:set ts=8 sts=4 sw=4: */