fast_osc 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,781 @@
1
+ #include <stdint.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include <stdarg.h>
5
+ #include <stdbool.h>
6
+ #include <ctype.h>
7
+ #include <assert.h>
8
+
9
+ // #include <rtosc.h>
10
+
11
+ const char *rtosc_argument_string(const char *msg)
12
+ {
13
+ assert(msg && *msg);
14
+ while(*++msg); //skip pattern
15
+ while(!*++msg);//skip null
16
+ return msg+1; //skip comma
17
+ }
18
+
19
+ unsigned rtosc_narguments(const char *msg)
20
+ {
21
+ const char *args = rtosc_argument_string(msg);
22
+ int nargs = 0;
23
+ while(*args++)
24
+ nargs += (*args == ']' || *args == '[') ? 0 : 1;
25
+ return nargs;
26
+ }
27
+
28
+ static int has_reserved(char type)
29
+ {
30
+ switch(type)
31
+ {
32
+ case 'i'://official types
33
+ case 's':
34
+ case 'b':
35
+ case 'f':
36
+
37
+ case 'h'://unofficial
38
+ case 't':
39
+ case 'd':
40
+ case 'S':
41
+ case 'r':
42
+ case 'm':
43
+ case 'c':
44
+ return 1;
45
+ case 'T':
46
+ case 'F':
47
+ case 'N':
48
+ case 'I':
49
+ case '[':
50
+ case ']':
51
+ return 0;
52
+ }
53
+
54
+ //Should not happen
55
+ return 0;
56
+ }
57
+
58
+ static unsigned nreserved(const char *args)
59
+ {
60
+ unsigned res = 0;
61
+ for(;*args;++args)
62
+ res += has_reserved(*args);
63
+
64
+ return res;
65
+ }
66
+
67
+ char rtosc_type(const char *msg, unsigned nargument)
68
+ {
69
+ assert(nargument < rtosc_narguments(msg));
70
+ const char *arg = rtosc_argument_string(msg);
71
+ while(1) {
72
+ if(*arg == '[' || *arg == ']')
73
+ ++arg;
74
+ else if(!nargument || !*arg)
75
+ return *arg;
76
+ else
77
+ ++arg, --nargument;
78
+ }
79
+ }
80
+
81
+ static unsigned arg_start(const char *msg_)
82
+ {
83
+ const uint8_t *msg = (const uint8_t*)msg_;
84
+ //Iterate to the right position
85
+ const uint8_t *args = (const uint8_t*) rtosc_argument_string(msg_);
86
+ const uint8_t *aligned_ptr = args-1;
87
+ const uint8_t *arg_pos = args;
88
+
89
+ while(*++arg_pos);
90
+ //Alignment
91
+ arg_pos += 4-(arg_pos-aligned_ptr)%4;
92
+ return arg_pos-msg;
93
+ }
94
+
95
+ static unsigned arg_size(const uint8_t *arg_mem, char type)
96
+ {
97
+ if(!has_reserved(type))
98
+ return 0;
99
+ const uint8_t *arg_pos=arg_mem;
100
+ uint32_t blob_length = 0;
101
+ switch(type)
102
+ {
103
+ case 'h':
104
+ case 't':
105
+ case 'd':
106
+ return 8;
107
+ case 'm':
108
+ case 'r':
109
+ case 'f':
110
+ case 'c':
111
+ case 'i':
112
+ return 4;
113
+ case 'S':
114
+ case 's':
115
+ while(*++arg_pos);
116
+ arg_pos += 4-(arg_pos-arg_mem)%4;
117
+ return arg_pos-arg_mem;
118
+ case 'b':
119
+ blob_length |= (*arg_pos++ << 24);
120
+ blob_length |= (*arg_pos++ << 16);
121
+ blob_length |= (*arg_pos++ << 8);
122
+ blob_length |= (*arg_pos++);
123
+ if(blob_length%4)
124
+ blob_length += 4-blob_length%4;
125
+ arg_pos += blob_length;
126
+ return arg_pos-arg_mem;
127
+ default:
128
+ assert("Invalid Type");
129
+ }
130
+ return -1;
131
+ }
132
+
133
+ static unsigned arg_off(const char *msg, unsigned idx)
134
+ {
135
+ if(!has_reserved(rtosc_type(msg,idx)))
136
+ return 0;
137
+
138
+ //Iterate to the right position
139
+ const uint8_t *args = (const uint8_t*) rtosc_argument_string(msg);
140
+ const uint8_t *aligned_ptr = args-1;
141
+ const uint8_t *arg_pos = args;
142
+
143
+ while(*++arg_pos);
144
+ //Alignment
145
+ arg_pos += 4-(arg_pos-((uint8_t*)aligned_ptr))%4;
146
+
147
+ //ignore any leading '[' or ']'
148
+ while(*args == '[' || *args == ']')
149
+ ++args;
150
+
151
+ while(idx--) {
152
+ char type = *args++;
153
+ if(type == '[' || type == ']')
154
+ idx++;//not a valid arg idx
155
+ else
156
+ arg_pos += arg_size(arg_pos, type);
157
+ }
158
+ return arg_pos-(uint8_t*)msg;
159
+ }
160
+
161
+ size_t rtosc_message(char *buffer,
162
+ size_t len,
163
+ const char *address,
164
+ const char *arguments,
165
+ ...)
166
+ {
167
+ va_list va;
168
+ va_start(va, arguments);
169
+ size_t result = rtosc_vmessage(buffer, len, address, arguments, va);
170
+ va_end(va);
171
+ return result;
172
+ }
173
+
174
+ //Calculate the size of the message without writing to a buffer
175
+ static size_t vsosc_null(const char *address,
176
+ const char *arguments,
177
+ const rtosc_arg_t *args)
178
+ {
179
+ unsigned pos = 0;
180
+ pos += strlen(address);
181
+ pos += 4-pos%4;//get 32 bit alignment
182
+ pos += 1+strlen(arguments);
183
+ pos += 4-pos%4;
184
+
185
+ unsigned toparse = nreserved(arguments);
186
+ unsigned arg_pos = 0;
187
+
188
+ //Take care of varargs
189
+ while(toparse)
190
+ {
191
+ char arg = *arguments++;
192
+ assert(arg);
193
+ int i;
194
+ const char *s;
195
+ switch(arg) {
196
+ case 'h':
197
+ case 't':
198
+ case 'd':
199
+ ++arg_pos;
200
+ pos += 8;
201
+ --toparse;
202
+ break;
203
+ case 'm':
204
+ case 'r':
205
+ case 'c':
206
+ case 'f':
207
+ case 'i':
208
+ ++arg_pos;
209
+ pos += 4;
210
+ --toparse;
211
+ break;
212
+ case 's':
213
+ case 'S':
214
+ s = args[arg_pos++].s;
215
+ assert(s && "Input strings CANNOT be NULL");
216
+ pos += strlen(s);
217
+ pos += 4-pos%4;
218
+ --toparse;
219
+ break;
220
+ case 'b':
221
+ i = args[arg_pos++].b.len;
222
+ pos += 4 + i;
223
+ if(pos%4)
224
+ pos += 4-pos%4;
225
+ --toparse;
226
+ break;
227
+ default:
228
+ ;
229
+ }
230
+ }
231
+
232
+ return pos;
233
+ }
234
+ size_t rtosc_vmessage(char *buffer,
235
+ size_t len,
236
+ const char *address,
237
+ const char *arguments,
238
+ va_list ap)
239
+ {
240
+ const unsigned nargs = nreserved(arguments);
241
+ if(!nargs)
242
+ return rtosc_amessage(buffer,len,address,arguments,NULL);
243
+
244
+ rtosc_arg_t args[nargs];
245
+
246
+ unsigned arg_pos = 0;
247
+ const char *arg_str = arguments;
248
+ uint8_t *midi_tmp;
249
+ while(arg_pos < nargs)
250
+ {
251
+ switch(*arg_str++) {
252
+ case 'h':
253
+ case 't':
254
+ args[arg_pos++].h = va_arg(ap, int64_t);
255
+ break;
256
+ case 'd':
257
+ args[arg_pos++].d = va_arg(ap, double);
258
+ break;
259
+ case 'c':
260
+ case 'i':
261
+ case 'r':
262
+ args[arg_pos++].i = va_arg(ap, int);
263
+ break;
264
+ case 'm':
265
+ midi_tmp = va_arg(ap, uint8_t *);
266
+ args[arg_pos].m[0] = midi_tmp[0];
267
+ args[arg_pos].m[1] = midi_tmp[1];
268
+ args[arg_pos].m[2] = midi_tmp[2];
269
+ args[arg_pos++].m[3] = midi_tmp[3];
270
+ break;
271
+ case 'S':
272
+ case 's':
273
+ args[arg_pos++].s = va_arg(ap, const char *);
274
+ break;
275
+ case 'b':
276
+ args[arg_pos].b.len = va_arg(ap, int);
277
+ args[arg_pos].b.data = va_arg(ap, unsigned char *);
278
+ arg_pos++;
279
+ break;
280
+ case 'f':
281
+ args[arg_pos++].f = va_arg(ap, double);
282
+ break;
283
+ default:
284
+ ;
285
+ }
286
+ }
287
+
288
+ return rtosc_amessage(buffer,len,address,arguments,args);
289
+ }
290
+
291
+ size_t rtosc_amessage(char *buffer,
292
+ size_t len,
293
+ const char *address,
294
+ const char *arguments,
295
+ const rtosc_arg_t *args)
296
+ {
297
+ const size_t total_len = vsosc_null(address, arguments, args);
298
+
299
+ if(!buffer)
300
+ return total_len;
301
+
302
+ //Abort if the message cannot fit
303
+ if(total_len>len) {
304
+ memset(buffer, 0, len);
305
+ return 0;
306
+ }
307
+
308
+ memset(buffer, 0, total_len);
309
+
310
+ unsigned pos = 0;
311
+ while(*address)
312
+ buffer[pos++] = *address++;
313
+
314
+ //get 32 bit alignment
315
+ pos += 4-pos%4;
316
+
317
+ buffer[pos++] = ',';
318
+
319
+ const char *arg_str = arguments;
320
+ while(*arg_str)
321
+ buffer[pos++] = *arg_str++;
322
+
323
+ pos += 4-pos%4;
324
+
325
+ unsigned toparse = nreserved(arguments);
326
+ unsigned arg_pos = 0;
327
+ while(toparse)
328
+ {
329
+ char arg = *arguments++;
330
+ assert(arg);
331
+ int32_t i;
332
+ int64_t d;
333
+ const uint8_t *m;
334
+ const char *s;
335
+ const unsigned char *u;
336
+ rtosc_blob_t b;
337
+ switch(arg) {
338
+ case 'h':
339
+ case 't':
340
+ case 'd':
341
+ d = args[arg_pos++].t;
342
+ buffer[pos++] = ((d>>56) & 0xff);
343
+ buffer[pos++] = ((d>>48) & 0xff);
344
+ buffer[pos++] = ((d>>40) & 0xff);
345
+ buffer[pos++] = ((d>>32) & 0xff);
346
+ buffer[pos++] = ((d>>24) & 0xff);
347
+ buffer[pos++] = ((d>>16) & 0xff);
348
+ buffer[pos++] = ((d>>8) & 0xff);
349
+ buffer[pos++] = (d & 0xff);
350
+ --toparse;
351
+ break;
352
+ case 'r':
353
+ case 'f':
354
+ case 'c':
355
+ case 'i':
356
+ i = args[arg_pos++].i;
357
+ buffer[pos++] = ((i>>24) & 0xff);
358
+ buffer[pos++] = ((i>>16) & 0xff);
359
+ buffer[pos++] = ((i>>8) & 0xff);
360
+ buffer[pos++] = (i & 0xff);
361
+ --toparse;
362
+ break;
363
+ case 'm':
364
+ //TODO verify ordering of spec
365
+ m = args[arg_pos++].m;
366
+ buffer[pos++] = m[0];
367
+ buffer[pos++] = m[1];
368
+ buffer[pos++] = m[2];
369
+ buffer[pos++] = m[3];
370
+ --toparse;
371
+ break;
372
+ case 'S':
373
+ case 's':
374
+ s = args[arg_pos++].s;
375
+ while(*s)
376
+ buffer[pos++] = *s++;
377
+ pos += 4-pos%4;
378
+ --toparse;
379
+ break;
380
+ case 'b':
381
+ b = args[arg_pos++].b;
382
+ i = b.len;
383
+ buffer[pos++] = ((i>>24) & 0xff);
384
+ buffer[pos++] = ((i>>16) & 0xff);
385
+ buffer[pos++] = ((i>>8) & 0xff);
386
+ buffer[pos++] = (i & 0xff);
387
+ u = b.data;
388
+ if(u) {
389
+ while(i--)
390
+ buffer[pos++] = *u++;
391
+ }
392
+ else
393
+ pos += i;
394
+ if(pos%4)
395
+ pos += 4-pos%4;
396
+ --toparse;
397
+ break;
398
+ default:
399
+ ;
400
+ }
401
+ }
402
+
403
+ return pos;
404
+ }
405
+
406
+ static rtosc_arg_t extract_arg(const uint8_t *arg_pos, char type)
407
+ {
408
+ rtosc_arg_t result = {0};
409
+ //trivial case
410
+ if(!has_reserved(type)) {
411
+ switch(type)
412
+ {
413
+ case 'T':
414
+ result.T = true;
415
+ break;
416
+ case 'F':
417
+ result.T = false;
418
+ break;
419
+ default:
420
+ ;
421
+ }
422
+ } else {
423
+ switch(type)
424
+ {
425
+ case 'h':
426
+ case 't':
427
+ case 'd':
428
+ result.t |= (((uint64_t)*arg_pos++) << 56);
429
+ result.t |= (((uint64_t)*arg_pos++) << 48);
430
+ result.t |= (((uint64_t)*arg_pos++) << 40);
431
+ result.t |= (((uint64_t)*arg_pos++) << 32);
432
+ result.t |= (((uint64_t)*arg_pos++) << 24);
433
+ result.t |= (((uint64_t)*arg_pos++) << 16);
434
+ result.t |= (((uint64_t)*arg_pos++) << 8);
435
+ result.t |= (((uint64_t)*arg_pos++));
436
+ break;
437
+ case 'r':
438
+ case 'f':
439
+ case 'c':
440
+ case 'i':
441
+ result.i |= (*arg_pos++ << 24);
442
+ result.i |= (*arg_pos++ << 16);
443
+ result.i |= (*arg_pos++ << 8);
444
+ result.i |= (*arg_pos++);
445
+ break;
446
+ case 'm':
447
+ result.m[0] = *arg_pos++;
448
+ result.m[1] = *arg_pos++;
449
+ result.m[2] = *arg_pos++;
450
+ result.m[3] = *arg_pos++;
451
+ break;
452
+ case 'b':
453
+ result.b.len |= (*arg_pos++ << 24);
454
+ result.b.len |= (*arg_pos++ << 16);
455
+ result.b.len |= (*arg_pos++ << 8);
456
+ result.b.len |= (*arg_pos++);
457
+ result.b.data = (unsigned char *)arg_pos;
458
+ break;
459
+ case 'S':
460
+ case 's':
461
+ result.s = (char *)arg_pos;
462
+ break;
463
+ }
464
+ }
465
+
466
+ return result;
467
+ }
468
+
469
+ static const char *advance_past_dummy_args(const char *args)
470
+ {
471
+ while(*args == '[' || *args == ']')
472
+ args++;
473
+ return args;
474
+ }
475
+
476
+ rtosc_arg_itr_t rtosc_itr_begin(const char *msg)
477
+ {
478
+ rtosc_arg_itr_t itr;
479
+ itr.type_pos = advance_past_dummy_args(rtosc_argument_string(msg));
480
+ itr.value_pos = (uint8_t*)(msg+arg_start(msg));
481
+
482
+ return itr;
483
+ }
484
+
485
+ rtosc_arg_val_t rtosc_itr_next(rtosc_arg_itr_t *itr)
486
+ {
487
+ //current position provides the value
488
+ rtosc_arg_val_t result = {0,{0}};
489
+ result.type = *itr->type_pos;
490
+ if(result.type)
491
+ result.val = extract_arg(itr->value_pos, result.type);
492
+
493
+ //advance
494
+ itr->type_pos = advance_past_dummy_args(itr->type_pos+1);
495
+ char type = result.type;
496
+ int size = arg_size(itr->value_pos, type);
497
+ itr->value_pos += size;
498
+
499
+
500
+ return result;
501
+ }
502
+
503
+ int rtosc_itr_end(rtosc_arg_itr_t itr)
504
+ {
505
+ return !itr.type_pos || !*itr.type_pos;
506
+ }
507
+
508
+ rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
509
+ {
510
+ char type = rtosc_type(msg, idx);
511
+ uint8_t *arg_mem = (uint8_t*)msg + arg_off(msg, idx);
512
+ return extract_arg(arg_mem, type);
513
+ }
514
+
515
+ static unsigned char deref(unsigned pos, ring_t *ring)
516
+ {
517
+ return pos<ring[0].len ? ring[0].data[pos] :
518
+ ((pos-ring[0].len)<ring[1].len ? ring[1].data[pos-ring[0].len] : 0x00);
519
+ }
520
+
521
+ static size_t bundle_ring_length(ring_t *ring)
522
+ {
523
+ unsigned pos = 8+8;//goto first length field
524
+ uint32_t advance = 0;
525
+ do {
526
+ advance = deref(pos+0, ring) << (8*3) |
527
+ deref(pos+1, ring) << (8*2) |
528
+ deref(pos+2, ring) << (8*1) |
529
+ deref(pos+3, ring) << (8*0);
530
+ if(advance)
531
+ pos += 4+advance;
532
+ } while(advance);
533
+
534
+ return pos <= (ring[0].len+ring[1].len) ? pos : 0;
535
+ }
536
+
537
+ //Zero means no full message present
538
+ size_t rtosc_message_ring_length(ring_t *ring)
539
+ {
540
+ //Check if the message is a bundle
541
+ if(deref(0,ring) == '#' &&
542
+ deref(1,ring) == 'b' &&
543
+ deref(2,ring) == 'u' &&
544
+ deref(3,ring) == 'n' &&
545
+ deref(4,ring) == 'd' &&
546
+ deref(5,ring) == 'l' &&
547
+ deref(6,ring) == 'e' &&
548
+ deref(7,ring) == '\0')
549
+ return bundle_ring_length(ring);
550
+
551
+ //Proceed for normal messages
552
+ //Consume path
553
+ unsigned pos = 0;
554
+ while(deref(pos++,ring));
555
+ pos--;
556
+
557
+ //Travel through the null word end [1..4] bytes
558
+ for(int i=0; i<4; ++i)
559
+ if(deref(++pos, ring))
560
+ break;
561
+
562
+ if(deref(pos, ring) != ',')
563
+ return 0;
564
+
565
+ unsigned aligned_pos = pos;
566
+ int arguments = pos+1;
567
+ while(deref(++pos,ring));
568
+ pos += 4-(pos-aligned_pos)%4;
569
+
570
+ unsigned toparse = 0;
571
+ {
572
+ int arg = arguments-1;
573
+ while(deref(++arg,ring))
574
+ toparse += has_reserved(deref(arg,ring));
575
+ }
576
+
577
+ //Take care of varargs
578
+ while(toparse)
579
+ {
580
+ char arg = deref(arguments++,ring);
581
+ assert(arg);
582
+ uint32_t i;
583
+ switch(arg) {
584
+ case 'h':
585
+ case 't':
586
+ case 'd':
587
+ pos += 8;
588
+ --toparse;
589
+ break;
590
+ case 'm':
591
+ case 'r':
592
+ case 'c':
593
+ case 'f':
594
+ case 'i':
595
+ pos += 4;
596
+ --toparse;
597
+ break;
598
+ case 'S':
599
+ case 's':
600
+ while(deref(++pos,ring));
601
+ pos += 4-(pos-aligned_pos)%4;
602
+ --toparse;
603
+ break;
604
+ case 'b':
605
+ i = 0;
606
+ i |= (deref(pos++,ring) << 24);
607
+ i |= (deref(pos++,ring) << 16);
608
+ i |= (deref(pos++,ring) << 8);
609
+ i |= (deref(pos++,ring));
610
+ pos += i;
611
+ if((pos-aligned_pos)%4)
612
+ pos += 4-(pos-aligned_pos)%4;
613
+ --toparse;
614
+ break;
615
+ default:
616
+ ;
617
+ }
618
+ }
619
+
620
+
621
+ return pos <= (ring[0].len+ring[1].len) ? pos : 0;
622
+ }
623
+
624
+ size_t rtosc_message_length(const char *msg, size_t len)
625
+ {
626
+ ring_t ring[2] = {{(char*)msg,len},{NULL,0}};
627
+ return rtosc_message_ring_length(ring);
628
+ }
629
+
630
+ bool rtosc_valid_message_p(const char *msg, size_t len)
631
+ {
632
+ //Validate Path Characters (assumes printable characters are sufficient)
633
+ if(*msg != '/')
634
+ return false;
635
+ const char *tmp = msg;
636
+ for(unsigned i=0; i<len; ++i) {
637
+ if(*tmp == 0)
638
+ break;
639
+ if(!isprint(*tmp))
640
+ return false;
641
+ tmp++;
642
+ }
643
+
644
+ //tmp is now either pointing to a null or the end of the string
645
+ const size_t offset1 = tmp-msg;
646
+ size_t offset2 = tmp-msg;
647
+ for(; offset2<len; offset2++) {
648
+ if(*tmp == ',')
649
+ break;
650
+ tmp++;
651
+ }
652
+
653
+ //Too many NULL bytes
654
+ if(offset2-offset1 > 4)
655
+ return false;
656
+
657
+ if((offset2 % 4) != 0)
658
+ return false;
659
+
660
+ size_t observed_length = rtosc_message_length(msg, len);
661
+ return observed_length == len;
662
+ }
663
+ static uint64_t extract_uint64(const uint8_t *arg_pos)
664
+ {
665
+ uint64_t arg = 0;
666
+ arg |= (((uint64_t)*arg_pos++) << 56);
667
+ arg |= (((uint64_t)*arg_pos++) << 48);
668
+ arg |= (((uint64_t)*arg_pos++) << 40);
669
+ arg |= (((uint64_t)*arg_pos++) << 32);
670
+ arg |= (((uint64_t)*arg_pos++) << 24);
671
+ arg |= (((uint64_t)*arg_pos++) << 16);
672
+ arg |= (((uint64_t)*arg_pos++) << 8);
673
+ arg |= (((uint64_t)*arg_pos++));
674
+ return arg;
675
+ }
676
+
677
+ static uint32_t extract_uint32(const uint8_t *arg_pos)
678
+ {
679
+ uint32_t arg = 0;
680
+ arg |= (((uint32_t)*arg_pos++) << 24);
681
+ arg |= (((uint32_t)*arg_pos++) << 16);
682
+ arg |= (((uint32_t)*arg_pos++) << 8);
683
+ arg |= (((uint32_t)*arg_pos++));
684
+ return arg;
685
+ }
686
+
687
+ static void emplace_uint64(uint8_t *buffer, uint64_t d)
688
+ {
689
+ buffer[0] = ((d>>56) & 0xff);
690
+ buffer[1] = ((d>>48) & 0xff);
691
+ buffer[2] = ((d>>40) & 0xff);
692
+ buffer[3] = ((d>>32) & 0xff);
693
+ buffer[4] = ((d>>24) & 0xff);
694
+ buffer[5] = ((d>>16) & 0xff);
695
+ buffer[6] = ((d>>8) & 0xff);
696
+ buffer[7] = ((d>>0) & 0xff);
697
+ }
698
+
699
+ static void emplace_uint32(uint8_t *buffer, uint32_t d)
700
+ {
701
+ buffer[0] = ((d>>24) & 0xff);
702
+ buffer[1] = ((d>>16) & 0xff);
703
+ buffer[2] = ((d>>8) & 0xff);
704
+ buffer[3] = ((d>>0) & 0xff);
705
+ }
706
+
707
+ size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...)
708
+ {
709
+ char *_buffer = buffer;
710
+ memset(buffer, 0, len);
711
+ strcpy(buffer, "#bundle");
712
+ buffer += 8;
713
+ emplace_uint64((uint8_t*)buffer, tt);
714
+ buffer += 8;
715
+ va_list va;
716
+ va_start(va, elms);
717
+ for(int i=0; i<elms; ++i) {
718
+ const char *msg = va_arg(va, const char*);
719
+ //It is assumed that any passed message/bundle is valid
720
+ size_t size = rtosc_message_length(msg, -1);
721
+ emplace_uint32((uint8_t*)buffer, size);
722
+ buffer += 4;
723
+ memcpy(buffer, msg, size);
724
+ buffer+=size;
725
+ }
726
+ va_end(va);
727
+
728
+ return buffer-_buffer;
729
+ }
730
+
731
+
732
+ #define POS ((size_t)(((const char *)lengths) - buffer))
733
+ size_t rtosc_bundle_elements(const char *buffer, size_t len)
734
+ {
735
+ const uint32_t *lengths = (const uint32_t*) (buffer+16);
736
+ size_t elms = 0;
737
+ while(POS < len && extract_uint32((const uint8_t*)lengths)) {
738
+ lengths += extract_uint32((const uint8_t*)lengths)/4+1;
739
+
740
+ if(POS > len)
741
+ break;
742
+ ++elms;
743
+ }
744
+ return elms;
745
+ }
746
+ #undef POS
747
+
748
+ const char *rtosc_bundle_fetch(const char *buffer, unsigned elm)
749
+ {
750
+ const uint32_t *lengths = (const uint32_t*) (buffer+16);
751
+ size_t elm_pos = 0;
752
+ while(elm_pos!=elm && extract_uint32((const uint8_t*)lengths)) {
753
+ ++elm_pos;
754
+ lengths += extract_uint32((const uint8_t*)lengths)/4+1;
755
+ }
756
+
757
+ return (const char*) (elm==elm_pos?lengths+1:NULL);
758
+ }
759
+
760
+ size_t rtosc_bundle_size(const char *buffer, unsigned elm)
761
+ {
762
+ const uint32_t *lengths = (const uint32_t*) (buffer+16);
763
+ size_t elm_pos = 0;
764
+ size_t last_len = 0;
765
+ while(elm_pos!=elm && extract_uint32((const uint8_t*)lengths)) {
766
+ last_len = extract_uint32((const uint8_t*)lengths);
767
+ ++elm_pos, lengths+=extract_uint32((const uint8_t*)lengths)/4+1;
768
+ }
769
+
770
+ return last_len;
771
+ }
772
+
773
+ int rtosc_bundle_p(const char *msg)
774
+ {
775
+ return !strcmp(msg,"#bundle");
776
+ }
777
+
778
+ uint64_t rtosc_bundle_timetag(const char *msg)
779
+ {
780
+ return extract_uint64((const uint8_t*)msg+8);
781
+ }