root/oscpack/tags/release_1_0_2/osc/OscReceivedElements.cpp

Revision 71, 17.3 kB (checked in by ross, 2 years ago)

patch to support SuperCollider? integer address patterns

  • Property svn:eol-style set to native
Line 
1 /*
2         oscpack -- Open Sound Control packet manipulation library
3         http://www.audiomulch.com/~rossb/oscpack
4
5         Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
6
7         Permission is hereby granted, free of charge, to any person obtaining
8         a copy of this software and associated documentation files
9         (the "Software"), to deal in the Software without restriction,
10         including without limitation the rights to use, copy, modify, merge,
11         publish, distribute, sublicense, and/or sell copies of the Software,
12         and to permit persons to whom the Software is furnished to do so,
13         subject to the following conditions:
14
15         The above copyright notice and this permission notice shall be
16         included in all copies or substantial portions of the Software.
17
18         Any person wishing to distribute modifications to the Software is
19         requested to send the modifications to the original developer so that
20         they can be incorporated into the canonical version.
21
22         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23         EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24         MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25         IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
26         ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27         CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28         WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 */
30 #include "OscReceivedElements.h"
31
32 #include <cassert>
33
34 #include "OscHostEndianness.h"
35
36
37 namespace osc{
38
39
40 // return the first 4 byte boundary after the end of a str4
41 // be careful about calling this version if you don't know whether
42 // the string is terminated correctly.
43 static inline const char* FindStr4End( const char *p )
44 {
45         if( p[0] == '\0' )    // special case for SuperCollider integer address pattern
46                 return p + 4;
47
48     p += 3;
49
50     while( *p )
51         p += 4;
52
53     return p + 1;
54 }
55
56
57 // return the first 4 byte boundary after the end of a str4
58 // returns 0 if p == end or if the string is unterminated
59 static inline const char* FindStr4End( const char *p, const char *end )
60 {
61     if( p >= end )
62         return 0;
63
64         if( p[0] == '\0' )    // special case for SuperCollider integer address pattern
65                 return p + 4;
66
67     p += 3;
68     end -= 1;
69
70     while( p < end && *p )
71         p += 4;
72
73     if( *p )
74         return 0;
75     else
76         return p + 1;
77 }
78
79
80 static inline unsigned long RoundUp4( unsigned long x )
81 {
82     unsigned long remainder = x & 0x3UL;
83     if( remainder )
84         return x + (4 - remainder);
85     else
86         return x;
87 }
88
89
90 static inline int32 ToInt32( const char *p )
91 {
92 #ifdef OSC_HOST_LITTLE_ENDIAN
93     union{
94         osc::int32 i;
95         char c[4];
96     } u;
97
98     u.c[0] = p[3];
99     u.c[1] = p[2];
100     u.c[2] = p[1];
101     u.c[3] = p[0];
102
103     return u.i;
104 #else
105         return *(int32*)p;
106 #endif
107 }
108
109
110 static inline uint32 ToUInt32( const char *p )
111 {
112 #ifdef OSC_HOST_LITTLE_ENDIAN
113     union{
114         osc::uint32 i;
115         char c[4];
116     } u;
117
118     u.c[0] = p[3];
119     u.c[1] = p[2];
120     u.c[2] = p[1];
121     u.c[3] = p[0];
122
123     return u.i;
124 #else
125         return *(uint32*)p;
126 #endif
127 }
128
129
130 int64 ToInt64( const char *p )
131 {
132 #ifdef OSC_HOST_LITTLE_ENDIAN
133     union{
134         osc::int64 i;
135         char c[4];
136     } u;
137
138     u.c[0] = p[7];
139     u.c[1] = p[6];
140     u.c[2] = p[5];
141     u.c[3] = p[4];
142     u.c[4] = p[3];
143     u.c[5] = p[2];
144     u.c[6] = p[1];
145     u.c[7] = p[0];
146
147     return u.i;
148 #else
149         return *(int64*)p;
150 #endif
151 }
152
153
154 uint64 ToUInt64( const char *p )
155 {
156 #ifdef OSC_HOST_LITTLE_ENDIAN
157     union{
158         osc::uint64 i;
159         char c[4];
160     } u;
161
162     u.c[0] = p[7];
163     u.c[1] = p[6];
164     u.c[2] = p[5];
165     u.c[3] = p[4];
166     u.c[4] = p[3];
167     u.c[5] = p[2];
168     u.c[6] = p[1];
169     u.c[7] = p[0];
170
171     return u.i;
172 #else
173         return *(uint64*)p;
174 #endif
175 }
176
177 //------------------------------------------------------------------------------
178
179 bool ReceivedPacket::IsBundle() const
180 {
181     return (Size() > 0 && Contents()[0] == '#');
182 }
183
184 //------------------------------------------------------------------------------
185
186 bool ReceivedBundleElement::IsBundle() const
187 {
188     return (Size() > 0 && Contents()[0] == '#');
189 }
190
191
192 int32 ReceivedBundleElement::Size() const
193 {
194     return ToUInt32( size_ );
195 }
196
197 //------------------------------------------------------------------------------
198
199 bool ReceivedMessageArgument::AsBool() const
200 {
201     if( !typeTag_ )
202         throw MissingArgumentException();
203         else if( *typeTag_ == TRUE_TYPE_TAG )
204                 return true;
205         else if( *typeTag_ == FALSE_TYPE_TAG )
206                 return false;
207         else
208                 throw WrongArgumentTypeException();
209 }
210
211
212 bool ReceivedMessageArgument::AsBoolUnchecked() const
213 {
214     if( !typeTag_ )
215         throw MissingArgumentException();
216         else if( *typeTag_ == TRUE_TYPE_TAG )
217                 return true;
218     else
219             return false;
220 }
221
222
223 int32 ReceivedMessageArgument::AsInt32() const
224 {
225     if( !typeTag_ )
226         throw MissingArgumentException();
227         else if( *typeTag_ == INT32_TYPE_TAG )
228                 return AsInt32Unchecked();
229         else
230                 throw WrongArgumentTypeException();
231 }
232
233
234 int32 ReceivedMessageArgument::AsInt32Unchecked() const
235 {
236 #ifdef OSC_HOST_LITTLE_ENDIAN
237     union{
238         osc::int32 i;
239         char c[4];
240     } u;
241
242     u.c[0] = argument_[3];
243     u.c[1] = argument_[2];
244     u.c[2] = argument_[1];
245     u.c[3] = argument_[0];
246
247     return u.i;
248 #else
249         return *(int32*)argument_;
250 #endif
251 }
252
253
254 float ReceivedMessageArgument::AsFloat() const
255 {
256     if( !typeTag_ )
257         throw MissingArgumentException();
258         else if( *typeTag_ == FLOAT_TYPE_TAG )
259                 return AsFloatUnchecked();
260         else
261                 throw WrongArgumentTypeException();
262 }
263
264
265 float ReceivedMessageArgument::AsFloatUnchecked() const
266 {
267 #ifdef OSC_HOST_LITTLE_ENDIAN
268     union{
269         float f;
270         char c[4];
271     } u;
272
273     u.c[0] = argument_[3];
274     u.c[1] = argument_[2];
275     u.c[2] = argument_[1];
276     u.c[3] = argument_[0];
277
278     return u.f;
279 #else
280         return *(float*)argument_;
281 #endif
282 }
283
284
285 char ReceivedMessageArgument::AsChar() const
286 {
287     if( !typeTag_ )
288         throw MissingArgumentException();
289         else if( *typeTag_ == CHAR_TYPE_TAG )
290                 return AsCharUnchecked();
291         else
292                 throw WrongArgumentTypeException();
293 }
294
295
296 char ReceivedMessageArgument::AsCharUnchecked() const
297 {
298     return (char)ToInt32( argument_ );
299 }
300
301
302 uint32 ReceivedMessageArgument::AsRgbaColor() const
303 {
304     if( !typeTag_ )
305         throw MissingArgumentException();
306         else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
307                 return AsRgbaColorUnchecked();
308         else
309                 throw WrongArgumentTypeException();
310 }
311
312
313 uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
314 {
315         return ToUInt32( argument_ );
316 }
317
318
319 uint32 ReceivedMessageArgument::AsMidiMessage() const
320 {
321     if( !typeTag_ )
322         throw MissingArgumentException();
323         else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
324                 return AsMidiMessageUnchecked();
325         else
326                 throw WrongArgumentTypeException();
327 }
328
329
330 uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
331 {
332         return ToUInt32( argument_ );
333 }
334
335
336 int64 ReceivedMessageArgument::AsInt64() const
337 {
338     if( !typeTag_ )
339         throw MissingArgumentException();
340         else if( *typeTag_ == INT64_TYPE_TAG )
341                 return AsInt64Unchecked();
342         else
343                 throw WrongArgumentTypeException();
344 }
345
346
347 int64 ReceivedMessageArgument::AsInt64Unchecked() const
348 {
349     return ToInt64( argument_ );
350 }
351
352
353 uint64 ReceivedMessageArgument::AsTimeTag() const
354 {
355     if( !typeTag_ )
356         throw MissingArgumentException();
357         else if( *typeTag_ == TIME_TAG_TYPE_TAG )
358                 return AsTimeTagUnchecked();
359         else
360                 throw WrongArgumentTypeException();
361 }
362
363
364 uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
365 {
366     return ToUInt64( argument_ );
367 }
368
369
370 double ReceivedMessageArgument::AsDouble() const
371 {
372     if( !typeTag_ )
373         throw MissingArgumentException();
374         else if( *typeTag_ == DOUBLE_TYPE_TAG )
375                 return AsDoubleUnchecked();
376         else
377                 throw WrongArgumentTypeException();
378 }
379
380
381 double ReceivedMessageArgument::AsDoubleUnchecked() const
382 {
383 #ifdef OSC_HOST_LITTLE_ENDIAN
384     union{
385         double d;
386         char c[8];
387     } u;
388
389     u.c[0] = argument_[7];
390     u.c[1] = argument_[6];
391     u.c[2] = argument_[5];
392     u.c[3] = argument_[4];
393     u.c[4] = argument_[3];
394     u.c[5] = argument_[2];
395     u.c[6] = argument_[1];
396     u.c[7] = argument_[0];
397
398     return u.d;
399 #else
400         return *(double*)argument_;
401 #endif
402 }
403
404
405 const char* ReceivedMessageArgument::AsString() const
406 {
407     if( !typeTag_ )
408         throw MissingArgumentException();
409         else if( *typeTag_ == STRING_TYPE_TAG )
410                 return argument_;
411         else
412                 throw WrongArgumentTypeException();
413 }
414
415
416 const char* ReceivedMessageArgument::AsSymbol() const
417 {
418     if( !typeTag_ )
419         throw MissingArgumentException();
420         else if( *typeTag_ == SYMBOL_TYPE_TAG )
421                 return argument_;
422         else
423                 throw WrongArgumentTypeException();
424 }
425
426
427 void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
428 {
429     if( !typeTag_ )
430         throw MissingArgumentException();
431         else if( *typeTag_ == BLOB_TYPE_TAG )
432                 AsBlobUnchecked( data, size );
433         else
434                 throw WrongArgumentTypeException();
435 }
436
437
438 void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
439 {
440     size = ToUInt32( argument_ );
441         data = (void*)(argument_+4);
442 }
443
444 //------------------------------------------------------------------------------
445
446 void ReceivedMessageArgumentIterator::Advance()
447 {
448     if( !value_.typeTag_ )
449         return;
450        
451     switch( *value_.typeTag_++ ){
452         case '\0':
453             // don't advance past end
454             --value_.typeTag_;
455             break;
456            
457         case TRUE_TYPE_TAG:
458         case FALSE_TYPE_TAG:
459         case NIL_TYPE_TAG:
460         case INFINITUM_TYPE_TAG:
461
462             // zero length
463             break;
464
465         case INT32_TYPE_TAG:
466         case FLOAT_TYPE_TAG:                                   
467         case CHAR_TYPE_TAG:
468         case RGBA_COLOR_TYPE_TAG:
469         case MIDI_MESSAGE_TYPE_TAG:
470
471             value_.argument_ += 4;
472             break;
473
474         case INT64_TYPE_TAG:
475         case TIME_TAG_TYPE_TAG:
476         case DOUBLE_TYPE_TAG:
477                                
478             value_.argument_ += 8;
479             break;
480
481         case STRING_TYPE_TAG:
482         case SYMBOL_TYPE_TAG:
483
484             // we use the unsafe function FindStr4End(char*) here because all of
485             // the arguments have already been validated in
486             // ReceivedMessage::Init() below.
487             
488             value_.argument_ = FindStr4End( value_.argument_ );
489             break;
490
491         case BLOB_TYPE_TAG:
492             {
493                 uint32 blobSize = ToUInt32( value_.argument_ );
494                 value_.argument_ = value_.argument_ + 4 + RoundUp4( blobSize );
495             }
496             break;
497
498         default:    // unknown type tag
499             // don't advance
500             --value_.typeTag_;
501             break;
502            
503
504         //    not handled:
505         //    [ Indicates the beginning of an array. The tags following are for
506         //        data in the Array until a close brace tag is reached.
507         //    ] Indicates the end of an array.
508     }
509 }
510
511 //------------------------------------------------------------------------------
512
513 ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
514     : addressPattern_( packet.Contents() )
515 {
516     Init( packet.Contents(), packet.Size() );
517 }
518
519
520 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
521     : addressPattern_( bundleElement.Contents() )
522 {
523     Init( bundleElement.Contents(), bundleElement.Size() );
524 }
525
526
527 bool ReceivedMessage::AddressPatternIsUInt32() const
528 {
529         return (addressPattern_[0] == '\0');
530 }
531
532
533 uint32 ReceivedMessage::AddressPatternAsUInt32() const
534 {
535     return ToUInt32( addressPattern_ );
536 }
537
538
539 void ReceivedMessage::Init( const char *message, unsigned long size )
540 {
541     if( size == 0 )
542         throw MalformedMessageException( "zero length messages not permitted" );
543
544     if( (size & 0x03L) != 0 )
545         throw MalformedMessageException( "message size must be multiple of four" );
546
547     const char *end = message + size;
548
549     typeTagsBegin_ = FindStr4End( addressPattern_, end );
550     if( typeTagsBegin_ == 0 ){
551         // address pattern was not terminated before end
552         throw MalformedMessageException( "unterminated address pattern" );
553     }
554
555     if( typeTagsBegin_ == end ){
556         // message consists of only the address pattern - no arguments or type tags.
557         typeTagsBegin_ = 0;
558         typeTagsEnd_ = 0;
559         arguments_ = 0;
560            
561     }else{
562         if( *typeTagsBegin_ != ',' )
563             throw MalformedMessageException( "type tags not present" );
564
565         if( *(typeTagsBegin_ + 1) == '\0' ){
566             // zero length type tags
567             typeTagsBegin_ = 0;
568             typeTagsEnd_ = 0;
569             arguments_ = 0;
570
571         }else{
572             // check that all arguments are present and well formed
573                 
574             arguments_ = FindStr4End( typeTagsBegin_, end );
575             if( arguments_ == 0 ){
576                 throw MalformedMessageException( "type tags were not terminated before end of message" );
577             }
578
579             ++typeTagsBegin_; // advance past initial ','
580             
581             const char *typeTag = typeTagsBegin_;
582             const char *argument = arguments_;
583                        
584             do{
585                 switch( *typeTag ){
586                     case TRUE_TYPE_TAG:
587                     case FALSE_TYPE_TAG:
588                     case NIL_TYPE_TAG:
589                     case INFINITUM_TYPE_TAG:
590
591                         // zero length
592                         break;
593
594                     case INT32_TYPE_TAG:
595                     case FLOAT_TYPE_TAG:
596                     case CHAR_TYPE_TAG:
597                     case RGBA_COLOR_TYPE_TAG:
598                     case MIDI_MESSAGE_TYPE_TAG:
599
600                         if( argument == end )
601                             throw MalformedMessageException( "arguments exceed message size" );
602                         argument += 4;
603                         if( argument > end )
604                             throw MalformedMessageException( "arguments exceed message size" );
605                         break;
606
607                     case INT64_TYPE_TAG:
608                     case TIME_TAG_TYPE_TAG:
609                     case DOUBLE_TYPE_TAG:
610
611                         if( argument == end )
612                             throw MalformedMessageException( "arguments exceed message size" );
613                         argument += 8;
614                         if( argument > end )
615                             throw MalformedMessageException( "arguments exceed message size" );
616                         break;
617
618                     case STRING_TYPE_TAG:
619                     case SYMBOL_TYPE_TAG:
620                    
621                         if( argument == end )
622                             throw MalformedMessageException( "arguments exceed message size" );
623                         argument = FindStr4End( argument, end );
624                         if( argument == 0 )
625                             throw MalformedMessageException( "unterminated string argument" );
626                         break;
627
628                     case BLOB_TYPE_TAG:
629                         {
630                             if( argument + 4 > end )
631                                 MalformedMessageException( "arguments exceed message size" );
632                                
633                             uint32 blobSize = ToUInt32( argument );
634                             argument = argument + 4 + RoundUp4( blobSize );
635                             if( argument > end )
636                                 MalformedMessageException( "arguments exceed message size" );
637                         }
638                         break;
639                        
640                     default:
641                         throw MalformedMessageException( "unknown type tag" );
642
643                     //    not handled:
644                     //    [ Indicates the beginning of an array. The tags following are for
645                     //        data in the Array until a close brace tag is reached.
646                     //    ] Indicates the end of an array.
647                 }
648
649             }while( *++typeTag != '\0' );
650             typeTagsEnd_ = typeTag;
651         }
652     }
653 }
654
655 //------------------------------------------------------------------------------
656
657 ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
658     : elementCount_( 0 )
659 {
660     Init( packet.Contents(), packet.Size() );
661 }
662
663
664 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
665     : elementCount_( 0 )
666 {
667     Init( bundleElement.Contents(), bundleElement.Size() );
668 }
669
670
671 void ReceivedBundle::Init( const char *bundle, unsigned long size )
672 {
673     if( size < 16 )
674         throw MalformedBundleException( "packet too short for bundle" );
675
676     if( (size & 0x03L) != 0 )
677         throw MalformedBundleException( "bundle size must be multiple of four" );
678
679     if( bundle[0] != '#'
680         || bundle[1] != 'b'
681         || bundle[2] != 'u'
682         || bundle[3] != 'n'
683         || bundle[4] != 'd'
684         || bundle[5] != 'l'
685         || bundle[6] != 'e'
686         || bundle[7] != '\0' )
687             throw MalformedBundleException( "bad bundle address pattern" );   
688
689     end_ = bundle + size;
690
691     timeTag_ = bundle + 8;
692
693     const char *p = timeTag_ + 8;
694        
695     while( p < end_ ){
696         if( p + 4 > end_ )
697             throw MalformedBundleException( "packet too short for elementSize" );
698
699         uint32 elementSize = ToUInt32( p );
700         if( (elementSize & 0x03L) != 0 )
701             throw MalformedBundleException( "bundle element size must be multiple of four" );
702
703         p += 4 + elementSize;
704         if( p > end_ )
705             throw MalformedBundleException( "packet too short for bundle element" );
706
707         ++elementCount_;
708     }
709
710     if( p != end_ )
711         throw MalformedBundleException( "bundle contents " );
712 }
713
714
715 uint64 ReceivedBundle::TimeTag() const
716 {
717     return ToUInt64( timeTag_ );
718 }
719
720
721 } // namespace osc
722
Note: See TracBrowser for help on using the browser.