Subversion Repositories svn.mios32

Rev

Rev 1004 | Rev 1006 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1003 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: OscHelper.cpp 1005 2010-04-22 22:16:49Z tk $
3
/*
4
 * OSC Help Routines
5
 * (taken from MIOS32_OSC)
6
 * Documentation: see there
7
 *
8
 * ==========================================================================
9
 *
10
 *  Copyright (C) 2010 Thorsten Klose (tk@midibox.org)
11
 *  Licensed for personal non-commercial use only.
12
 *  All other rights reserved.
13
 *
14
 * ==========================================================================
15
 */
16
 
17
#include "OscHelper.h"
18
#include <string.h>
19
 
1004 philetaylo 20
 
1003 tk 21
//==============================================================================
22
OscHelper::OscHelper()
23
{
24
}
25
 
26
OscHelper::~OscHelper()
27
{
28
}
29
 
30
 
31
//==============================================================================
32
// strnlen() not available for all libc's, therefore we use a local solution here
33
static size_t my_strnlen(char *str, size_t max_len)
34
{
35
  size_t len = 0;
36
 
37
  while( *str++ && (len < max_len) )
38
    ++len;
39
 
40
  return len;
41
}
42
 
43
//==============================================================================
1004 philetaylo 44
// stpcpy is not available in windows, therefore we use a local solution here
45
#ifdef WIN32
46
static char *stpcpy(char *dest, const char *src){strcpy(dest,src);return dest +strlen(dest);}
47
#endif
48
 
49
//==============================================================================
1003 tk 50
/////////////////////////////////////////////////////////////////////////////
51
// Gets a word (4 bytes) from buffer
52
// \param[in] buffer pointer to OSC message buffer 
53
// \return 32bit unsigned integer
54
/////////////////////////////////////////////////////////////////////////////
55
unsigned OscHelper::getWord(unsigned char *buffer)
56
{
57
  // taking endianess into account
58
  return
59
    (((unsigned)*(buffer+0)) << 24) | (((unsigned)*(buffer+1)) << 16) |
60
    (((unsigned)*(buffer+2)) <<  8) | (((unsigned)*(buffer+3)) <<  0);
61
}
62
 
63
/////////////////////////////////////////////////////////////////////////////
64
// Puts a word (4 bytes) into buffer
65
// \param[in] buffer pointer to OSC message buffer 
66
// \param[in] word 32bit word
67
// \return buffer pointer behind the inserted entry
68
/////////////////////////////////////////////////////////////////////////////
69
unsigned char *OscHelper::putWord(unsigned char *buffer, unsigned word)
70
{
71
  *buffer++ = (word >> 24) & 0xff;
72
  *buffer++ = (word >> 16) & 0xff;
73
  *buffer++ = (word >>  8) & 0xff;
74
  *buffer++ = (word >>  0) & 0xff;
75
  return buffer;
76
}
77
 
78
/////////////////////////////////////////////////////////////////////////////
79
// Gets a timetag (8 bytes) from buffer
80
// \param[in] buffer pointer to OSC message buffer 
81
// \return timetag (seconds and fraction part)
82
/////////////////////////////////////////////////////////////////////////////
83
OscHelper::OscTimetagT OscHelper::getTimetag(unsigned char *buffer)
84
{
85
  OscTimetagT timetag;
86
  timetag.seconds = getWord(buffer);
87
  timetag.fraction = getWord(buffer+4);
88
  return timetag;
89
}
90
 
91
/////////////////////////////////////////////////////////////////////////////
92
// Puts a timetag (8 bytes) into buffer
93
// \param[in] buffer pointer to OSC message buffer 
94
// \param[in] timetag the timetag which should be inserted
95
// \return buffer pointer behind the inserted entry
96
/////////////////////////////////////////////////////////////////////////////
97
unsigned char *OscHelper::putTimetag(unsigned char *buffer, OscTimetagT timetag)
98
{
99
  buffer = putWord(buffer, timetag.seconds);
100
  buffer = putWord(buffer, timetag.fraction);
101
  return buffer;
102
}
103
 
