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