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 std::size_t ReceivedMessageArgument::ArraySize() const
447 unsigned int level
= 0;
448 const char * type_tag
= typeTag_
+ 1;
451 switch (*type_tag
++) {
452 case ARRAY_START_TYPE_TAG
:
456 case ARRAY_END_TYPE_TAG
:
470 //------------------------------------------------------------------------------
472 void ReceivedMessageArgumentIterator::Advance()
474 if( !value_
.typeTag_
)
477 switch( *value_
.typeTag_
++ ){
479 // don't advance past end
486 case INFINITUM_TYPE_TAG
:
487 case ARRAY_START_TYPE_TAG
:
488 case ARRAY_END_TYPE_TAG
:
496 case RGBA_COLOR_TYPE_TAG
:
497 case MIDI_MESSAGE_TYPE_TAG
:
499 value_
.argument_
+= 4;
503 case TIME_TAG_TYPE_TAG
:
504 case DOUBLE_TYPE_TAG
:
506 value_
.argument_
+= 8;
509 case STRING_TYPE_TAG
:
510 case SYMBOL_TYPE_TAG
:
512 // we use the unsafe function FindStr4End(char*) here because all of
513 // the arguments have already been validated in
514 // ReceivedMessage::Init() below.
516 value_
.argument_
= FindStr4End( value_
.argument_
);
521 uint32 blobSize
= ToUInt32( value_
.argument_
);
522 value_
.argument_
= value_
.argument_
+ 4 + RoundUp4( (unsigned long)blobSize
);
526 default: // unknown type tag
533 //------------------------------------------------------------------------------
535 ReceivedMessage::ReceivedMessage( const ReceivedPacket
& packet
)
536 : addressPattern_( packet
.Contents() )
538 Init( packet
.Contents(), packet
.Size() );
542 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement
& bundleElement
)
543 : addressPattern_( bundleElement
.Contents() )
545 Init( bundleElement
.Contents(), bundleElement
.Size() );
549 bool ReceivedMessage::AddressPatternIsUInt32() const
551 return (addressPattern_
[0] == '\0');
555 uint32
ReceivedMessage::AddressPatternAsUInt32() const
557 return ToUInt32( addressPattern_
);
561 void ReceivedMessage::Init( const char *message
, unsigned long size
)
564 throw MalformedMessageException( "zero length messages not permitted" );
566 if( (size
& 0x03L
) != 0 )
567 throw MalformedMessageException( "message size must be multiple of four" );
569 const char *end
= message
+ size
;
571 typeTagsBegin_
= FindStr4End( addressPattern_
, end
);
572 if( typeTagsBegin_
== 0 ){
573 // address pattern was not terminated before end
574 throw MalformedMessageException( "unterminated address pattern" );
577 if( typeTagsBegin_
== end
){
578 // message consists of only the address pattern - no arguments or type tags.
584 if( *typeTagsBegin_
!= ',' )
585 throw MalformedMessageException( "type tags not present" );
587 if( *(typeTagsBegin_
+ 1) == '\0' ){
588 // zero length type tags
594 // check that all arguments are present and well formed
596 arguments_
= FindStr4End( typeTagsBegin_
, end
);
597 if( arguments_
== 0 ){
598 throw MalformedMessageException( "type tags were not terminated before end of message" );
601 ++typeTagsBegin_
; // advance past initial ','
603 const char *typeTag
= typeTagsBegin_
;
604 const char *argument
= arguments_
;
611 case INFINITUM_TYPE_TAG
:
612 case ARRAY_START_TYPE_TAG
:
613 case ARRAY_END_TYPE_TAG
:
621 case RGBA_COLOR_TYPE_TAG
:
622 case MIDI_MESSAGE_TYPE_TAG
:
624 if( argument
== end
)
625 throw MalformedMessageException( "arguments exceed message size" );
628 throw MalformedMessageException( "arguments exceed message size" );
632 case TIME_TAG_TYPE_TAG
:
633 case DOUBLE_TYPE_TAG
:
635 if( argument
== end
)
636 throw MalformedMessageException( "arguments exceed message size" );
639 throw MalformedMessageException( "arguments exceed message size" );
642 case STRING_TYPE_TAG
:
643 case SYMBOL_TYPE_TAG
:
645 if( argument
== end
)
646 throw MalformedMessageException( "arguments exceed message size" );
647 argument
= FindStr4End( argument
, end
);
649 throw MalformedMessageException( "unterminated string argument" );
654 if( argument
+ 4 > end
)
655 MalformedMessageException( "arguments exceed message size" );
657 uint32 blobSize
= ToUInt32( argument
);
658 argument
= argument
+ 4 + RoundUp4( (unsigned long)blobSize
);
660 MalformedMessageException( "arguments exceed message size" );
665 throw MalformedMessageException( "unknown type tag" );
668 // [ Indicates the beginning of an array. The tags following are for
669 // data in the Array until a close brace tag is reached.
670 // ] Indicates the end of an array.
673 }while( *++typeTag
!= '\0' );
674 typeTagsEnd_
= typeTag
;
679 //------------------------------------------------------------------------------
681 ReceivedBundle::ReceivedBundle( const ReceivedPacket
& packet
)
684 Init( packet
.Contents(), packet
.Size() );
688 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement
& bundleElement
)
691 Init( bundleElement
.Contents(), bundleElement
.Size() );
695 void ReceivedBundle::Init( const char *bundle
, unsigned long size
)
698 throw MalformedBundleException( "packet too short for bundle" );
700 if( (size
& 0x03L
) != 0 )
701 throw MalformedBundleException( "bundle size must be multiple of four" );
710 || bundle
[7] != '\0' )
711 throw MalformedBundleException( "bad bundle address pattern" );
713 end_
= bundle
+ size
;
715 timeTag_
= bundle
+ 8;
717 const char *p
= timeTag_
+ 8;
721 throw MalformedBundleException( "packet too short for elementSize" );
723 uint32 elementSize
= ToUInt32( p
);
724 if( (elementSize
& 0x03L
) != 0 )
725 throw MalformedBundleException( "bundle element size must be multiple of four" );
727 p
+= 4 + elementSize
;
729 throw MalformedBundleException( "packet too short for bundle element" );
735 throw MalformedBundleException( "bundle contents " );
739 uint64
ReceivedBundle::TimeTag() const
741 return ToUInt64( timeTag_
);