104
/////////////////////////////////////////////////////////////////////////////
105
// Gets a word (4 bytes) from buffer and converts it to a 32bit signed integer.
106
// \param[in] buffer pointer to OSC message buffer 
107
// \return 32bit signed integer
108
/////////////////////////////////////////////////////////////////////////////
109
int OscHelper::getInt(unsigned char *buffer)
110
{
111
  return (int)getWord(buffer);
112
}
113
 
114
/////////////////////////////////////////////////////////////////////////////
115
// Puts a 32bit signed integer into buffer
116
// \param[in] buffer pointer to OSC message buffer 
117
// \param[in] value the integer value which should be inserted
118
// \return buffer pointer behind the inserted entry
119
/////////////////////////////////////////////////////////////////////////////
120
unsigned char *OscHelper::putInt(unsigned char *buffer, int value)
121
{
122
  return putWord(buffer, (unsigned)value);
123
}
124
 
125
/////////////////////////////////////////////////////////////////////////////
126
// Gets a word (4 bytes) from buffer and converts it to a float with 
127
// normal precession
128
// \param[in] buffer pointer to OSC message buffer 
129
// \return float with normal procession
130
/////////////////////////////////////////////////////////////////////////////
131
float OscHelper::getFloat(unsigned char *buffer)
132
{
133
#if 0
134
  unsigned word = getWord(buffer);
135
  return *(float *)(&word);
136
#else
137
  // TK: doesn't work with my gcc installation (i686-apple-darwin9-gcc-4.0.1):
138
  // float not converted correctly - it works when optimisation is disabled!
139
  // according to http://gcc.gnu.org/ml/gcc-bugs/2003-02/msg01128.html this isn't a bug...
140
  // workaround:
141
  union { unsigned word; float f; } converted;
142
  converted.word = getWord(buffer);
143
  return converted.f;
144
#endif
145
}
146
 
147
 
148
/////////////////////////////////////////////////////////////////////////////
149
// Puts a float with normal precission into buffer
150
// \param[in] buffer pointer to OSC message buffer 
151
// \param[in] value the float value which should be inserted
152
// \return buffer pointer behind the inserted entry
153
/////////////////////////////////////////////////////////////////////////////
154
unsigned char *OscHelper::putFloat(unsigned char *buffer, float value)
155
{
156
  union { unsigned word; float f; } converted;
157
  converted.f = value;
158
  return putWord(buffer, converted.word);
159
}
160
 
161
/////////////////////////////////////////////////////////////////////////////
162
// Returns pointer to a string in message buffer
163
// \param[in] buffer pointer to OSC message buffer 
164
// \return zero-terminated string
165
/////////////////////////////////////////////////////////////////////////////
166
char *OscHelper::getString(unsigned char *buffer)
167
{
168
  return (char *)buffer; // OSC protocol ensures zero termination (checked in MIOS32_OSC_SearchElement)
169
}
170
 
171
/////////////////////////////////////////////////////////////////////////////
172
// Puts a string into buffer and pads with 0 until word boundary has been reached
173
// \param[in] buffer pointer to OSC message buffer 
174
// \param[in] value the string which should be inserted
175
// \return buffer pointer behind the inserted entry
176
/////////////////////////////////////////////////////////////////////////////
177
unsigned char *OscHelper::putString(unsigned char *buffer, char *str)
178
{
179
  unsigned char *buffer_start = buffer;
180
 
181
  buffer = (unsigned char *)stpcpy((char *)buffer, str);
182
  *buffer++ = 0;
183
 
184
  // pad with zeroes until word boundary is reached
185
  while( (unsigned)(buffer-buffer_start) % 4 )
186
    *buffer++ = 0;
187
 
188
  return buffer;
189
}
190
 
191
/////////////////////////////////////////////////////////////////////////////
192
// Returns the length of a Blob
193
// \param[in] buffer pointer to OSC message buffer 
194
// \return blob length
195
/////////////////////////////////////////////////////////////////////////////
196
unsigned OscHelper::getBlobLength(unsigned char *buffer)
197
{
198
  return *buffer;
199
}
200
 
