Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1007 lines
27KB

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