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.

rtosc.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  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.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_off(const char *msg, unsigned idx)
  72. {
  73. if(!has_reserved(rtosc_type(msg,idx)))
  74. return 0;
  75. //Iterate to the right position
  76. const uint8_t *args = (const uint8_t*) rtosc_argument_string(msg);
  77. const uint8_t *aligned_ptr = args-1;
  78. const uint8_t *arg_pos = args;
  79. while(*++arg_pos);
  80. //Alignment
  81. arg_pos += 4-(arg_pos-((uint8_t*)aligned_ptr))%4;
  82. //ignore any leading '[' or ']'
  83. while(*args == '[' || *args == ']')
  84. ++args;
  85. while(idx--) {
  86. uint32_t bundle_length = 0;
  87. switch(*args++)
  88. {
  89. case 'h':
  90. case 't':
  91. case 'd':
  92. arg_pos +=8;
  93. break;
  94. case 'm':
  95. case 'r':
  96. case 'f':
  97. case 'c':
  98. case 'i':
  99. arg_pos += 4;
  100. break;
  101. case 'S':
  102. case 's':
  103. while(*++arg_pos);
  104. arg_pos += 4-(arg_pos-((uint8_t*)aligned_ptr))%4;
  105. break;
  106. case 'b':
  107. bundle_length |= (*arg_pos++ << 24);
  108. bundle_length |= (*arg_pos++ << 16);
  109. bundle_length |= (*arg_pos++ << 8);
  110. bundle_length |= (*arg_pos++);
  111. if(bundle_length%4)
  112. bundle_length += 4-bundle_length%4;
  113. arg_pos += bundle_length;
  114. break;
  115. case '[':
  116. case ']':
  117. //completely ignore array chars
  118. ++idx;
  119. break;
  120. case 'T':
  121. case 'F':
  122. case 'I':
  123. ;
  124. }
  125. }
  126. return arg_pos-(uint8_t*)msg;
  127. }
  128. size_t rtosc_message(char *buffer,
  129. size_t len,
  130. const char *address,
  131. const char *arguments,
  132. ...)
  133. {
  134. va_list va;
  135. va_start(va, arguments);
  136. size_t result = rtosc_vmessage(buffer, len, address, arguments, va);
  137. va_end(va);
  138. return result;
  139. }
  140. //Calculate the size of the message without writing to a buffer
  141. static size_t vsosc_null(const char *address,
  142. const char *arguments,
  143. const rtosc_arg_t *args)
  144. {
  145. unsigned pos = 0;
  146. pos += strlen(address);
  147. pos += 4-pos%4;//get 32 bit alignment
  148. pos += 1+strlen(arguments);
  149. pos += 4-pos%4;
  150. unsigned toparse = nreserved(arguments);
  151. unsigned arg_pos = 0;
  152. //Take care of varargs
  153. while(toparse)
  154. {
  155. char arg = *arguments++;
  156. assert(arg);
  157. int i;
  158. const char *s;
  159. switch(arg) {
  160. case 'h':
  161. case 't':
  162. case 'd':
  163. ++arg_pos;
  164. pos += 8;
  165. --toparse;
  166. break;
  167. case 'm':
  168. case 'r':
  169. case 'c':
  170. case 'f':
  171. case 'i':
  172. ++arg_pos;
  173. pos += 4;
  174. --toparse;
  175. break;
  176. case 's':
  177. case 'S':
  178. s = args[arg_pos++].s;
  179. assert(s && "Input strings CANNOT be NULL");
  180. pos += strlen(s);
  181. pos += 4-pos%4;
  182. --toparse;
  183. break;
  184. case 'b':
  185. i = args[arg_pos++].b.len;
  186. pos += 4 + i;
  187. if(pos%4)
  188. pos += 4-pos%4;
  189. --toparse;
  190. break;
  191. default:
  192. ;
  193. }
  194. }
  195. return pos;
  196. }
  197. size_t rtosc_vmessage(char *buffer,
  198. size_t len,
  199. const char *address,
  200. const char *arguments,
  201. va_list ap)
  202. {
  203. const unsigned nargs = nreserved(arguments);
  204. if(!nargs)
  205. return rtosc_amessage(buffer,len,address,arguments,NULL);
  206. rtosc_arg_t args[nargs];
  207. unsigned arg_pos = 0;
  208. const char *arg_str = arguments;
  209. uint8_t *midi_tmp;
  210. while(arg_pos < nargs)
  211. {
  212. switch(*arg_str++) {
  213. case 'h':
  214. case 't':
  215. args[arg_pos++].h = va_arg(ap, int64_t);
  216. break;
  217. case 'd':
  218. args[arg_pos++].d = va_arg(ap, double);
  219. break;
  220. case 'c':
  221. case 'i':
  222. case 'r':
  223. args[arg_pos++].i = va_arg(ap, int);
  224. break;
  225. case 'm':
  226. midi_tmp = va_arg(ap, uint8_t *);
  227. args[arg_pos].m[0] = midi_tmp[0];
  228. args[arg_pos].m[1] = midi_tmp[1];
  229. args[arg_pos].m[2] = midi_tmp[2];
  230. args[arg_pos++].m[3] = midi_tmp[3];
  231. break;
  232. case 'S':
  233. case 's':
  234. args[arg_pos++].s = va_arg(ap, const char *);
  235. break;
  236. case 'b':
  237. args[arg_pos].b.len = va_arg(ap, int);
  238. args[arg_pos].b.data = va_arg(ap, unsigned char *);
  239. arg_pos++;
  240. break;
  241. case 'f':
  242. args[arg_pos++].f = va_arg(ap, double);
  243. break;
  244. default:
  245. ;
  246. }
  247. }
  248. return rtosc_amessage(buffer,len,address,arguments,args);
  249. }
  250. size_t rtosc_amessage(char *buffer,
  251. size_t len,
  252. const char *address,
  253. const char *arguments,
  254. const rtosc_arg_t *args)
  255. {
  256. const size_t total_len = vsosc_null(address, arguments, args);
  257. if(!buffer)
  258. return total_len;
  259. //Abort if the message cannot fit
  260. if(total_len>len) {
  261. memset(buffer, 0, len);
  262. return 0;
  263. }
  264. memset(buffer, 0, total_len);
  265. unsigned pos = 0;
  266. while(*address)
  267. buffer[pos++] = *address++;
  268. //get 32 bit alignment
  269. pos += 4-pos%4;
  270. buffer[pos++] = ',';
  271. const char *arg_str = arguments;
  272. while(*arg_str)
  273. buffer[pos++] = *arg_str++;
  274. pos += 4-pos%4;
  275. unsigned toparse = nreserved(arguments);
  276. unsigned arg_pos = 0;
  277. while(toparse)
  278. {
  279. char arg = *arguments++;
  280. assert(arg);
  281. int32_t i;
  282. int64_t d;
  283. const uint8_t *m;
  284. const char *s;
  285. const unsigned char *u;
  286. rtosc_blob_t b;
  287. switch(arg) {
  288. case 'h':
  289. case 't':
  290. case 'd':
  291. d = args[arg_pos++].t;
  292. buffer[pos++] = ((d>>56) & 0xff);
  293. buffer[pos++] = ((d>>48) & 0xff);
  294. buffer[pos++] = ((d>>40) & 0xff);
  295. buffer[pos++] = ((d>>32) & 0xff);
  296. buffer[pos++] = ((d>>24) & 0xff);
  297. buffer[pos++] = ((d>>16) & 0xff);
  298. buffer[pos++] = ((d>>8) & 0xff);
  299. buffer[pos++] = (d & 0xff);
  300. --toparse;
  301. break;
  302. case 'r':
  303. case 'f':
  304. case 'c':
  305. case 'i':
  306. i = args[arg_pos++].i;
  307. buffer[pos++] = ((i>>24) & 0xff);
  308. buffer[pos++] = ((i>>16) & 0xff);
  309. buffer[pos++] = ((i>>8) & 0xff);
  310. buffer[pos++] = (i & 0xff);
  311. --toparse;
  312. break;
  313. case 'm':
  314. //TODO verify ordering of spec
  315. m = args[arg_pos++].m;
  316. buffer[pos++] = m[0];
  317. buffer[pos++] = m[1];
  318. buffer[pos++] = m[2];
  319. buffer[pos++] = m[3];
  320. --toparse;
  321. break;
  322. case 'S':
  323. case 's':
  324. s = args[arg_pos++].s;
  325. while(*s)
  326. buffer[pos++] = *s++;
  327. pos += 4-pos%4;
  328. --toparse;
  329. break;
  330. case 'b':
  331. b = args[arg_pos++].b;
  332. i = b.len;
  333. buffer[pos++] = ((i>>24) & 0xff);
  334. buffer[pos++] = ((i>>16) & 0xff);
  335. buffer[pos++] = ((i>>8) & 0xff);
  336. buffer[pos++] = (i & 0xff);
  337. u = b.data;
  338. if(u) {
  339. while(i--)
  340. buffer[pos++] = *u++;
  341. }
  342. else
  343. pos += i;
  344. if(pos%4)
  345. pos += 4-pos%4;
  346. --toparse;
  347. break;
  348. default:
  349. ;
  350. }
  351. }
  352. return pos;
  353. }
  354. rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
  355. {
  356. rtosc_arg_t result = {0};
  357. char type = rtosc_type(msg, idx);
  358. //trivial case
  359. if(!has_reserved(type)) {
  360. switch(type)
  361. {
  362. case 'T':
  363. result.T = true;
  364. break;
  365. case 'F':
  366. result.T = false;
  367. break;
  368. default:
  369. ;
  370. }
  371. } else {
  372. const unsigned char *arg_pos = (const unsigned char*)msg+arg_off(msg,idx);
  373. switch(type)
  374. {
  375. case 'h':
  376. case 't':
  377. case 'd':
  378. result.t |= (((uint64_t)*arg_pos++) << 56);
  379. result.t |= (((uint64_t)*arg_pos++) << 48);
  380. result.t |= (((uint64_t)*arg_pos++) << 40);
  381. result.t |= (((uint64_t)*arg_pos++) << 32);
  382. result.t |= (((uint64_t)*arg_pos++) << 24);
  383. result.t |= (((uint64_t)*arg_pos++) << 16);
  384. result.t |= (((uint64_t)*arg_pos++) << 8);
  385. result.t |= (((uint64_t)*arg_pos++));
  386. break;
  387. case 'r':
  388. case 'f':
  389. case 'c':
  390. case 'i':
  391. result.i |= (*arg_pos++ << 24);
  392. result.i |= (*arg_pos++ << 16);
  393. result.i |= (*arg_pos++ << 8);
  394. result.i |= (*arg_pos++);
  395. break;
  396. case 'm':
  397. result.m[0] = *arg_pos++;
  398. result.m[1] = *arg_pos++;
  399. result.m[2] = *arg_pos++;
  400. result.m[3] = *arg_pos++;
  401. break;
  402. case 'b':
  403. result.b.len |= (*arg_pos++ << 24);
  404. result.b.len |= (*arg_pos++ << 16);
  405. result.b.len |= (*arg_pos++ << 8);
  406. result.b.len |= (*arg_pos++);
  407. result.b.data = (unsigned char *)arg_pos;
  408. break;
  409. case 'S':
  410. case 's':
  411. result.s = (char *)arg_pos;
  412. break;
  413. }
  414. }
  415. return result;
  416. }
  417. static unsigned char deref(unsigned pos, ring_t *ring)
  418. {
  419. return pos<ring[0].len ? ring[0].data[pos] :
  420. ((pos-ring[0].len)<ring[1].len ? ring[1].data[pos-ring[0].len] : 0x00);
  421. }
  422. static size_t bundle_ring_length(ring_t *ring)
  423. {
  424. unsigned pos = 8+8;//goto first length field
  425. uint32_t advance = 0;
  426. do {
  427. advance = deref(pos+0, ring) << (8*0) |
  428. deref(pos+1, ring) << (8*1) |
  429. deref(pos+2, ring) << (8*2) |
  430. deref(pos+3, ring) << (8*3);
  431. if(advance)
  432. pos += 4+advance;
  433. } while(advance);
  434. return pos <= (ring[0].len+ring[1].len) ? pos : 0;
  435. }
  436. //Zero means no full message present
  437. size_t rtosc_message_ring_length(ring_t *ring)
  438. {
  439. //Check if the message is a bundle
  440. if(deref(0,ring) == '#' &&
  441. deref(1,ring) == 'b' &&
  442. deref(2,ring) == 'u' &&
  443. deref(3,ring) == 'n' &&
  444. deref(4,ring) == 'd' &&
  445. deref(5,ring) == 'l' &&
  446. deref(6,ring) == 'e' &&
  447. deref(7,ring) == '\0')
  448. return bundle_ring_length(ring);
  449. //Proceed for normal messages
  450. //Consume path
  451. unsigned pos = 0;
  452. while(deref(pos++,ring));
  453. pos--;
  454. //Travel through the null word end [1..4] bytes
  455. for(int i=0; i<4; ++i)
  456. if(deref(++pos, ring))
  457. break;
  458. if(deref(pos, ring) != ',')
  459. return 0;
  460. unsigned aligned_pos = pos;
  461. int arguments = pos+1;
  462. while(deref(++pos,ring));
  463. pos += 4-(pos-aligned_pos)%4;
  464. unsigned toparse = 0;
  465. {
  466. int arg = arguments-1;
  467. while(deref(++arg,ring))
  468. toparse += has_reserved(deref(arg,ring));
  469. }
  470. //Take care of varargs
  471. while(toparse)
  472. {
  473. char arg = deref(arguments++,ring);
  474. assert(arg);
  475. uint32_t i;
  476. switch(arg) {
  477. case 'h':
  478. case 't':
  479. case 'd':
  480. pos += 8;
  481. --toparse;
  482. break;
  483. case 'm':
  484. case 'r':
  485. case 'c':
  486. case 'f':
  487. case 'i':
  488. pos += 4;
  489. --toparse;
  490. break;
  491. case 'S':
  492. case 's':
  493. while(deref(++pos,ring));
  494. pos += 4-(pos-aligned_pos)%4;
  495. --toparse;
  496. break;
  497. case 'b':
  498. i = 0;
  499. i |= (deref(pos++,ring) << 24);
  500. i |= (deref(pos++,ring) << 16);
  501. i |= (deref(pos++,ring) << 8);
  502. i |= (deref(pos++,ring));
  503. pos += i;
  504. if((pos-aligned_pos)%4)
  505. pos += 4-(pos-aligned_pos)%4;
  506. --toparse;
  507. break;
  508. default:
  509. ;
  510. }
  511. }
  512. return pos <= (ring[0].len+ring[1].len) ? pos : 0;
  513. }
  514. size_t rtosc_message_length(const char *msg, size_t len)
  515. {
  516. ring_t ring[2] = {{(char*)msg,len},{NULL,0}};
  517. return rtosc_message_ring_length(ring);
  518. }
  519. bool rtosc_valid_message_p(const char *msg, size_t len)
  520. {
  521. //Validate Path Characters (assumes printable characters are sufficient)
  522. if(*msg != '/')
  523. return false;
  524. const char *tmp = msg;
  525. for(unsigned i=0; i<len; ++i) {
  526. if(*tmp == 0)
  527. break;
  528. if(!isprint(*tmp))
  529. return false;
  530. tmp++;
  531. }
  532. //tmp is now either pointing to a null or the end of the string
  533. const size_t offset1 = tmp-msg;
  534. size_t offset2 = tmp-msg;
  535. for(; offset2<len; offset2++) {
  536. if(*tmp == ',')
  537. break;
  538. tmp++;
  539. }
  540. //Too many NULL bytes
  541. if(offset2-offset1 > 4)
  542. return false;
  543. if((offset2 % 4) != 0)
  544. return false;
  545. size_t observed_length = rtosc_message_length(msg, len);
  546. return observed_length == len;
  547. }
  548. size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...)
  549. {
  550. char *_buffer = buffer;
  551. memset(buffer, 0, len);
  552. strcpy(buffer, "#bundle");
  553. buffer += 8;
  554. (*(uint64_t*)buffer) = tt;
  555. buffer +=8;
  556. va_list va;
  557. va_start(va, elms);
  558. for(int i=0; i<elms; ++i) {
  559. const char *msg = va_arg(va, const char*);
  560. //It is assumed that any passed message/bundle is valid
  561. size_t size = rtosc_message_length(msg, -1);
  562. *(uint32_t*)buffer = size;
  563. buffer += 4;
  564. memcpy(buffer, msg, size);
  565. buffer+=size;
  566. }
  567. va_end(va);
  568. return buffer-_buffer;
  569. }
  570. #define POS ((size_t)(((const char *)lengths) - buffer))
  571. size_t rtosc_bundle_elements(const char *buffer, size_t len)
  572. {
  573. const uint32_t *lengths = (const uint32_t*) (buffer+16);
  574. size_t elms = 0;
  575. //TODO
  576. while(POS < len && *lengths) {
  577. lengths += *lengths/4+1;
  578. if(POS > len)
  579. break;
  580. ++elms;
  581. }
  582. return elms;
  583. }
  584. #undef POS
  585. const char *rtosc_bundle_fetch(const char *buffer, unsigned elm)
  586. {
  587. const uint32_t *lengths = (const uint32_t*) (buffer+16);
  588. size_t elm_pos = 0;
  589. while(elm_pos!=elm && *lengths) ++elm_pos, lengths+=*lengths/4+1;
  590. return (const char*) (elm==elm_pos?lengths+1:NULL);
  591. }
  592. size_t rtosc_bundle_size(const char *buffer, unsigned elm)
  593. {
  594. const uint32_t *lengths = (const uint32_t*) (buffer+16);
  595. size_t elm_pos = 0;
  596. size_t last_len = 0;
  597. while(elm_pos!=elm && *lengths) {
  598. last_len = *lengths;
  599. ++elm_pos, lengths+=*lengths/4+1;
  600. }
  601. return last_len;
  602. }
  603. int rtosc_bundle_p(const char *msg)
  604. {
  605. return !strcmp(msg,"#bundle");
  606. }
  607. uint64_t rtosc_bundle_timetag(const char *msg)
  608. {
  609. return *(uint64_t*)(msg+8);
  610. }