201
/////////////////////////////////////////////////////////////////////////////
202
// Returns the data part of a Blob
203
// \param[in] buffer pointer to OSC message buffer 
204
// \return pointer to data part of a Blob
205
/////////////////////////////////////////////////////////////////////////////
206
unsigned char *OscHelper::getBlobData(unsigned char *buffer)
207
{
208
  return buffer+4;
209
}
210
 
211
 
212
/////////////////////////////////////////////////////////////////////////////
213
// Puts an OSC-Blob into buffer and pads with 0 until word boundary has been reached
214
// \param[in] buffer pointer to OSC message buffer 
215
// \param[in] data blob data
216
// \param[in] len blob size
217
// \return buffer pointer behind the inserted entry
218
/////////////////////////////////////////////////////////////////////////////
219
unsigned char *OscHelper::putBlob(unsigned char *buffer, unsigned char *data, unsigned len)
220
{
221
  // ensure that length considers word alignment
222
  unsigned aligned_len = (len+3) & 0xfffffffc;
223
 
224
  // add length
225
  buffer = putWord(buffer, aligned_len);
226
 
227
  // add bytes
228
  int i;
229
  for(i=0; i<len; ++i)
230
    *buffer++ = *data++;
231
 
232
  // pad with zeroes
233
  while( i % 4 )
234
    *buffer++ = 0;
235
 
236
  return buffer;
237
}
238
 
239
 
240
/////////////////////////////////////////////////////////////////////////////
241
// Gets two words (8 bytes) from buffer and converts them to a 64bit signed integer.
242
// \param[in] buffer pointer to OSC message buffer 
243
// \return 64bit signed integer
244
/////////////////////////////////////////////////////////////////////////////
245
long long OscHelper::getLongLong(unsigned char *buffer)
246
{
247
  return ((long long)getWord(buffer) << 32) | getWord(buffer+4);
248
}
249
 
250
/////////////////////////////////////////////////////////////////////////////
251
// Puts a 64bit signed integer into buffer
252
// \param[in] buffer pointer to OSC message buffer 
253
// \param[in] value the "long long" value which should be inserted
254
// \return buffer pointer behind the inserted entry
255
/////////////////////////////////////////////////////////////////////////////
256
unsigned char *OscHelper::putLongLong(unsigned char *buffer, long long value)
257
{
258
  buffer = putWord(buffer, (unsigned)(value >> 32));
259
  buffer = putWord(buffer, (unsigned)value);
260
  return buffer;
261
}
262
 
263
 
264
/////////////////////////////////////////////////////////////////////////////
265
// Gets two words (8 bytes) from buffer and converts them to a float with 
266
// double precession
267
// \param[in] buffer pointer to OSC message buffer 
268
// \return float with double procession
269
/////////////////////////////////////////////////////////////////////////////
270
double OscHelper::getDouble(unsigned char *buffer)
271
{
272
#if 0
273
  long long word = ((long long)getWord(buffer) << 32) | getWord(buffer+4);
274
  return *(double *)(&word);
275
#else
276
  // TK: doesn't work with my gcc installation (i686-apple-darwin9-gcc-4.0.1):
277
  // float not converted correctly - it works when optimisation is disabled!
278
  // according to http://gcc.gnu.org/ml/gcc-bugs/2003-02/msg01128.html this isn't a bug...
279
  // workaround:
280
  union { long long word; double d; } converted;
281
  converted.word = getLongLong(buffer);
282
  return converted.d;
283
#endif
284
}
285
 
286
/////////////////////////////////////////////////////////////////////////////
287
// Puts a float with double precission into buffer
288
// \param[in] buffer pointer to OSC message buffer 
289
// \param[in] value the double value which should be inserted
290
// \return buffer pointer behind the inserted entry
291
/////////////////////////////////////////////////////////////////////////////
292
unsigned char *OscHelper::putDouble(unsigned char *buffer, double value)
293
{
294
  union { long long word; double d; } converted;
295
  converted.d = value;
296
  return putLongLong(buffer, converted.word);
297
}
298
 
299
 
300
/////////////////////////////////////////////////////////////////////////////
301
// Returns a character
302
// \param[in] buffer pointer to OSC message buffer 
303
// \return a single character
304
/////////////////////////////////////////////////////////////////////////////
305
char OscHelper::getChar(unsigned char *buffer)
306
{
307
  return *buffer; // just for completeness..
308
}
309
 
