CSL  5.2
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 
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 
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:
199  break;
200 
201  case LO_NIL:
202  lo_message_add_nil(msg);
203  break;
204 
205  case LO_INFINITUM:
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 
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 
269  return -1;
270  *nptr = b.nl;
271  return 0;
272 }
273 
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 
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 
294  return -1;
295  strncpy(nptr, a, size);
296  return 0;
297 }
298 
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 
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 
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 
323  return -1;
324  *nptr = b.nl;
325  return 0;
326 }
327 
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 
336  return -1;
337  *nptr = b.nl;
338  return 0;
339 }
340 
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 
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 
361  return -1;
362  strncpy(nptr, a, size);
363  return 0;
364 }
365 
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 
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 
386  return -1;
387 
388  memcpy(nptr, a, sizeof(a));
389  return 0;
390 }
391 
393 {
394  return lo_message_add_typechar(m, LO_TRUE);
395 }
396 
398 {
400 }
401 
403 {
404  return lo_message_add_typechar(m, LO_NIL);
405 }
406 
408 {
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 */
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 
708 {
709  return m->source;
710 }
711 
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 
723 {
724  return m->typelen - 1;
725 }
726 
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 
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 
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 
1008 {
1009  return strchr(lo_numerical_types, a) != 0;
1010 }
1011 
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 
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: */