2 oscpack -- Open Sound Control packet manipulation library
3 http://www.audiomulch.com/~rossb/oscpack
5 Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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:
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
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.
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.
30 #include "OscReceivedElements.h"
34 #include "OscHostEndianness.h"
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
)
45 if( p
[0] == '\0' ) // special case for SuperCollider integer address pattern
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
)
64 if( p
[0] == '\0' ) // special case for SuperCollider integer address pattern
70 while( p
< end
&& *p
)
80 static inline unsigned long RoundUp4( unsigned long x
)
82 unsigned long remainder
= x
& 0x3UL
;
84 return x
+ (4 - remainder
);
90 static inline int32
ToInt32( const char *p
)
92 #ifdef OSC_HOST_LITTLE_ENDIAN
110 static inline uint32
ToUInt32( const char *p
)
112 #ifdef OSC_HOST_LITTLE_ENDIAN
130 int64
ToInt64( const char *p
)
132 #ifdef OSC_HOST_LITTLE_ENDIAN
154 uint64
ToUInt64( const char *p
)
156 #ifdef OSC_HOST_LITTLE_ENDIAN
177 //------------------------------------------------------------------------------
179 bool ReceivedPacket::IsBundle() const
181 return (Size() > 0 && Contents()[0] == '#');
184 //------------------------------------------------------------------------------
186 bool ReceivedBundleElement::IsBundle() const
188 return (Size() > 0 && Contents()[0] == '#');
192 int32
ReceivedBundleElement::Size() const
194 return ToUInt32( size_
);
197 //------------------------------------------------------------------------------
199 bool ReceivedMessageArgument::AsBool() const
202 throw MissingArgumentException();
203 else if( *typeTag_
== TRUE_TYPE_TAG
)
205 else if( *typeTag_
== FALSE_TYPE_TAG
)
208 throw WrongArgumentTypeException();
212 bool ReceivedMessageArgument::AsBoolUnchecked() const
215 throw MissingArgumentException();
216 else if( *typeTag_
== TRUE_TYPE_TAG
)
223 int32
ReceivedMessageArgument::AsInt32() const
226 throw MissingArgumentException();
227 else if( *typeTag_
== INT32_TYPE_TAG
)
228 return AsInt32Unchecked();
230 throw WrongArgumentTypeException();
234 int32
ReceivedMessageArgument::AsInt32Unchecked() const
236 #ifdef OSC_HOST_LITTLE_ENDIAN
242 u
.c
[0] = argument_
[3];
243 u
.c
[1] = argument_
[2];
244 u
.c
[2] = argument_
[1];
245 u
.c
[3] = argument_
[0];
249 return *(int32
*)argument_
;
254 float ReceivedMessageArgument::AsFloat() const
257 throw MissingArgumentException();
258 else if( *typeTag_
== FLOAT_TYPE_TAG
)
259 return AsFloatUnchecked();
261 throw WrongArgumentTypeException();
265 float ReceivedMessageArgument::AsFloatUnchecked() const
267 #ifdef OSC_HOST_LITTLE_ENDIAN
273 u
.c
[0] = argument_
[3];
274 u
.c
[1] = argument_
[2];
275 u
.c
[2] = argument_
[1];
276 u
.c
[3] = argument_
[0];
280 return *(float*)argument_
;
285 char ReceivedMessageArgument::AsChar() const
288 throw MissingArgumentException();
289 else if( *typeTag_
== CHAR_TYPE_TAG
)
290 return AsCharUnchecked();
292 throw WrongArgumentTypeException();
296 char ReceivedMessageArgument::AsCharUnchecked() const
298 return (char)ToInt32( argument_
);
302 uint32
ReceivedMessageArgument::AsRgbaColor() const
305 throw MissingArgumentException();
306 else if( *typeTag_
== RGBA_COLOR_TYPE_TAG
)
307 return AsRgbaColorUnchecked();
309 throw WrongArgumentTypeException();
313 uint32
ReceivedMessageArgument::AsRgbaColorUnchecked() const
315 return ToUInt32( argument_
);
319 uint32
ReceivedMessageArgument::AsMidiMessage() const
322 throw MissingArgumentException();
323 else if( *typeTag_
== MIDI_MESSAGE_TYPE_TAG
)
324 return AsMidiMessageUnchecked();
326 throw WrongArgumentTypeException();
330 uint32
ReceivedMessageArgument::AsMidiMessageUnchecked() const
332 return ToUInt32( argument_
);
336 int64
ReceivedMessageArgument::AsInt64() const
339 throw MissingArgumentException();
340 else if( *typeTag_
== INT64_TYPE_TAG
)
341 return AsInt64Unchecked();
343 throw WrongArgumentTypeException();
347 int64
ReceivedMessageArgument::AsInt64Unchecked() const
349 return ToInt64( argument_
);
353 uint64
ReceivedMessageArgument::AsTimeTag() const
356 throw MissingArgumentException();
357 else if( *typeTag_
== TIME_TAG_TYPE_TAG
)
358 return AsTimeTagUnchecked();
360 throw WrongArgumentTypeException();
364 uint64
ReceivedMessageArgument::AsTimeTagUnchecked() const
366 return ToUInt64( argument_
);
370 double ReceivedMessageArgument::AsDouble() const
373 throw MissingArgumentException();
374 else if( *typeTag_
== DOUBLE_TYPE_TAG
)
375 return AsDoubleUnchecked();
377 throw WrongArgumentTypeException();
381 double ReceivedMessageArgument::AsDoubleUnchecked() const
383 #ifdef OSC_HOST_LITTLE_ENDIAN
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];
400 return *(double*)argument_
;
405 const char* ReceivedMessageArgument::AsString() const
408 throw MissingArgumentException();
409 else if( *typeTag_
== STRING_TYPE_TAG
)
412 throw WrongArgumentTypeException();
416 const char* ReceivedMessageArgument::AsSymbol() const
419 throw MissingArgumentException();
420 else if( *typeTag_
== SYMBOL_TYPE_TAG
)
423 throw WrongArgumentTypeException();
427 void ReceivedMessageArgument::AsBlob( const void*& data
, unsigned long& size
) const
430 throw MissingArgumentException();
431 else if( *typeTag_
== BLOB_TYPE_TAG
)
432 AsBlobUnchecked( data
, size
);
434 throw WrongArgumentTypeException();
438 void ReceivedMessageArgument::AsBlobUnchecked( const void*& data
, unsigned long& size
) const
440 size
= ToUInt32( argument_
);
441 data
= (void*)(argument_
+4);
444 //------------------------------------------------------------------------------
446 void ReceivedMessageArgumentIterator::Advance()
448 if( !value_
.typeTag_
)
451 switch( *value_
.typeTag_
++ ){
453 // don't advance past end
460 case INFINITUM_TYPE_TAG
:
468 case RGBA_COLOR_TYPE_TAG
:
469 case MIDI_MESSAGE_TYPE_TAG
:
471 value_
.argument_
+= 4;
475 case TIME_TAG_TYPE_TAG
:
476 case DOUBLE_TYPE_TAG
:
478 value_
.argument_
+= 8;
481 case STRING_TYPE_TAG
:
482 case SYMBOL_TYPE_TAG
:
484 // we use the unsafe function FindStr4End(char*) here because all of
485 // the arguments have already been validated in
486 // ReceivedMessage::Init() below.
488 value_
.argument_
= FindStr4End( value_
.argument_
);
493 uint32 blobSize
= ToUInt32( value_
.argument_
);
494 value_
.argument_
= value_
.argument_
+ 4 + RoundUp4( blobSize
);
498 default: // unknown type tag
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.
511 //------------------------------------------------------------------------------
513 ReceivedMessage::ReceivedMessage( const ReceivedPacket
& packet
)
514 : addressPattern_( packet
.Contents() )
516 Init( packet
.Contents(), packet
.Size() );
520 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement
& bundleElement
)
521 : addressPattern_( bundleElement
.Contents() )
523 Init( bundleElement
.Contents(), bundleElement
.Size() );
527 bool ReceivedMessage::AddressPatternIsUInt32() const
529 return (addressPattern_
[0] == '\0');
533 uint32
ReceivedMessage::AddressPatternAsUInt32() const
535 return ToUInt32( addressPattern_
);
539 void ReceivedMessage::Init( const char *message
, unsigned long size
)
542 throw MalformedMessageException( "zero length messages not permitted" );
544 if( (size
& 0x03L
) != 0 )
545 throw MalformedMessageException( "message size must be multiple of four" );
547 const char *end
= message
+ size
;
549 typeTagsBegin_
= FindStr4End( addressPattern_
, end
);
550 if( typeTagsBegin_
== 0 ){
551 // address pattern was not terminated before end
552 throw MalformedMessageException( "unterminated address pattern" );
555 if( typeTagsBegin_
== end
){
556 // message consists of only the address pattern - no arguments or type tags.
562 if( *typeTagsBegin_
!= ',' )
563 throw MalformedMessageException( "type tags not present" );
565 if( *(typeTagsBegin_
+ 1) == '\0' ){
566 // zero length type tags
572 // check that all arguments are present and well formed
574 arguments_
= FindStr4End( typeTagsBegin_
, end
);
575 if( arguments_
== 0 ){
576 throw MalformedMessageException( "type tags were not terminated before end of message" );
579 ++typeTagsBegin_
; // advance past initial ','
581 const char *typeTag
= typeTagsBegin_
;
582 const char *argument
= arguments_
;
589 case INFINITUM_TYPE_TAG
:
597 case RGBA_COLOR_TYPE_TAG
:
598 case MIDI_MESSAGE_TYPE_TAG
:
600 if( argument
== end
)
601 throw MalformedMessageException( "arguments exceed message size" );
604 throw MalformedMessageException( "arguments exceed message size" );
608 case TIME_TAG_TYPE_TAG
:
609 case DOUBLE_TYPE_TAG
:
611 if( argument
== end
)
612 throw MalformedMessageException( "arguments exceed message size" );
615 throw MalformedMessageException( "arguments exceed message size" );
618 case STRING_TYPE_TAG
:
619 case SYMBOL_TYPE_TAG
:
621 if( argument
== end
)
622 throw MalformedMessageException( "arguments exceed message size" );
623 argument
= FindStr4End( argument
, end
);
625 throw MalformedMessageException( "unterminated string argument" );
630 if( argument
+ 4 > end
)
631 MalformedMessageException( "arguments exceed message size" );
633 uint32 blobSize
= ToUInt32( argument
);
634 argument
= argument
+ 4 + RoundUp4( blobSize
);
636 MalformedMessageException( "arguments exceed message size" );
641 throw MalformedMessageException( "unknown type tag" );
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.
649 }while( *++typeTag
!= '\0' );
650 typeTagsEnd_
= typeTag
;
655 //------------------------------------------------------------------------------
657 ReceivedBundle::ReceivedBundle( const ReceivedPacket
& packet
)
660 Init( packet
.Contents(), packet
.Size() );
664 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement
& bundleElement
)
667 Init( bundleElement
.Contents(), bundleElement
.Size() );
671 void ReceivedBundle::Init( const char *bundle
, unsigned long size
)
674 throw MalformedBundleException( "packet too short for bundle" );
676 if( (size
& 0x03L
) != 0 )
677 throw MalformedBundleException( "bundle size must be multiple of four" );
686 || bundle
[7] != '\0' )
687 throw MalformedBundleException( "bad bundle address pattern" );
689 end_
= bundle
+ size
;
691 timeTag_
= bundle
+ 8;
693 const char *p
= timeTag_
+ 8;
697 throw MalformedBundleException( "packet too short for elementSize" );
699 uint32 elementSize
= ToUInt32( p
);
700 if( (elementSize
& 0x03L
) != 0 )
701 throw MalformedBundleException( "bundle element size must be multiple of four" );
703 p
+= 4 + elementSize
;
705 throw MalformedBundleException( "packet too short for bundle element" );
711 throw MalformedBundleException( "bundle contents " );
715 uint64
ReceivedBundle::TimeTag() const
717 return ToUInt64( timeTag_
);