310
/////////////////////////////////////////////////////////////////////////////
311
// Puts a character into buffer and pads with 3 zeros (word aligned)
312
// \param[in] buffer pointer to OSC message buffer 
313
// \param[in] c the character which should be inserted
314
// \return buffer pointer behind the inserted entry
315
/////////////////////////////////////////////////////////////////////////////
316
unsigned char *OscHelper::putChar(unsigned char *buffer, char c)
317
{
318
  return putWord(buffer, (unsigned)c);
319
}
320
 
321
 
322
 
323
/////////////////////////////////////////////////////////////////////////////
324
// Returns a MIDI package
325
// \param[in] buffer pointer to OSC message buffer 
326
// \return a MIOS32 compliant MIDI package
327
/////////////////////////////////////////////////////////////////////////////
328
unsigned OscHelper::getMIDI(unsigned char *buffer)
329
{
330
    // note: no extra conversion to MIOS32 MIDI package format
331
    return getWord(buffer);
332
}
333
 
334
/////////////////////////////////////////////////////////////////////////////
335
// Puts a MIDI package into buffer
336
// \param[in] buffer pointer to OSC message buffer 
337
// \param[in] p the MIDI package which should be inserted
338
// \return buffer pointer behind the inserted entry
339
/////////////////////////////////////////////////////////////////////////////
340
unsigned char *OscHelper::putMIDI(unsigned char *buffer, unsigned p)
341
{
342
    // note: no extra conversion to MIOS32 MIDI package format
343
    return putWord(buffer, p);
344
}
1005 tk 345
 
346
 
347
/////////////////////////////////////////////////////////////////////////////
348
// Parses an incoming OSC packet and calls OSC methods defined in searchTree
349
// on matching addresses
350
// \param[in] packet pointer to OSC packet
351
// \param[in] len length of packet
352
// \param[in] searchTree a tree which defines address parts and methods to be called
353
// \return 0 if packet has been parsed w/o errors
354
// \return -1 if packet format invalid
355
// \return -2 if the packet contains an OSC element with invalid format
356
// \return -3 if the packet contains an OSC element with an unsupported format
357
// returns -4 if MIOS32_OSC_MAX_PATH_PARTS has been exceeded
358
/////////////////////////////////////////////////////////////////////////////
359
int OscHelper::parsePacket(unsigned char *packet, const unsigned& len, OscHelper::OscSearchTreeT *searchTree)
360
{
361
    // store osc arguments (and more...) into oscArgs variable
362
    OscArgsT oscArgs;
363
 
364
    // check if we got a bundle
365
    if( strncmp((char *)packet, "#bundle", len) == 0 ) {
366
        unsigned pos = 8;
367
 
368
        // we expect at least 8 bytes for the timetag
369
        if( (pos+8) > len )
370
            return -1; // invalid format
371
 
372
 
373
        // get timetag
374
        oscArgs.timetag = getTimetag((unsigned char *)packet+pos);
375
        pos += 8;
376
 
377
        // parse elements
378
        while( (pos+4) <= len ) {
379
            // get element size
380
            unsigned elem_size = getWord((unsigned char *)(packet+pos));
381
            pos += 4;
382
 
383
            // invalid packet if elem_size exceeds packet length
384
            if( (pos+elem_size) > len )
385
                return -1; // invalid packet
386
 
387
            // parse element if size > 0
388
            if( elem_size ) {
389
                int status = searchElement((unsigned char *)(packet+pos), elem_size, &oscArgs, searchTree);
390
                if( status < 0 )
391
                    return status;
392
            }
393
 
394
            // switch to next element
395
            pos += elem_size;
396
        }
397
 
398
    } else {
399
        // no timetag
400
        oscArgs.timetag.seconds = 0;
401
        oscArgs.timetag.fraction = 0;
402
 
403
        // get element size
404
        unsigned elemSize = getWord(packet);
405
 
406
        // invalid packet if elemSize exceeds packet length
407
        if( elemSize > len )
408
            return -1; // invalid packet
409
 
410
        // parse element if size > 0
411
        if( elemSize ) {
412
            int status = searchElement((unsigned char *)(packet+4), elemSize, &oscArgs, searchTree);
413
            if( status < 0 )
414
                return status;
415
        }
416
    }
417
 
418
    return 0; // no error
419
}
420
 
