1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #ifndef LV2_OSC_READER_H
19 #define LV2_OSC_READER_H
20
21 #include <stdbool.h>
22 #include <string.h>
23 #include <stdarg.h>
24
25 #include <osc.lv2/osc.h>
26 #include <osc.lv2/endian.h>
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 typedef struct _LV2_OSC_Reader LV2_OSC_Reader;
33 typedef struct _LV2_OSC_Item LV2_OSC_Item;
34 typedef struct _LV2_OSC_Arg LV2_OSC_Arg;
35
36 struct _LV2_OSC_Reader {
37 const uint8_t *buf;
38 const uint8_t *ptr;
39 const uint8_t *end;
40 };
41
42 struct _LV2_OSC_Item {
43 int32_t size;
44 const uint8_t *body;
45
46 uint64_t timetag;
47 const uint8_t *end;
48 };
49
50 struct _LV2_OSC_Arg {
51 const char *type;
52 int32_t size;
53 union {
54 int32_t i;
55 float f;
56 const char *s;
57 const uint8_t *b;
58
59 int64_t h;
60 double d;
61 uint64_t t;
62
63 const uint8_t *m;
64 const char *S;
65 char c;
66 struct {
67 uint8_t R;
68 uint8_t G;
69 uint8_t B;
70 uint8_t A;
71 }; // anonymous RGBA struct
72 };
73
74 const char *path;
75 const uint8_t *end;
76 };
77
78 static inline void
lv2_osc_reader_initialize(LV2_OSC_Reader * reader,const uint8_t * buf,size_t size)79 lv2_osc_reader_initialize(LV2_OSC_Reader *reader, const uint8_t *buf, size_t size)
80 {
81 reader->buf = buf;
82 reader->ptr = buf;
83 reader->end = buf + size;
84 }
85
86 static inline bool
lv2_osc_reader_overflow(LV2_OSC_Reader * reader,size_t size)87 lv2_osc_reader_overflow(LV2_OSC_Reader *reader, size_t size)
88 {
89 return reader->ptr + size > reader->end;
90 }
91
92 static inline bool
lv2_osc_reader_be32toh(LV2_OSC_Reader * reader,union swap32_t * s32)93 lv2_osc_reader_be32toh(LV2_OSC_Reader *reader, union swap32_t *s32)
94 {
95 if(lv2_osc_reader_overflow(reader, 4))
96 return false;
97
98 s32->u = *(const uint32_t *)reader->ptr;
99 s32->u = be32toh(s32->u);
100 reader->ptr += 4;
101
102 return true;
103 }
104
105 static inline bool
lv2_osc_reader_be64toh(LV2_OSC_Reader * reader,union swap64_t * s64)106 lv2_osc_reader_be64toh(LV2_OSC_Reader *reader, union swap64_t *s64)
107 {
108 if(lv2_osc_reader_overflow(reader, 8))
109 return false;
110
111 s64->u = *(const uint64_t *)reader->ptr;
112 s64->u = be64toh(s64->u);
113 reader->ptr += 8;
114
115 return true;
116 }
117
118 static inline bool
lv2_osc_reader_get_int32(LV2_OSC_Reader * reader,int32_t * i)119 lv2_osc_reader_get_int32(LV2_OSC_Reader *reader, int32_t *i)
120 {
121 union swap32_t s32;
122 if(!lv2_osc_reader_be32toh(reader, &s32))
123 return false;
124
125 *i = s32.i;
126
127 return true;
128 }
129
130 static inline bool
lv2_osc_reader_get_float(LV2_OSC_Reader * reader,float * f)131 lv2_osc_reader_get_float(LV2_OSC_Reader *reader, float *f)
132 {
133 union swap32_t s32;
134 if(!lv2_osc_reader_be32toh(reader, &s32))
135 return false;
136
137 *f = s32.f;
138
139 return true;
140 }
141
142 static inline bool
lv2_osc_reader_get_int64(LV2_OSC_Reader * reader,int64_t * h)143 lv2_osc_reader_get_int64(LV2_OSC_Reader *reader, int64_t *h)
144 {
145 union swap64_t s64;
146 if(!lv2_osc_reader_be64toh(reader, &s64))
147 return false;
148
149 *h = s64.h;
150
151 return true;
152 }
153
154 static inline bool
lv2_osc_reader_get_timetag(LV2_OSC_Reader * reader,uint64_t * t)155 lv2_osc_reader_get_timetag(LV2_OSC_Reader *reader, uint64_t *t)
156 {
157 union swap64_t s64;
158 if(!lv2_osc_reader_be64toh(reader, &s64))
159 return false;
160
161 *t = s64.u;
162
163 return true;
164 }
165
166 static inline bool
lv2_osc_reader_get_double(LV2_OSC_Reader * reader,double * d)167 lv2_osc_reader_get_double(LV2_OSC_Reader *reader, double *d)
168 {
169 union swap64_t s64;
170 if(!lv2_osc_reader_be64toh(reader, &s64))
171 return false;
172
173 *d = s64.d;
174
175 return true;
176 }
177
178 static inline bool
lv2_osc_reader_get_string(LV2_OSC_Reader * reader,const char ** s)179 lv2_osc_reader_get_string(LV2_OSC_Reader *reader, const char **s)
180 {
181 const char *str = (const char *)reader->ptr;
182 const size_t padded = LV2_OSC_PADDED_SIZE(strlen(str) + 1);
183 if(lv2_osc_reader_overflow(reader, padded ))
184 return false;
185
186 *s = str;
187 reader->ptr += padded;
188
189 return true;
190 }
191
192 static inline bool
lv2_osc_reader_get_symbol(LV2_OSC_Reader * reader,const char ** S)193 lv2_osc_reader_get_symbol(LV2_OSC_Reader *reader, const char **S)
194 {
195 return lv2_osc_reader_get_string(reader, S);
196 }
197
198 static inline bool
lv2_osc_reader_get_midi(LV2_OSC_Reader * reader,const uint8_t ** m)199 lv2_osc_reader_get_midi(LV2_OSC_Reader *reader, const uint8_t **m)
200 {
201 if(lv2_osc_reader_overflow(reader, 4))
202 return false;
203
204 *m = reader->ptr;
205 reader->ptr += 4;
206
207 return true;
208 }
209
210 static inline bool
lv2_osc_reader_get_blob(LV2_OSC_Reader * reader,int32_t * len,const uint8_t ** body)211 lv2_osc_reader_get_blob(LV2_OSC_Reader *reader, int32_t *len, const uint8_t **body)
212 {
213 if(!lv2_osc_reader_get_int32(reader, len))
214 return false;
215
216 const size_t padded = LV2_OSC_PADDED_SIZE(*len);
217 if(lv2_osc_reader_overflow(reader, padded))
218 return false;
219
220 *body = reader->ptr;
221 reader->ptr += padded;
222
223 return true;
224 }
225
226 static inline bool
lv2_osc_reader_get_rgba(LV2_OSC_Reader * reader,uint8_t * r,uint8_t * g,uint8_t * b,uint8_t * a)227 lv2_osc_reader_get_rgba(LV2_OSC_Reader *reader, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a)
228 {
229 if(lv2_osc_reader_overflow(reader, 4))
230 return false;
231
232 *r = reader->ptr[0];
233 *g = reader->ptr[1];
234 *b = reader->ptr[2];
235 *a = reader->ptr[3];
236 reader->ptr += 4;
237
238 return true;
239 }
240
241 static inline bool
lv2_osc_reader_get_char(LV2_OSC_Reader * reader,char * c)242 lv2_osc_reader_get_char(LV2_OSC_Reader *reader, char *c)
243 {
244 int32_t i;
245 if(!lv2_osc_reader_get_int32(reader, &i))
246 return false;
247
248 *c = i;
249
250 return true;
251 }
252
253 static inline LV2_OSC_Item *
lv2_osc_reader_item_raw(LV2_OSC_Reader * reader,LV2_OSC_Item * itm)254 lv2_osc_reader_item_raw(LV2_OSC_Reader *reader, LV2_OSC_Item *itm)
255 {
256 if(!lv2_osc_reader_get_int32(reader, &itm->size))
257 return NULL;
258
259 if(lv2_osc_reader_overflow(reader, itm->size))
260 return NULL;
261
262 itm->body = reader->ptr;
263
264 return itm;
265 }
266
267 static inline LV2_OSC_Item *
lv2_osc_reader_item_begin(LV2_OSC_Reader * reader,LV2_OSC_Item * itm,size_t len)268 lv2_osc_reader_item_begin(LV2_OSC_Reader *reader, LV2_OSC_Item *itm, size_t len)
269 {
270 if(lv2_osc_reader_overflow(reader, len))
271 return NULL;
272
273 itm->end = reader->ptr + len;
274
275 if(lv2_osc_reader_overflow(reader, 16))
276 return NULL;
277
278 if(strncmp((const char *)reader->ptr, "#bundle", 8))
279 return NULL;
280 reader->ptr += 8;
281
282 if(!lv2_osc_reader_get_timetag(reader, &itm->timetag))
283 return NULL;
284
285 return lv2_osc_reader_item_raw(reader, itm);
286 }
287
288 static inline bool
lv2_osc_reader_item_is_end(LV2_OSC_Reader * reader,LV2_OSC_Item * itm)289 lv2_osc_reader_item_is_end(LV2_OSC_Reader *reader, LV2_OSC_Item *itm)
290 {
291 return reader->ptr > itm->end;
292 }
293
294 static inline LV2_OSC_Item *
lv2_osc_reader_item_next(LV2_OSC_Reader * reader,LV2_OSC_Item * itm)295 lv2_osc_reader_item_next(LV2_OSC_Reader *reader, LV2_OSC_Item *itm)
296 {
297 reader->ptr += itm->size;
298
299 return lv2_osc_reader_item_raw(reader, itm);
300 }
301
302 #define OSC_READER_BUNDLE_BEGIN(reader, len) \
303 lv2_osc_reader_item_begin( \
304 (reader), \
305 &(LV2_OSC_Item){ .size = 0, .body = NULL, .timetag = 1ULL, .end = NULL }, \
306 len)
307
308 #define OSC_READER_BUNDLE_ITERATE(reader, itm) \
309 for(itm = itm; \
310 itm && !lv2_osc_reader_item_is_end((reader), (itm)); \
311 itm = lv2_osc_reader_item_next((reader), (itm)))
312
313 #define OSC_READER_BUNDLE_FOREACH(reader, itm, len) \
314 for(LV2_OSC_Item *(itm) = OSC_READER_BUNDLE_BEGIN((reader), (len)); \
315 itm && !lv2_osc_reader_item_is_end((reader), (itm)); \
316 itm = lv2_osc_reader_item_next((reader), (itm)))
317
318 static inline LV2_OSC_Arg *
lv2_osc_reader_arg_raw(LV2_OSC_Reader * reader,LV2_OSC_Arg * arg)319 lv2_osc_reader_arg_raw(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg)
320 {
321 switch( (LV2_OSC_Type)*arg->type)
322 {
323 case LV2_OSC_INT32:
324 {
325 if(!lv2_osc_reader_get_int32(reader, &arg->i))
326 return NULL;
327 arg->size = 4;
328
329 break;
330 }
331 case LV2_OSC_FLOAT:
332 {
333 if(!lv2_osc_reader_get_float(reader, &arg->f))
334 return NULL;
335 arg->size = 4;
336
337 break;
338 }
339 case LV2_OSC_STRING:
340 {
341 if(!lv2_osc_reader_get_string(reader, &arg->s))
342 return NULL;
343 arg->size = strlen(arg->s) + 1;
344
345 break;
346 }
347 case LV2_OSC_BLOB:
348 {
349 if(!lv2_osc_reader_get_blob(reader, &arg->size, &arg->b))
350 return NULL;
351 //arg->size = arg->size;
352
353 break;
354 }
355
356 case LV2_OSC_TRUE:
357 case LV2_OSC_FALSE:
358 case LV2_OSC_NIL:
359 case LV2_OSC_IMPULSE:
360 break;
361
362 case LV2_OSC_INT64:
363 {
364 if(!lv2_osc_reader_get_int64(reader, &arg->h))
365 return NULL;
366 arg->size = 8;
367
368 break;
369 }
370 case LV2_OSC_DOUBLE:
371 {
372 if(!lv2_osc_reader_get_double(reader, &arg->d))
373 return NULL;
374 arg->size = 8;
375
376 break;
377 }
378 case LV2_OSC_TIMETAG:
379 {
380 if(!lv2_osc_reader_get_timetag(reader, &arg->t))
381 return NULL;
382 arg->size = 8;
383
384 break;
385 }
386
387 case LV2_OSC_MIDI:
388 {
389 if(!lv2_osc_reader_get_midi(reader, &arg->m))
390 return NULL;
391 arg->size = 4;
392
393 break;
394 }
395 case LV2_OSC_SYMBOL:
396 {
397 if(!lv2_osc_reader_get_symbol(reader, &arg->S))
398 return NULL;
399 arg->size = strlen(arg->S) + 1;
400
401 break;
402 }
403 case LV2_OSC_CHAR:
404 {
405 if(!lv2_osc_reader_get_char(reader, &arg->c))
406 return NULL;
407 arg->size = 4;
408
409 break;
410 }
411 case LV2_OSC_RGBA:
412 {
413 if(!lv2_osc_reader_get_rgba(reader, &arg->R, &arg->G, &arg->B, &arg->A))
414 return NULL;
415 arg->size = 4;
416
417 break;
418 }
419 }
420
421 return arg;
422 }
423
424 static inline LV2_OSC_Arg *
lv2_osc_reader_arg_begin(LV2_OSC_Reader * reader,LV2_OSC_Arg * arg,size_t len)425 lv2_osc_reader_arg_begin(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg, size_t len)
426 {
427 if(lv2_osc_reader_overflow(reader, len))
428 return NULL;
429
430 arg->end = reader->ptr + len;
431
432 if(!lv2_osc_reader_get_string(reader, &arg->path)) //TODO check for validity
433 return NULL;
434
435 if(!lv2_osc_reader_get_string(reader, &arg->type)) //TODO check for validity
436 return NULL;
437
438 if(*arg->type != ',')
439 return NULL;
440
441 arg->type++; // skip ','
442
443 return lv2_osc_reader_arg_raw(reader, arg);
444 }
445
446 static inline bool
lv2_osc_reader_arg_is_end(LV2_OSC_Reader * reader,LV2_OSC_Arg * arg)447 lv2_osc_reader_arg_is_end(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg)
448 {
449 return (*arg->type == '\0') || (reader->ptr > arg->end);
450 }
451
452 static inline LV2_OSC_Arg *
lv2_osc_reader_arg_next(LV2_OSC_Reader * reader,LV2_OSC_Arg * arg)453 lv2_osc_reader_arg_next(LV2_OSC_Reader *reader, LV2_OSC_Arg *arg)
454 {
455 arg->type++;
456
457 return lv2_osc_reader_arg_raw(reader, arg);
458 }
459
460 #define OSC_READER_MESSAGE_BEGIN(reader, len) \
461 lv2_osc_reader_arg_begin( \
462 (reader), \
463 &(LV2_OSC_Arg){ .type = NULL, .size = 0, .path = NULL, .end = NULL }, \
464 len)
465
466 #define OSC_READER_MESSAGE_ITERATE(reader, arg) \
467 for(arg = arg; \
468 arg && !lv2_osc_reader_arg_is_end((reader), (arg)); \
469 arg = lv2_osc_reader_arg_next((reader), (arg)))
470
471 #define OSC_READER_MESSAGE_FOREACH(reader, arg, len) \
472 for(LV2_OSC_Arg *(arg) = OSC_READER_MESSAGE_BEGIN((reader), (len)); \
473 arg && !lv2_osc_reader_arg_is_end((reader), (arg)); \
474 arg = lv2_osc_reader_arg_next((reader), (arg)))
475
476 static inline bool
lv2_osc_reader_arg_varlist(LV2_OSC_Reader * reader,const char * fmt,va_list args)477 lv2_osc_reader_arg_varlist(LV2_OSC_Reader *reader, const char *fmt, va_list args)
478 {
479 for(const char *type = fmt; *type; type++)
480 {
481 switch( (LV2_OSC_Type)*type)
482 {
483 case LV2_OSC_INT32:
484 if(!lv2_osc_reader_get_int32(reader, va_arg(args, int32_t *)))
485 return false;
486 break;
487 case LV2_OSC_FLOAT:
488 if(!lv2_osc_reader_get_float(reader, va_arg(args, float *)))
489 return false;
490 break;
491 case LV2_OSC_STRING:
492 if(!lv2_osc_reader_get_string(reader, va_arg(args, const char **)))
493 return false;
494 break;
495 case LV2_OSC_BLOB:
496 if(!lv2_osc_reader_get_blob(reader, va_arg(args, int32_t *), va_arg(args, const uint8_t **)))
497 return false;
498 break;
499
500 case LV2_OSC_TRUE:
501 case LV2_OSC_FALSE:
502 case LV2_OSC_NIL:
503 case LV2_OSC_IMPULSE:
504 break;
505
506 case LV2_OSC_INT64:
507 if(!lv2_osc_reader_get_int64(reader, va_arg(args, int64_t *)))
508 return false;
509 break;
510 case LV2_OSC_DOUBLE:
511 if(!lv2_osc_reader_get_double(reader, va_arg(args, double *)))
512 return false;
513 break;
514 case LV2_OSC_TIMETAG:
515 if(!lv2_osc_reader_get_timetag(reader, va_arg(args, uint64_t *)))
516 return false;
517 break;
518
519 case LV2_OSC_MIDI:
520 if(!lv2_osc_reader_get_midi(reader, va_arg(args, const uint8_t **)))
521 return false;
522 break;
523 case LV2_OSC_SYMBOL:
524 if(!lv2_osc_reader_get_symbol(reader, va_arg(args, const char **)))
525 return false;
526 break;
527 case LV2_OSC_CHAR:
528 if(!lv2_osc_reader_get_char(reader, va_arg(args, char *)))
529 return false;
530 break;
531 case LV2_OSC_RGBA:
532 if(!lv2_osc_reader_get_rgba(reader, va_arg(args, uint8_t *), va_arg(args, uint8_t *),
533 va_arg(args, uint8_t *), va_arg(args, uint8_t *)))
534 return false;
535 break;
536 }
537 }
538
539 return true;
540 }
541
542 static inline bool
lv2_osc_reader_arg_vararg(LV2_OSC_Reader * reader,const char * fmt,...)543 lv2_osc_reader_arg_vararg(LV2_OSC_Reader *reader, const char *fmt, ...)
544 {
545 va_list args;
546 va_start(args, fmt);
547
548 const bool res = lv2_osc_reader_arg_varlist(reader, fmt, args);
549
550 va_end(args);
551
552 return res;
553 }
554
555 static inline bool
lv2_osc_reader_is_bundle(LV2_OSC_Reader * reader)556 lv2_osc_reader_is_bundle(LV2_OSC_Reader *reader)
557 {
558 return strncmp((const char *)reader->ptr, "#bundle", 8) == 0;
559 }
560
561 static inline bool
lv2_osc_reader_is_message(LV2_OSC_Reader * reader)562 lv2_osc_reader_is_message(LV2_OSC_Reader *reader)
563 {
564 return reader->ptr[0] == '/'; //FIXME check path
565 }
566
567 #ifdef __cplusplus
568 } // extern "C"
569 #endif
570
571 #endif // LV2_OSC_READER_H
572