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