421
 
422
/////////////////////////////////////////////////////////////////////////////
423
// Internal function:
424
// parses a single OSC element
425
// returns -2 if element has invalid format
426
// returns -3 if element contains an unsupported format
427
// returns -4 if MIOS32_OSC_MAX_PATH_PARTS has been exceeded
428
/////////////////////////////////////////////////////////////////////////////
429
int OscHelper::searchElement(unsigned char *buffer, const unsigned& len, OscHelper::OscArgsT *oscArgs, OscHelper::OscSearchTreeT *searchTree)
430
{
431
    // exit immediately if element is empty
432
    if( !len )
433
        return 0;
434
 
435
    // according to OSC spec, the path could be ommitted, and the element could start with the argument list
436
    // I don't know how to handle this correctly, but we should at least exit in this case
437
    unsigned char *path = buffer;
438
    if( *path == ',' )
439
        return -3; // unsupported element format
440
 
441
    // path: determine string length
442
    size_t pathLen = my_strnlen((char *)path, len);
443
 
444
    // check for valid string
445
    if( pathLen < 2 || path[pathLen] != 0 ) // expect at least two characters, e.g. "/*"
446
        return -2; // invalid element format
447
 
448
    // path must start with '/'
449
    if( *path != '/' )
450
        return -2; // invalid element format
451
 
452
    // tags are starting at word aligned offset
453
    // add +1 to pathLen, since \0 terminator is counted as well
454
    size_t tagsPos = (pathLen+1 + 3) & 0xfffffc;
455
 
456
    // check that tags are at valid position
457
    if( tagsPos >= len )
458
        return -2; // invalid element format
459
 
460
    // tags: determine string length
461
    unsigned char *tags = (unsigned char *)(buffer + tagsPos);
462
    size_t tagsLen = my_strnlen((char *)tags, len-tagsPos);
463
 
464
    // check for valid string
465
    if( tagsLen == 0 || tags[tagsLen] != 0 )
466
        return -2; // invalid element format
467
 
468
    // check that tags are starting with comma
469
    if( *tags != ',' )
470
        return -2; // invalid element format
471
 
472
    // number of arguments:
473
    unsigned numArgs = tagsLen - 1;
474
 
475
    // limit by max number of args which can be stored in oscArgs structure
476
    if( numArgs > MIOS32_OSC_MAX_ARGS )
477
        numArgs = MIOS32_OSC_MAX_ARGS;
478
 
479
    // arguments are starting at word aligned offset
480
    // add +1 to tagsLen, since \0 terminator is counted as well
481
    size_t argPos = (tagsPos + tagsLen+1 + 3) & 0xfffffc;
482
 
483
    // parse arguments
484
    oscArgs->numArgs = 0;
485
    unsigned arg;
486
    for(arg=0; arg<numArgs; ++arg) {
487
        // check that argument is at valid position
488
        if( argPos > len ) // TK: use > instead of >= to cover non-value parameters like T/F/I/...
489
            return -2; // invalid element format
490
 
491
        // store type and pointer to argument
492
        oscArgs->argType[oscArgs->numArgs] = tags[arg+1];
493
        oscArgs->argPtr[oscArgs->numArgs] = (unsigned char *)(buffer + argPos);
494
 
495
        // branch depending on argument tag
496
        unsigned char knownArg = 0;
497
        switch( tags[arg+1] ) {
498
        case 'i': // int32
499
        case 'f': // float32
500
        case 'c': // ASCII character
501
        case 'r': // 32bit RGBA color
502
        case 'm': // 4 byte MIDI message
503
            knownArg = 1;
504
            argPos += 4;
505
            break;
506
 
507
        case 's':   // OSC-string
508
        case 'S': { // OSC alternate string
509
            knownArg = 1;
510
            char *str = (char *)oscArgs->argPtr[oscArgs->numArgs];
511
            size_t strLen = my_strnlen(str, len-argPos);
512
            // check for valid string
513
            if( strLen == 0 || str[strLen] != 0 )
514
                return -2; // invalid element format
515
            // next argument at word aligned offset
516
            // add +1 to strLen, since \0 terminator is counted as well
517
            argPos = (argPos + strLen+1 + 3) & 0xfffffc;
518
        } break;
519
 
520
        case 'b': { // OSC-blob
521
            knownArg = 1;
522
            unsigned blobLen = getBlobLength((unsigned char *)(buffer + argPos));
523
            // next argument at word aligned offset
524
            argPos = (argPos + 4 + blobLen + 3) & 0xfffffc;
525
        } break;
526
 
527
        case 'h': // long64
528
        case 't': // OSC timetag
529
        case 'd': // float64 (double)
530
            knownArg = 1;
531
            argPos += 8;
532
            break;
533
 
534
        case 'T': // TRUE
535
        case 'F': // FALSE
536
        case 'N': // NIL
537
        case 'I': // Infinitum
538
        case '[': // Begin of Array
539
        case ']': // End of Array
540
            knownArg = 1;
541
            break;
542
        }
543
 
544
        // according to OSC V1.0 spec, nonstandard arguments should be discarded (don't report error)
545
        // since we don't know the position to the next argument, we have to stop parsing here!
546
        if( knownArg )
547
            ++oscArgs->numArgs;
548
        else
549
            break;
550
    }
551
 
552
    // finally parse for elements which are matching the OSC address
553
    oscArgs->numPathParts = 0;
554
    return searchPath((char *)&path[1], oscArgs, 0x00000000, searchTree);
555
}
556
 
