| 
							- #include <stdint.h>
 - #include <stdio.h>
 - #include <string.h>
 - #include <stdarg.h>
 - #include <stdbool.h>
 - #include <ctype.h>
 - #include <assert.h>
 - 
 - #include <rtosc/rtosc.h>
 - 
 - const char *rtosc_argument_string(const char *msg)
 - {
 -     assert(msg && *msg);
 -     while(*++msg); //skip pattern
 -     while(!*++msg);//skip null
 -     return msg+1;  //skip comma
 - }
 - 
 - unsigned rtosc_narguments(const char *msg)
 - {
 -     const char *args = rtosc_argument_string(msg);
 -     int nargs = 0;
 -     while(*args++)
 -         nargs += (*args == ']' || *args == '[') ? 0 : 1;
 -     return nargs;
 - }
 - 
 - static int has_reserved(char type)
 - {
 -     switch(type)
 -     {
 -         case 'i'://official types
 -         case 's':
 -         case 'b':
 -         case 'f':
 - 
 -         case 'h'://unofficial
 -         case 't':
 -         case 'd':
 -         case 'S':
 -         case 'r':
 -         case 'm':
 -         case 'c':
 -             return 1;
 -         case 'T':
 -         case 'F':
 -         case 'N':
 -         case 'I':
 -         case '[':
 -         case ']':
 -             return 0;
 -     }
 - 
 -     //Should not happen
 -     return 0;
 - }
 - 
 - static unsigned nreserved(const char *args)
 - {
 -     unsigned res = 0;
 -     for(;*args;++args)
 -         res += has_reserved(*args);
 - 
 -     return res;
 - }
 - 
 - char rtosc_type(const char *msg, unsigned nargument)
 - {
 -     assert(nargument < rtosc_narguments(msg));
 -     const char *arg = rtosc_argument_string(msg);
 -     while(1) {
 -         if(*arg == '[' || *arg == ']')
 -             ++arg;
 -         else if(!nargument || !*arg)
 -             return *arg;
 -         else
 -             ++arg, --nargument;
 -     }
 - }
 - 
 - static unsigned arg_start(const char *msg_)
 - {
 -     const uint8_t *msg = (const uint8_t*)msg_;
 -     //Iterate to the right position
 -     const uint8_t *args = (const uint8_t*) rtosc_argument_string(msg_);
 -     const uint8_t *aligned_ptr = args-1;
 -     const uint8_t *arg_pos = args;
 - 
 -     while(*++arg_pos);
 -     //Alignment
 -     arg_pos += 4-(arg_pos-aligned_ptr)%4;
 -     return arg_pos-msg;
 - }
 - 
 - static unsigned arg_size(const uint8_t *arg_mem, char type)
 - {
 -     if(!has_reserved(type))
 -         return 0;
 -     const uint8_t  *arg_pos=arg_mem;
 -     uint32_t blob_length = 0;
 -     switch(type)
 -     {
 -         case 'h':
 -         case 't':
 -         case 'd':
 -             return 8;
 -         case 'm':
 -         case 'r':
 -         case 'f':
 -         case 'c':
 -         case 'i':
 -             return 4;
 -         case 'S':
 -         case 's':
 -             while(*++arg_pos);
 -             arg_pos += 4-(arg_pos-arg_mem)%4;
 -             return arg_pos-arg_mem;
 -         case 'b':
 -             blob_length |= (*arg_pos++ << 24);
 -             blob_length |= (*arg_pos++ << 16);
 -             blob_length |= (*arg_pos++ << 8);
 -             blob_length |= (*arg_pos++);
 -             if(blob_length%4)
 -                 blob_length += 4-blob_length%4;
 -             arg_pos += blob_length;
 -             return arg_pos-arg_mem;
 -         default:
 -             assert("Invalid Type");
 -     }
 -     return -1;
 - }
 - 
 - static unsigned arg_off(const char *msg, unsigned idx)
 - {
 -     if(!has_reserved(rtosc_type(msg,idx)))
 -         return 0;
 - 
 -     //Iterate to the right position
 -     const uint8_t *args = (const uint8_t*) rtosc_argument_string(msg);
 -     const uint8_t *aligned_ptr = args-1;
 -     const uint8_t *arg_pos = args;
 - 
 -     while(*++arg_pos);
 -     //Alignment
 -     arg_pos += 4-(arg_pos-((uint8_t*)aligned_ptr))%4;
 - 
 -     //ignore any leading '[' or ']'
 -     while(*args == '[' || *args == ']')
 -         ++args;
 - 
 -     while(idx--) {
 -         char type = *args++;
 -         if(type == '[' || type == ']')
 -             idx++;//not a valid arg idx
 -         else
 -             arg_pos += arg_size(arg_pos, type);
 -     }
 -     return arg_pos-(uint8_t*)msg;
 - }
 - 
 - size_t rtosc_message(char   *buffer,
 -                      size_t      len,
 -                      const char *address,
 -                      const char *arguments,
 -                      ...)
 - {
 -     va_list va;
 -     va_start(va, arguments);
 -     size_t result = rtosc_vmessage(buffer, len, address, arguments, va);
 -     va_end(va);
 -     return result;
 - }
 - 
 - //Calculate the size of the message without writing to a buffer
 - static size_t vsosc_null(const char        *address,
 -                          const char        *arguments,
 -                          const rtosc_arg_t *args)
 - {
 -     unsigned pos = 0;
 -     pos += strlen(address);
 -     pos += 4-pos%4;//get 32 bit alignment
 -     pos += 1+strlen(arguments);
 -     pos += 4-pos%4;
 - 
 -     unsigned toparse = nreserved(arguments);
 -     unsigned arg_pos = 0;
 - 
 -     //Take care of varargs
 -     while(toparse)
 -     {
 -         char arg = *arguments++;
 -         assert(arg);
 -         int i;
 -         const char *s;
 -         switch(arg) {
 -             case 'h':
 -             case 't':
 -             case 'd':
 -                 ++arg_pos;
 -                 pos += 8;
 -                 --toparse;
 -                 break;
 -             case 'm':
 -             case 'r':
 -             case 'c':
 -             case 'f':
 -             case 'i':
 -                 ++arg_pos;
 -                 pos += 4;
 -                 --toparse;
 -                 break;
 -             case 's':
 -             case 'S':
 -                 s = args[arg_pos++].s;
 -                 assert(s && "Input strings CANNOT be NULL");
 -                 pos += strlen(s);
 -                 pos += 4-pos%4;
 -                 --toparse;
 -                 break;
 -             case 'b':
 -                 i = args[arg_pos++].b.len;
 -                 pos += 4 + i;
 -                 if(pos%4)
 -                     pos += 4-pos%4;
 -                 --toparse;
 -                 break;
 -             default:
 -                 ;
 -         }
 -     }
 - 
 -     return pos;
 - }
 - size_t rtosc_vmessage(char   *buffer,
 -                       size_t      len,
 -                       const char *address,
 -                       const char *arguments,
 -                       va_list ap)
 - {
 -     const unsigned nargs = nreserved(arguments);
 -     if(!nargs)
 -         return rtosc_amessage(buffer,len,address,arguments,NULL);
 - 
 -     rtosc_arg_t args[nargs];
 - 
 -     unsigned arg_pos = 0;
 -     const char *arg_str = arguments;
 -     uint8_t *midi_tmp;
 -     while(arg_pos < nargs)
 -     {
 -         switch(*arg_str++) {
 -             case 'h':
 -             case 't':
 -                 args[arg_pos++].h = va_arg(ap, int64_t);
 -                 break;
 -             case 'd':
 -                 args[arg_pos++].d = va_arg(ap, double);
 -                 break;
 -             case 'c':
 -             case 'i':
 -             case 'r':
 -                 args[arg_pos++].i = va_arg(ap, int);
 -                 break;
 -             case 'm':
 -                 midi_tmp = va_arg(ap, uint8_t *);
 -                 args[arg_pos].m[0] = midi_tmp[0];
 -                 args[arg_pos].m[1] = midi_tmp[1];
 -                 args[arg_pos].m[2] = midi_tmp[2];
 -                 args[arg_pos++].m[3] = midi_tmp[3];
 -                 break;
 -             case 'S':
 -             case 's':
 -                 args[arg_pos++].s = va_arg(ap, const char *);
 -                 break;
 -             case 'b':
 -                 args[arg_pos].b.len = va_arg(ap, int);
 -                 args[arg_pos].b.data = va_arg(ap, unsigned char *);
 -                 arg_pos++;
 -                 break;
 -             case 'f':
 -                 args[arg_pos++].f = va_arg(ap, double);
 -                 break;
 -             default:
 -                 ;
 -         }
 -     }
 - 
 -     return rtosc_amessage(buffer,len,address,arguments,args);
 - }
 - 
 - size_t rtosc_amessage(char              *buffer,
 -                       size_t             len,
 -                       const char        *address,
 -                       const char        *arguments,
 -                       const rtosc_arg_t *args)
 - {
 -     const size_t total_len = vsosc_null(address, arguments, args);
 - 
 -     if(!buffer)
 -         return total_len;
 - 
 -     //Abort if the message cannot fit
 -     if(total_len>len) {
 -         memset(buffer, 0, len);
 -         return 0;
 -     }
 - 
 -     memset(buffer, 0, total_len);
 - 
 -     unsigned pos = 0;
 -     while(*address)
 -         buffer[pos++] = *address++;
 - 
 -     //get 32 bit alignment
 -     pos += 4-pos%4;
 - 
 -     buffer[pos++] = ',';
 - 
 -     const char *arg_str = arguments;
 -     while(*arg_str)
 -         buffer[pos++] = *arg_str++;
 - 
 -     pos += 4-pos%4;
 - 
 -     unsigned toparse = nreserved(arguments);
 -     unsigned arg_pos = 0;
 -     while(toparse)
 -     {
 -         char arg = *arguments++;
 -         assert(arg);
 -         int32_t i;
 -         int64_t d;
 -         const uint8_t *m;
 -         const char *s;
 -         const unsigned char *u;
 -         rtosc_blob_t b;
 -         switch(arg) {
 -             case 'h':
 -             case 't':
 -             case 'd':
 -                 d = args[arg_pos++].t;
 -                 buffer[pos++] = ((d>>56) & 0xff);
 -                 buffer[pos++] = ((d>>48) & 0xff);
 -                 buffer[pos++] = ((d>>40) & 0xff);
 -                 buffer[pos++] = ((d>>32) & 0xff);
 -                 buffer[pos++] = ((d>>24) & 0xff);
 -                 buffer[pos++] = ((d>>16) & 0xff);
 -                 buffer[pos++] = ((d>>8) & 0xff);
 -                 buffer[pos++] = (d & 0xff);
 -                 --toparse;
 -                 break;
 -             case 'r':
 -             case 'f':
 -             case 'c':
 -             case 'i':
 -                 i = args[arg_pos++].i;
 -                 buffer[pos++] = ((i>>24) & 0xff);
 -                 buffer[pos++] = ((i>>16) & 0xff);
 -                 buffer[pos++] = ((i>>8) & 0xff);
 -                 buffer[pos++] = (i & 0xff);
 -                 --toparse;
 -                 break;
 -             case 'm':
 -                 //TODO verify ordering of spec
 -                 m = args[arg_pos++].m;
 -                 buffer[pos++] = m[0];
 -                 buffer[pos++] = m[1];
 -                 buffer[pos++] = m[2];
 -                 buffer[pos++] = m[3];
 -                 --toparse;
 -                 break;
 -             case 'S':
 -             case 's':
 -                 s = args[arg_pos++].s;
 -                 while(*s)
 -                     buffer[pos++] = *s++;
 -                 pos += 4-pos%4;
 -                 --toparse;
 -                 break;
 -             case 'b':
 -                 b = args[arg_pos++].b;
 -                 i = b.len;
 -                 buffer[pos++] = ((i>>24) & 0xff);
 -                 buffer[pos++] = ((i>>16) & 0xff);
 -                 buffer[pos++] = ((i>>8) & 0xff);
 -                 buffer[pos++] = (i & 0xff);
 -                 u = b.data;
 -                 if(u) {
 -                     while(i--)
 -                         buffer[pos++] = *u++;
 -                 }
 -                 else
 -                     pos += i;
 -                 if(pos%4)
 -                     pos += 4-pos%4;
 -                 --toparse;
 -                 break;
 -             default:
 -                 ;
 -         }
 -     }
 - 
 -     return pos;
 - }
 - 
 - static rtosc_arg_t extract_arg(const uint8_t *arg_pos, char type)
 - {
 -     rtosc_arg_t result = {0};
 -     //trivial case
 -     if(!has_reserved(type)) {
 -         switch(type)
 -         {
 -             case 'T':
 -                 result.T = true;
 -                 break;
 -             case 'F':
 -                 result.T = false;
 -                 break;
 -             default:
 -                 ;
 -         }
 -     } else {
 -         switch(type)
 -         {
 -             case 'h':
 -             case 't':
 -             case 'd':
 -                 result.t |= (((uint64_t)*arg_pos++) << 56);
 -                 result.t |= (((uint64_t)*arg_pos++) << 48);
 -                 result.t |= (((uint64_t)*arg_pos++) << 40);
 -                 result.t |= (((uint64_t)*arg_pos++) << 32);
 -                 result.t |= (((uint64_t)*arg_pos++) << 24);
 -                 result.t |= (((uint64_t)*arg_pos++) << 16);
 -                 result.t |= (((uint64_t)*arg_pos++) << 8);
 -                 result.t |= (((uint64_t)*arg_pos++));
 -                 break;
 -             case 'r':
 -             case 'f':
 -             case 'c':
 -             case 'i':
 -                 result.i |= (*arg_pos++ << 24);
 -                 result.i |= (*arg_pos++ << 16);
 -                 result.i |= (*arg_pos++ << 8);
 -                 result.i |= (*arg_pos++);
 -                 break;
 -             case 'm':
 -                 result.m[0] = *arg_pos++;
 -                 result.m[1] = *arg_pos++;
 -                 result.m[2] = *arg_pos++;
 -                 result.m[3] = *arg_pos++;
 -                 break;
 -             case 'b':
 -                 result.b.len |= (*arg_pos++ << 24);
 -                 result.b.len |= (*arg_pos++ << 16);
 -                 result.b.len |= (*arg_pos++ << 8);
 -                 result.b.len |= (*arg_pos++);
 -                 result.b.data = (unsigned char *)arg_pos;
 -                 break;
 -             case 'S':
 -             case 's':
 -                 result.s = (char *)arg_pos;
 -                 break;
 -         }
 -     }
 - 
 -     return result;
 - }
 - 
 - static const char *advance_past_dummy_args(const char *args)
 - {
 -     while(*args == '[' || *args == ']')
 -         args++;
 -     return args;
 - }
 - 
 - rtosc_arg_itr_t rtosc_itr_begin(const char *msg)
 - {
 -     rtosc_arg_itr_t itr;
 -     itr.type_pos  = advance_past_dummy_args(rtosc_argument_string(msg));
 -     itr.value_pos = (uint8_t*)(msg+arg_start(msg));
 - 
 -     return itr;
 - }
 - 
 - rtosc_arg_val_t rtosc_itr_next(rtosc_arg_itr_t *itr)
 - {
 -     //current position provides the value
 -     rtosc_arg_val_t result = {0,{0}};
 -     result.type = *itr->type_pos;
 -     if(result.type)
 -         result.val = extract_arg(itr->value_pos, result.type);
 - 
 -     //advance
 -     itr->type_pos = advance_past_dummy_args(itr->type_pos+1);
 -     char type = result.type;
 -     int size  = arg_size(itr->value_pos, type);
 -     itr->value_pos += size;
 - 
 - 
 -     return result;
 - }
 - 
 - int rtosc_itr_end(rtosc_arg_itr_t itr)
 - {
 -     return !itr.type_pos  || !*itr.type_pos;
 - }
 - 
 - rtosc_arg_t rtosc_argument(const char *msg, unsigned idx)
 - {
 -     char type = rtosc_type(msg, idx);
 -     uint8_t *arg_mem = (uint8_t*)msg + arg_off(msg, idx);
 -     return extract_arg(arg_mem, type);
 - }
 - 
 - static unsigned char deref(unsigned pos, ring_t *ring)
 - {
 -     return pos<ring[0].len ? ring[0].data[pos] :
 -         ((pos-ring[0].len)<ring[1].len ? ring[1].data[pos-ring[0].len] : 0x00);
 - }
 - 
 - static size_t bundle_ring_length(ring_t *ring)
 - {
 -     unsigned pos = 8+8;//goto first length field
 -     uint32_t advance = 0;
 -     do {
 -         advance = deref(pos+0, ring) << (8*3) |
 -                   deref(pos+1, ring) << (8*2) |
 -                   deref(pos+2, ring) << (8*1) |
 -                   deref(pos+3, ring) << (8*0);
 -         if(advance)
 -             pos += 4+advance;
 -     } while(advance);
 - 
 -     return pos <= (ring[0].len+ring[1].len) ? pos : 0;
 - }
 - 
 - //Zero means no full message present
 - size_t rtosc_message_ring_length(ring_t *ring)
 - {
 -     //Check if the message is a bundle
 -     if(deref(0,ring) == '#' &&
 -             deref(1,ring) == 'b' &&
 -             deref(2,ring) == 'u' &&
 -             deref(3,ring) == 'n' &&
 -             deref(4,ring) == 'd' &&
 -             deref(5,ring) == 'l' &&
 -             deref(6,ring) == 'e' &&
 -             deref(7,ring) == '\0')
 -         return bundle_ring_length(ring);
 - 
 -     //Proceed for normal messages
 -     //Consume path
 -     unsigned pos = 0;
 -     while(deref(pos++,ring));
 -     pos--;
 - 
 -     //Travel through the null word end [1..4] bytes
 -     for(int i=0; i<4; ++i)
 -         if(deref(++pos, ring))
 -             break;
 - 
 -     if(deref(pos, ring) != ',')
 -         return 0;
 - 
 -     unsigned aligned_pos = pos;
 -     int arguments = pos+1;
 -     while(deref(++pos,ring));
 -     pos += 4-(pos-aligned_pos)%4;
 - 
 -     unsigned toparse = 0;
 -     {
 -         int arg = arguments-1;
 -         while(deref(++arg,ring))
 -             toparse += has_reserved(deref(arg,ring));
 -     }
 - 
 -     //Take care of varargs
 -     while(toparse)
 -     {
 -         char arg = deref(arguments++,ring);
 -         assert(arg);
 -         uint32_t i;
 -         switch(arg) {
 -             case 'h':
 -             case 't':
 -             case 'd':
 -                 pos += 8;
 -                 --toparse;
 -                 break;
 -             case 'm':
 -             case 'r':
 -             case 'c':
 -             case 'f':
 -             case 'i':
 -                 pos += 4;
 -                 --toparse;
 -                 break;
 -             case 'S':
 -             case 's':
 -                 while(deref(++pos,ring));
 -                 pos += 4-(pos-aligned_pos)%4;
 -                 --toparse;
 -                 break;
 -             case 'b':
 -                 i = 0;
 -                 i |= (deref(pos++,ring) << 24);
 -                 i |= (deref(pos++,ring) << 16);
 -                 i |= (deref(pos++,ring) << 8);
 -                 i |= (deref(pos++,ring));
 -                 pos += i;
 -                 if((pos-aligned_pos)%4)
 -                     pos += 4-(pos-aligned_pos)%4;
 -                 --toparse;
 -                 break;
 -             default:
 -                 ;
 -         }
 -     }
 - 
 - 
 -     return pos <= (ring[0].len+ring[1].len) ? pos : 0;
 - }
 - 
 - size_t rtosc_message_length(const char *msg, size_t len)
 - {
 -     ring_t ring[2] = {{(char*)msg,len},{NULL,0}};
 -     return rtosc_message_ring_length(ring);
 - }
 - 
 - bool rtosc_valid_message_p(const char *msg, size_t len)
 - {
 -     //Validate Path Characters (assumes printable characters are sufficient)
 -     if(*msg != '/')
 -         return false;
 -     const char *tmp = msg;
 -     for(unsigned i=0; i<len; ++i) {
 -         if(*tmp == 0)
 -             break;
 -         if(!isprint(*tmp))
 -             return false;
 -         tmp++;
 -     }
 - 
 -     //tmp is now either pointing to a null or the end of the string
 -     const size_t offset1 = tmp-msg;
 -     size_t       offset2 = tmp-msg;
 -     for(; offset2<len; offset2++) {
 -         if(*tmp == ',')
 -             break;
 -         tmp++;
 -     }
 - 
 -     //Too many NULL bytes
 -     if(offset2-offset1 > 4)
 -         return false;
 - 
 -     if((offset2 % 4) != 0)
 -         return false;
 - 
 -     size_t observed_length = rtosc_message_length(msg, len);
 -     return observed_length == len;
 - }
 - static uint64_t extract_uint64(const uint8_t *arg_pos)
 - {
 -     uint64_t arg = 0;
 -     arg |= (((uint64_t)*arg_pos++) << 56);
 -     arg |= (((uint64_t)*arg_pos++) << 48);
 -     arg |= (((uint64_t)*arg_pos++) << 40);
 -     arg |= (((uint64_t)*arg_pos++) << 32);
 -     arg |= (((uint64_t)*arg_pos++) << 24);
 -     arg |= (((uint64_t)*arg_pos++) << 16);
 -     arg |= (((uint64_t)*arg_pos++) << 8);
 -     arg |= (((uint64_t)*arg_pos++));
 -     return arg;
 - }
 - 
 - static uint32_t extract_uint32(const uint8_t *arg_pos)
 - {
 -     uint32_t arg = 0;
 -     arg |= (((uint32_t)*arg_pos++) << 24);
 -     arg |= (((uint32_t)*arg_pos++) << 16);
 -     arg |= (((uint32_t)*arg_pos++) << 8);
 -     arg |= (((uint32_t)*arg_pos++));
 -     return arg;
 - }
 - 
 - static void emplace_uint64(uint8_t *buffer, uint64_t d)
 - {
 -     buffer[0] = ((d>>56) & 0xff);
 -     buffer[1] = ((d>>48) & 0xff);
 -     buffer[2] = ((d>>40) & 0xff);
 -     buffer[3] = ((d>>32) & 0xff);
 -     buffer[4] = ((d>>24) & 0xff);
 -     buffer[5] = ((d>>16) & 0xff);
 -     buffer[6] = ((d>>8)  & 0xff);
 -     buffer[7] = ((d>>0)  & 0xff);
 - }
 - 
 - static void emplace_uint32(uint8_t *buffer, uint32_t d)
 - {
 -     buffer[0] = ((d>>24) & 0xff);
 -     buffer[1] = ((d>>16) & 0xff);
 -     buffer[2] = ((d>>8)  & 0xff);
 -     buffer[3] = ((d>>0)  & 0xff);
 - }
 - 
 - size_t rtosc_bundle(char *buffer, size_t len, uint64_t tt, int elms, ...)
 - {
 -     char *_buffer = buffer;
 -     memset(buffer, 0, len);
 -     strcpy(buffer, "#bundle");
 -     buffer += 8;
 -     emplace_uint64((uint8_t*)buffer, tt);
 -     buffer += 8;
 -     va_list va;
 -     va_start(va, elms);
 -     for(int i=0; i<elms; ++i) {
 -         const char   *msg  = va_arg(va, const char*);
 -         //It is assumed that any passed message/bundle is valid
 -         size_t        size = rtosc_message_length(msg, -1);
 -         emplace_uint32((uint8_t*)buffer, size);
 -         buffer += 4;
 -         memcpy(buffer, msg, size);
 -         buffer+=size;
 -     }
 -     va_end(va);
 - 
 -     return buffer-_buffer;
 - }
 - 
 - 
 - #define POS ((size_t)(((const char *)lengths) - buffer))
 - size_t rtosc_bundle_elements(const char *buffer, size_t len)
 - {
 -     const uint32_t *lengths = (const uint32_t*) (buffer+16);
 -     size_t elms = 0;
 -     while(POS < len && extract_uint32((const uint8_t*)lengths)) {
 -         lengths += extract_uint32((const uint8_t*)lengths)/4+1;
 - 
 -         if(POS > len)
 -             break;
 -         ++elms;
 -     }
 -     return elms;
 - }
 - #undef POS
 - 
 - const char *rtosc_bundle_fetch(const char *buffer, unsigned elm)
 - {
 -     const uint32_t *lengths = (const uint32_t*) (buffer+16);
 -     size_t elm_pos = 0;
 -     while(elm_pos!=elm && extract_uint32((const uint8_t*)lengths)) {
 -         ++elm_pos;
 -         lengths += extract_uint32((const uint8_t*)lengths)/4+1;
 -     }
 - 
 -     return (const char*) (elm==elm_pos?lengths+1:NULL);
 - }
 - 
 - size_t rtosc_bundle_size(const char *buffer, unsigned elm)
 - {
 -     const uint32_t *lengths = (const uint32_t*) (buffer+16);
 -     size_t elm_pos = 0;
 -     size_t last_len = 0;
 -     while(elm_pos!=elm && extract_uint32((const uint8_t*)lengths)) {
 -         last_len = extract_uint32((const uint8_t*)lengths);
 -         ++elm_pos, lengths+=extract_uint32((const uint8_t*)lengths)/4+1;
 -     }
 - 
 -     return last_len;
 - }
 - 
 - int rtosc_bundle_p(const char *msg)
 - {
 -     return !strcmp(msg,"#bundle");
 - }
 - 
 - uint64_t rtosc_bundle_timetag(const char *msg)
 - {
 -     return extract_uint64((const uint8_t*)msg+8);
 - }
 
 
  |