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