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