557
 
558
/////////////////////////////////////////////////////////////////////////////
559
// Internal function:
560
// searches in searchTree for matching OSC addresses
561
// returns -4 if MIOS32_OSC_MAX_PATH_PARTS has been exceeded
562
/////////////////////////////////////////////////////////////////////////////
563
int OscHelper::searchPath(char *path, OscHelper::OscArgsT *oscArgs, const unsigned& methodArg, OscHelper::OscSearchTreeT *searchTree)
564
{
565
    if( oscArgs->numPathParts >= MIOS32_OSC_MAX_PATH_PARTS )
566
        return -4; // maximum number of path parts exceeded
567
 
568
    while( searchTree->address != NULL ) {
569
        // compare OSC address with name of tree item
570
        unsigned char match = 1;
571
        unsigned char wildcard = 0;
572
 
573
        char *str1 = path;
574
        char *str2 = (char *)searchTree->address;
575
        size_t sepPos = 0;
576
 
577
        while( *str1 != 0 && *str1 != '/' ) {
578
            if( *str1 == '*' ) {
579
                // '*' wildcard: continue to end of address part
580
                while( *str1 != 0 && *str1 != '/' ) {
581
                    ++sepPos;
582
                    ++str1;
583
                }
584
                wildcard = 1;
585
                break;
586
            } else {
587
                // no wildcard: check for matching characters
588
                ++sepPos;
589
                if( *str2 == 0 || (*str2 != *str1 && *str1 != '?') ) {
590
                    match = 0;
591
                    break;
592
                }
593
                ++str1;
594
                ++str2;
595
            }
596
        }
597
 
598
        if( !wildcard && *str2 != 0 ) // we haven't parsed the complete string
599
            match = 0;
600
 
601
        if( match ) {
602
            // store number of path parts in local variable, since content of oscArgs is changed recursively
603
            // we don't want to copy the whole structure to save (a lot of...) memory
604
            unsigned char numPathParts = oscArgs->numPathParts;
605
            // add pointer to path part
606
            oscArgs->pathPart[numPathParts] = (char *)searchTree->address;
607
            oscArgs->numPathParts = numPathParts + 1;
608
 
609
            // OR method args of current node to the args to propagate optional parameters
610
            unsigned combinedMethodArg = methodArg | searchTree->methodArg;
611
 
612
            if( searchTree->oscListener ) {
613
                searchTree->oscListener->parsedOscPacket(*oscArgs, combinedMethodArg);
614
            } else if( searchTree->next ) {
615
 
616
                // continue search in next hierarchy level
617
                int status = searchPath((char *)&path[sepPos+1], oscArgs, combinedMethodArg, searchTree->next);
618
                if( status < 0 )
619
                    return status;
620
            }
621
 
622
            // restore number of path parts (which has been changed recursively)
623
            oscArgs->numPathParts = numPathParts;
624
        }
625
 
626
        ++searchTree;
627
    }
628
 
629
    // Table Terminator has been reached - check if method is defined that will be executed on any received OSC element
630
    // TODO: bring this into MIOS32 as well?
631
    if( searchTree->oscListener ) {
632
        oscArgs->numPathParts = 1;
633
        oscArgs->pathPart[0] = (char *)path;
634
        searchTree->oscListener->parsedOscPacket(*oscArgs, 0);
635
    }
636
 
637
    return 0; // no error
638
}
639
 
