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.

328 lines
9.9KB

  1. /**
  2. * Copyright (c) 2015, Martin Roth (mhroth@gmail.com)
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  9. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  13. * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. * PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <stddef.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #if _WIN32
  21. #include <winsock2.h>
  22. #define tosc_strncpy(_dst, _src, _len) strncpy_s(_dst, _len, _src, _TRUNCATE)
  23. #define htonll(x) _byteswap_uint64(x)
  24. #define ntohll(x) _byteswap_uint64(x)
  25. #else
  26. #include <netinet/in.h>
  27. #define tosc_strncpy(_dst, _src, _len) strncpy(_dst, _src, _len)
  28. #endif
  29. #if __unix__ && !__APPLE__
  30. #include <endian.h>
  31. #define htonll(x) htobe64(x)
  32. #define ntohll(x) be64toh(x)
  33. #endif
  34. #if __APPLE__
  35. #ifndef htonll
  36. #define htonll(x) __DARWIN_OSSwapInt64(x)
  37. #endif
  38. #ifndef ntohll
  39. #define ntohll(x) __DARWIN_OSSwapInt64(x)
  40. #endif
  41. #endif
  42. #include "tinyosc.h"
  43. #define BUNDLE_ID 0x2362756E646C6500L // "#bundle"
  44. // http://opensoundcontrol.org/spec-1_0
  45. int tosc_parseMessage(tosc_message *o, char *buffer, const int len) {
  46. // NOTE(mhroth): if there's a comma in the address, that's weird
  47. int i = 0;
  48. while (buffer[i] != '\0') ++i; // find the null-terimated address
  49. while (buffer[i] != ',') ++i; // find the comma which starts the format string
  50. if (i >= len) return -1; // error while looking for format string
  51. // format string is null terminated
  52. o->format = buffer + i + 1; // format starts after comma
  53. while (i < len && buffer[i] != '\0') ++i;
  54. if (i == len) return -2; // format string not null terminated
  55. i = (i + 4) & ~0x3; // advance to the next multiple of 4 after trailing '\0'
  56. o->marker = buffer + i;
  57. o->buffer = buffer;
  58. o->len = len;
  59. return 0;
  60. }
  61. // check if first eight bytes are '#bundle '
  62. bool tosc_isBundle(const char *buffer) {
  63. return ((*(const int64_t *) buffer) == htonll(BUNDLE_ID));
  64. }
  65. void tosc_parseBundle(tosc_bundle *b, char *buffer, const int len) {
  66. b->buffer = (char *) buffer;
  67. b->marker = buffer + 16; // move past '#bundle ' and timetag fields
  68. b->bufLen = len;
  69. b->bundleLen = len;
  70. }
  71. uint64_t tosc_getTimetag(tosc_bundle *b) {
  72. return ntohll(*((uint64_t *) (b->buffer+8)));
  73. }
  74. uint32_t tosc_getBundleLength(tosc_bundle *b) {
  75. return b->bundleLen;
  76. }
  77. bool tosc_getNextMessage(tosc_bundle *b, tosc_message *o) {
  78. if ((b->marker - b->buffer) >= b->bundleLen) return false;
  79. uint32_t len = (uint32_t) ntohl(*((int32_t *) b->marker));
  80. tosc_parseMessage(o, b->marker+4, len);
  81. b->marker += (4 + len); // move marker to next bundle element
  82. return true;
  83. }
  84. char *tosc_getAddress(tosc_message *o) {
  85. return o->buffer;
  86. }
  87. char *tosc_getFormat(tosc_message *o) {
  88. return o->format;
  89. }
  90. uint32_t tosc_getLength(tosc_message *o) {
  91. return o->len;
  92. }
  93. int32_t tosc_getNextInt32(tosc_message *o) {
  94. // convert from big-endian (network btye order)
  95. const int32_t i = (int32_t) ntohl(*((uint32_t *) o->marker));
  96. o->marker += 4;
  97. return i;
  98. }
  99. int64_t tosc_getNextInt64(tosc_message *o) {
  100. const int64_t i = (int64_t) ntohll(*((uint64_t *) o->marker));
  101. o->marker += 8;
  102. return i;
  103. }
  104. uint64_t tosc_getNextTimetag(tosc_message *o) {
  105. return (uint64_t) tosc_getNextInt64(o);
  106. }
  107. float tosc_getNextFloat(tosc_message *o) {
  108. // convert from big-endian (network btye order)
  109. const uint32_t i = ntohl(*((uint32_t *) o->marker));
  110. o->marker += 4;
  111. return *((float *) (&i));
  112. }
  113. double tosc_getNextDouble(tosc_message *o) {
  114. const uint64_t i = ntohll(*((uint64_t *) o->marker));
  115. o->marker += 8;
  116. return *((double *) (&i));
  117. }
  118. const char *tosc_getNextString(tosc_message *o) {
  119. int i = (int) strlen(o->marker);
  120. if (o->marker + i >= o->buffer + o->len) return NULL;
  121. const char *s = o->marker;
  122. i = (i + 4) & ~0x3; // advance to next multiple of 4 after trailing '\0'
  123. o->marker += i;
  124. return s;
  125. }
  126. void tosc_getNextBlob(tosc_message *o, const char **buffer, int *len) {
  127. int i = (int) ntohl(*((uint32_t *) o->marker)); // get the blob length
  128. if (o->marker + 4 + i <= o->buffer + o->len) {
  129. *len = i; // length of blob
  130. *buffer = o->marker + 4;
  131. i = (i + 7) & ~0x3;
  132. o->marker += i;
  133. } else {
  134. *len = 0;
  135. *buffer = NULL;
  136. }
  137. }
  138. unsigned char *tosc_getNextMidi(tosc_message *o) {
  139. unsigned char *m = (unsigned char *) o->marker;
  140. o->marker += 4;
  141. return m;
  142. }
  143. void tosc_writeBundle(tosc_bundle *b, uint64_t timetag, char *buffer, const int len) {
  144. *((uint64_t *) buffer) = htonll(BUNDLE_ID);
  145. *((uint64_t *) (buffer + 8)) = htonll(timetag);
  146. b->buffer = buffer;
  147. b->marker = buffer + 16;
  148. b->bufLen = len;
  149. b->bundleLen = 16;
  150. }
  151. // always writes a multiple of 4 bytes
  152. static uint32_t tosc_vwrite(char *buffer, const int len,
  153. const char *address, const char *format, va_list ap) {
  154. memset(buffer, 0, len); // clear the buffer
  155. uint32_t i = (uint32_t) strlen(address);
  156. if (address == NULL || i >= len) return -1;
  157. tosc_strncpy(buffer, address, len);
  158. i = (i + 4) & ~0x3;
  159. buffer[i++] = ',';
  160. int s_len = (int) strlen(format);
  161. if (format == NULL || (i + s_len) >= len) return -2;
  162. tosc_strncpy(buffer+i, format, len-i-s_len);
  163. i = (i + 4 + s_len) & ~0x3;
  164. for (int j = 0; format[j] != '\0'; ++j) {
  165. switch (format[j]) {
  166. case 'b': {
  167. const uint32_t n = (uint32_t) va_arg(ap, int); // length of blob
  168. if (i + 4 + n > len) return -3;
  169. char *b = (char *) va_arg(ap, void *); // pointer to binary data
  170. *((uint32_t *) (buffer+i)) = htonl(n); i += 4;
  171. memcpy(buffer+i, b, n);
  172. i = (i + 3 + n) & ~0x3;
  173. break;
  174. }
  175. case 'f': {
  176. if (i + 4 > len) return -3;
  177. const float f = (float) va_arg(ap, double);
  178. *((uint32_t *) (buffer+i)) = htonl(*((uint32_t *) &f));
  179. i += 4;
  180. break;
  181. }
  182. case 'd': {
  183. if (i + 8 > len) return -3;
  184. const double f = (double) va_arg(ap, double);
  185. *((uint64_t *) (buffer+i)) = htonll(*((uint64_t *) &f));
  186. i += 8;
  187. break;
  188. }
  189. case 'i': {
  190. if (i + 4 > len) return -3;
  191. const uint32_t k = (uint32_t) va_arg(ap, int);
  192. *((uint32_t *) (buffer+i)) = htonl(k);
  193. i += 4;
  194. break;
  195. }
  196. case 'm': {
  197. if (i + 4 > len) return -3;
  198. const unsigned char *const k = (unsigned char *) va_arg(ap, void *);
  199. memcpy(buffer+i, k, 4);
  200. i += 4;
  201. break;
  202. }
  203. case 't':
  204. case 'h': {
  205. if (i + 8 > len) return -3;
  206. const uint64_t k = (uint64_t) va_arg(ap, long long);
  207. *((uint64_t *) (buffer+i)) = htonll(k);
  208. i += 8;
  209. break;
  210. }
  211. case 's': {
  212. const char *str = (const char *) va_arg(ap, void *);
  213. s_len = (int) strlen(str);
  214. if (i + s_len >= len) return -3;
  215. tosc_strncpy(buffer+i, str, len-i-s_len);
  216. i = (i + 4 + s_len) & ~0x3;
  217. break;
  218. }
  219. case 'T': // true
  220. case 'F': // false
  221. case 'N': // nil
  222. case 'I': // infinitum
  223. break;
  224. default: return -4; // unknown type
  225. }
  226. }
  227. return i; // return the total number of bytes written
  228. }
  229. uint32_t tosc_writeNextMessage(tosc_bundle *b,
  230. const char *address, const char *format, ...) {
  231. va_list ap;
  232. va_start(ap, format);
  233. if (b->bundleLen >= b->bufLen) return 0;
  234. const uint32_t i = tosc_vwrite(
  235. b->marker+4, b->bufLen-b->bundleLen-4, address, format, ap);
  236. va_end(ap);
  237. *((uint32_t *) b->marker) = htonl(i); // write the length of the message
  238. b->marker += (4 + i);
  239. b->bundleLen += (4 + i);
  240. return i;
  241. }
  242. uint32_t tosc_writeMessage(char *buffer, const int len,
  243. const char *address, const char *format, ...) {
  244. va_list ap;
  245. va_start(ap, format);
  246. const uint32_t i = tosc_vwrite(buffer, len, address, format, ap);
  247. va_end(ap);
  248. return i; // return the total number of bytes written
  249. }
  250. void tosc_printOscBuffer(char *buffer, const int len) {
  251. // parse the buffer contents (the raw OSC bytes)
  252. // a return value of 0 indicates no error
  253. tosc_message m;
  254. const int err = tosc_parseMessage(&m, buffer, len);
  255. if (err == 0) tosc_printMessage(&m);
  256. else printf("Error while reading OSC buffer: %i\n", err);
  257. }
  258. void tosc_printMessage(tosc_message *osc) {
  259. printf("[%i bytes] %s %s",
  260. osc->len, // the number of bytes in the OSC message
  261. tosc_getAddress(osc), // the OSC address string, e.g. "/button1"
  262. tosc_getFormat(osc)); // the OSC format string, e.g. "f"
  263. for (int i = 0; osc->format[i] != '\0'; i++) {
  264. switch (osc->format[i]) {
  265. case 'b': {
  266. const char *b = NULL; // will point to binary data
  267. int n = 0; // takes the length of the blob
  268. tosc_getNextBlob(osc, &b, &n);
  269. printf(" [%i]", n); // print length of blob
  270. for (int j = 0; j < n; ++j) printf("%02X", b[j] & 0xFF); // print blob bytes
  271. break;
  272. }
  273. case 'm': {
  274. unsigned char *m = tosc_getNextMidi(osc);
  275. printf(" 0x%02X%02X%02X%02X", m[0], m[1], m[2], m[3]);
  276. break;
  277. }
  278. case 'f': printf(" %g", tosc_getNextFloat(osc)); break;
  279. case 'd': printf(" %g", tosc_getNextDouble(osc)); break;
  280. case 'i': printf(" %d", tosc_getNextInt32(osc)); break;
  281. case 'h': printf(" %lld", tosc_getNextInt64(osc)); break;
  282. case 't': printf(" %lld", tosc_getNextTimetag(osc)); break;
  283. case 's': printf(" %s", tosc_getNextString(osc)); break;
  284. case 'F': printf(" false"); break;
  285. case 'I': printf(" inf"); break;
  286. case 'N': printf(" nil"); break;
  287. case 'T': printf(" true"); break;
  288. default: printf(" Unknown format: '%c'", osc->format[i]); break;
  289. }
  290. }
  291. printf("\n");
  292. }