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.

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