640
 
641
/////////////////////////////////////////////////////////////////////////////
642
// Converts an OSC element in readable format.
643
//
644
// Usage Example:
645
// \code
646
// void parsedOscPacket(const OscHelper::OscArgsT& oscArgs, const const unsigned& methodArg)
647
// {
648
//     if( oscString == String::empty )
649
//         oscString = T("@") + String::formatted(T("%d.%d "), oscArgs.timetag.seconds, oscArgs.timetag.fraction);
650
//     else
651
//         oscString += " ";
652
// 
653
//     oscString += OscHelper::element2String(oscArgs);
654
// }
655
// \endcode
656
//
657
// \param[in] oscArgs pointer to OSC argument list as forwarded by parsePacket()
658
// \return < 0 on errors
659
/////////////////////////////////////////////////////////////////////////////
660
String OscHelper::element2String(const OscArgsT& oscArgs)
661
{
662
    String str;
663
 
664
    for(int i=0; i<oscArgs.numPathParts; ++i)
665
        str += T("/") + String(oscArgs.pathPart[i]);
666
 
667
    for(int i=0; i < oscArgs.numArgs; ++i) {
668
        str += T(" ") + String::formatted(T("%c"), oscArgs.argType[i]);
669
 
670
        switch( oscArgs.argType[i] ) {
671
        case 'i': // int32
672
            str += String(getInt(oscArgs.argPtr[i]));
673
            break;
674
 
675
        case 'f': // float32
676
            str += String::formatted(T("%05.3f"), getFloat(oscArgs.argPtr[i]));
677
            break;
678
 
679
        case 's': // string
680
        case 'S': // alternate string
681
            str += String(getString(oscArgs.argPtr[i]));
682
            break;
683
 
684
        case 'b': // blob
685
            str += String(T("(blob with length ") + String(getWord(oscArgs.argPtr[i])) + ")");
686
            break;
687
 
688
        case 'h': // int64
689
            str += String(getLongLong(oscArgs.argPtr[i]));
690
            break;
691
 
692
        case 't': { // timetag
693
            OscTimetagT timetag = getTimetag(oscArgs.argPtr[i]);
694
            str += String::formatted(T("%d.%d"), timetag.seconds, timetag.fraction);
695
        } break;
696
 
697
        case 'd': // float64 (double)
698
            str += String::formatted(T("%05.3f"), getDouble(oscArgs.argPtr[i]));
699
            break;
700
 
701
        case 'c': // ASCII character
702
            str += String::formatted(T("%c"), getChar(oscArgs.argPtr[i]));
703
            break;
704
 
705
        case 'r': // 32 bit RGBA color
706
            str += String::formatted(T("0x%08x"), getWord(oscArgs.argPtr[i]));
707
            break;
708
 
709
        case 'm': // MIDI message
710
            str += String::formatted(T("0x%08x"), getMIDI(oscArgs.argPtr[i]));
711
            break;
712
 
713
        case 'T': // TRUE
714
        case 'F': // FALSE
715
        case 'N': // NIL
716
        case 'I': // Infinitum
717
        case '[': // beginning of array
718
        case ']': // end of array
719
            break;
720
 
721
        default:
722
            str += T("(unknown)");
723
        }
724
    }
725
 
726
    return str;
727
}