tomwalters@570: /* tomwalters@570: oscpack -- Open Sound Control packet manipulation library tomwalters@570: http://www.audiomulch.com/~rossb/oscpack tomwalters@570: tomwalters@570: Copyright (c) 2004-2005 Ross Bencina tomwalters@570: tomwalters@570: Permission is hereby granted, free of charge, to any person obtaining tomwalters@570: a copy of this software and associated documentation files tomwalters@570: (the "Software"), to deal in the Software without restriction, tomwalters@570: including without limitation the rights to use, copy, modify, merge, tomwalters@570: publish, distribute, sublicense, and/or sell copies of the Software, tomwalters@570: and to permit persons to whom the Software is furnished to do so, tomwalters@570: subject to the following conditions: tomwalters@570: tomwalters@570: The above copyright notice and this permission notice shall be tomwalters@570: included in all copies or substantial portions of the Software. tomwalters@570: tomwalters@570: Any person wishing to distribute modifications to the Software is tomwalters@570: requested to send the modifications to the original developer so that tomwalters@570: they can be incorporated into the canonical version. tomwalters@570: tomwalters@570: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, tomwalters@570: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF tomwalters@570: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. tomwalters@570: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR tomwalters@570: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF tomwalters@570: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION tomwalters@570: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tomwalters@570: */ tomwalters@570: #include "OscReceivedElements.h" tomwalters@570: tomwalters@570: #include tomwalters@570: tomwalters@570: #include "OscHostEndianness.h" tomwalters@570: tomwalters@570: tomwalters@570: namespace osc{ tomwalters@570: tomwalters@570: tomwalters@570: // return the first 4 byte boundary after the end of a str4 tomwalters@570: // be careful about calling this version if you don't know whether tomwalters@570: // the string is terminated correctly. tomwalters@570: static inline const char* FindStr4End( const char *p ) tomwalters@570: { tomwalters@570: if( p[0] == '\0' ) // special case for SuperCollider integer address pattern tomwalters@570: return p + 4; tomwalters@570: tomwalters@570: p += 3; tomwalters@570: tomwalters@570: while( *p ) tomwalters@570: p += 4; tomwalters@570: tomwalters@570: return p + 1; tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: // return the first 4 byte boundary after the end of a str4 tomwalters@570: // returns 0 if p == end or if the string is unterminated tomwalters@570: static inline const char* FindStr4End( const char *p, const char *end ) tomwalters@570: { tomwalters@570: if( p >= end ) tomwalters@570: return 0; tomwalters@570: tomwalters@570: if( p[0] == '\0' ) // special case for SuperCollider integer address pattern tomwalters@570: return p + 4; tomwalters@570: tomwalters@570: p += 3; tomwalters@570: end -= 1; tomwalters@570: tomwalters@570: while( p < end && *p ) tomwalters@570: p += 4; tomwalters@570: tomwalters@570: if( *p ) tomwalters@570: return 0; tomwalters@570: else tomwalters@570: return p + 1; tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: static inline unsigned long RoundUp4( unsigned long x ) tomwalters@570: { tomwalters@570: unsigned long remainder = x & 0x3UL; tomwalters@570: if( remainder ) tomwalters@570: return x + (4 - remainder); tomwalters@570: else tomwalters@570: return x; tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: static inline int32 ToInt32( const char *p ) tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: osc::int32 i; tomwalters@570: char c[4]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = p[3]; tomwalters@570: u.c[1] = p[2]; tomwalters@570: u.c[2] = p[1]; tomwalters@570: u.c[3] = p[0]; tomwalters@570: tomwalters@570: return u.i; tomwalters@570: #else tomwalters@570: return *(int32*)p; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: static inline uint32 ToUInt32( const char *p ) tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: osc::uint32 i; tomwalters@570: char c[4]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = p[3]; tomwalters@570: u.c[1] = p[2]; tomwalters@570: u.c[2] = p[1]; tomwalters@570: u.c[3] = p[0]; tomwalters@570: tomwalters@570: return u.i; tomwalters@570: #else tomwalters@570: return *(uint32*)p; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: int64 ToInt64( const char *p ) tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: osc::int64 i; tomwalters@570: char c[4]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = p[7]; tomwalters@570: u.c[1] = p[6]; tomwalters@570: u.c[2] = p[5]; tomwalters@570: u.c[3] = p[4]; tomwalters@570: u.c[4] = p[3]; tomwalters@570: u.c[5] = p[2]; tomwalters@570: u.c[6] = p[1]; tomwalters@570: u.c[7] = p[0]; tomwalters@570: tomwalters@570: return u.i; tomwalters@570: #else tomwalters@570: return *(int64*)p; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint64 ToUInt64( const char *p ) tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: osc::uint64 i; tomwalters@570: char c[4]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = p[7]; tomwalters@570: u.c[1] = p[6]; tomwalters@570: u.c[2] = p[5]; tomwalters@570: u.c[3] = p[4]; tomwalters@570: u.c[4] = p[3]; tomwalters@570: u.c[5] = p[2]; tomwalters@570: u.c[6] = p[1]; tomwalters@570: u.c[7] = p[0]; tomwalters@570: tomwalters@570: return u.i; tomwalters@570: #else tomwalters@570: return *(uint64*)p; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: //------------------------------------------------------------------------------ tomwalters@570: tomwalters@570: bool ReceivedPacket::IsBundle() const tomwalters@570: { tomwalters@570: return (Size() > 0 && Contents()[0] == '#'); tomwalters@570: } tomwalters@570: tomwalters@570: //------------------------------------------------------------------------------ tomwalters@570: tomwalters@570: bool ReceivedBundleElement::IsBundle() const tomwalters@570: { tomwalters@570: return (Size() > 0 && Contents()[0] == '#'); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: int32 ReceivedBundleElement::Size() const tomwalters@570: { tomwalters@570: return ToUInt32( size_ ); tomwalters@570: } tomwalters@570: tomwalters@570: //------------------------------------------------------------------------------ tomwalters@570: tomwalters@570: bool ReceivedMessageArgument::AsBool() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == TRUE_TYPE_TAG ) tomwalters@570: return true; tomwalters@570: else if( *typeTag_ == FALSE_TYPE_TAG ) tomwalters@570: return false; tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: bool ReceivedMessageArgument::AsBoolUnchecked() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == TRUE_TYPE_TAG ) tomwalters@570: return true; tomwalters@570: else tomwalters@570: return false; tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: int32 ReceivedMessageArgument::AsInt32() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == INT32_TYPE_TAG ) tomwalters@570: return AsInt32Unchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: int32 ReceivedMessageArgument::AsInt32Unchecked() const tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: osc::int32 i; tomwalters@570: char c[4]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = argument_[3]; tomwalters@570: u.c[1] = argument_[2]; tomwalters@570: u.c[2] = argument_[1]; tomwalters@570: u.c[3] = argument_[0]; tomwalters@570: tomwalters@570: return u.i; tomwalters@570: #else tomwalters@570: return *(int32*)argument_; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: float ReceivedMessageArgument::AsFloat() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == FLOAT_TYPE_TAG ) tomwalters@570: return AsFloatUnchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: float ReceivedMessageArgument::AsFloatUnchecked() const tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: float f; tomwalters@570: char c[4]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = argument_[3]; tomwalters@570: u.c[1] = argument_[2]; tomwalters@570: u.c[2] = argument_[1]; tomwalters@570: u.c[3] = argument_[0]; tomwalters@570: tomwalters@570: return u.f; tomwalters@570: #else tomwalters@570: return *(float*)argument_; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: char ReceivedMessageArgument::AsChar() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == CHAR_TYPE_TAG ) tomwalters@570: return AsCharUnchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: char ReceivedMessageArgument::AsCharUnchecked() const tomwalters@570: { tomwalters@570: return (char)ToInt32( argument_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint32 ReceivedMessageArgument::AsRgbaColor() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == RGBA_COLOR_TYPE_TAG ) tomwalters@570: return AsRgbaColorUnchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const tomwalters@570: { tomwalters@570: return ToUInt32( argument_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint32 ReceivedMessageArgument::AsMidiMessage() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG ) tomwalters@570: return AsMidiMessageUnchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const tomwalters@570: { tomwalters@570: return ToUInt32( argument_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: int64 ReceivedMessageArgument::AsInt64() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == INT64_TYPE_TAG ) tomwalters@570: return AsInt64Unchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: int64 ReceivedMessageArgument::AsInt64Unchecked() const tomwalters@570: { tomwalters@570: return ToInt64( argument_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint64 ReceivedMessageArgument::AsTimeTag() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == TIME_TAG_TYPE_TAG ) tomwalters@570: return AsTimeTagUnchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const tomwalters@570: { tomwalters@570: return ToUInt64( argument_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: double ReceivedMessageArgument::AsDouble() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == DOUBLE_TYPE_TAG ) tomwalters@570: return AsDoubleUnchecked(); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: double ReceivedMessageArgument::AsDoubleUnchecked() const tomwalters@570: { tomwalters@570: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@570: union{ tomwalters@570: double d; tomwalters@570: char c[8]; tomwalters@570: } u; tomwalters@570: tomwalters@570: u.c[0] = argument_[7]; tomwalters@570: u.c[1] = argument_[6]; tomwalters@570: u.c[2] = argument_[5]; tomwalters@570: u.c[3] = argument_[4]; tomwalters@570: u.c[4] = argument_[3]; tomwalters@570: u.c[5] = argument_[2]; tomwalters@570: u.c[6] = argument_[1]; tomwalters@570: u.c[7] = argument_[0]; tomwalters@570: tomwalters@570: return u.d; tomwalters@570: #else tomwalters@570: return *(double*)argument_; tomwalters@570: #endif tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: const char* ReceivedMessageArgument::AsString() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == STRING_TYPE_TAG ) tomwalters@570: return argument_; tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: const char* ReceivedMessageArgument::AsSymbol() const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == SYMBOL_TYPE_TAG ) tomwalters@570: return argument_; tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const tomwalters@570: { tomwalters@570: if( !typeTag_ ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: else if( *typeTag_ == BLOB_TYPE_TAG ) tomwalters@570: AsBlobUnchecked( data, size ); tomwalters@570: else tomwalters@570: throw WrongArgumentTypeException(); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const tomwalters@570: { tomwalters@570: size = ToUInt32( argument_ ); tomwalters@570: data = (void*)(argument_+4); tomwalters@570: } tomwalters@570: tomwalters@570: //------------------------------------------------------------------------------ tomwalters@570: tomwalters@570: void ReceivedMessageArgumentIterator::Advance() tomwalters@570: { tomwalters@570: if( !value_.typeTag_ ) tomwalters@570: return; tomwalters@570: tomwalters@570: switch( *value_.typeTag_++ ){ tomwalters@570: case '\0': tomwalters@570: // don't advance past end tomwalters@570: --value_.typeTag_; tomwalters@570: break; tomwalters@570: tomwalters@570: case TRUE_TYPE_TAG: tomwalters@570: case FALSE_TYPE_TAG: tomwalters@570: case NIL_TYPE_TAG: tomwalters@570: case INFINITUM_TYPE_TAG: tomwalters@570: tomwalters@570: // zero length tomwalters@570: break; tomwalters@570: tomwalters@570: case INT32_TYPE_TAG: tomwalters@570: case FLOAT_TYPE_TAG: tomwalters@570: case CHAR_TYPE_TAG: tomwalters@570: case RGBA_COLOR_TYPE_TAG: tomwalters@570: case MIDI_MESSAGE_TYPE_TAG: tomwalters@570: tomwalters@570: value_.argument_ += 4; tomwalters@570: break; tomwalters@570: tomwalters@570: case INT64_TYPE_TAG: tomwalters@570: case TIME_TAG_TYPE_TAG: tomwalters@570: case DOUBLE_TYPE_TAG: tomwalters@570: tomwalters@570: value_.argument_ += 8; tomwalters@570: break; tomwalters@570: tomwalters@570: case STRING_TYPE_TAG: tomwalters@570: case SYMBOL_TYPE_TAG: tomwalters@570: tomwalters@570: // we use the unsafe function FindStr4End(char*) here because all of tomwalters@570: // the arguments have already been validated in tomwalters@570: // ReceivedMessage::Init() below. tomwalters@570: tomwalters@570: value_.argument_ = FindStr4End( value_.argument_ ); tomwalters@570: break; tomwalters@570: tomwalters@570: case BLOB_TYPE_TAG: tomwalters@570: { tomwalters@570: uint32 blobSize = ToUInt32( value_.argument_ ); tomwalters@570: value_.argument_ = value_.argument_ + 4 + RoundUp4( blobSize ); tomwalters@570: } tomwalters@570: break; tomwalters@570: tomwalters@570: default: // unknown type tag tomwalters@570: // don't advance tomwalters@570: --value_.typeTag_; tomwalters@570: break; tomwalters@570: tomwalters@570: tomwalters@570: // not handled: tomwalters@570: // [ Indicates the beginning of an array. The tags following are for tomwalters@570: // data in the Array until a close brace tag is reached. tomwalters@570: // ] Indicates the end of an array. tomwalters@570: } tomwalters@570: } tomwalters@570: tomwalters@570: //------------------------------------------------------------------------------ tomwalters@570: tomwalters@570: ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet ) tomwalters@570: : addressPattern_( packet.Contents() ) tomwalters@570: { tomwalters@570: Init( packet.Contents(), packet.Size() ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement ) tomwalters@570: : addressPattern_( bundleElement.Contents() ) tomwalters@570: { tomwalters@570: Init( bundleElement.Contents(), bundleElement.Size() ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: bool ReceivedMessage::AddressPatternIsUInt32() const tomwalters@570: { tomwalters@570: return (addressPattern_[0] == '\0'); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint32 ReceivedMessage::AddressPatternAsUInt32() const tomwalters@570: { tomwalters@570: return ToUInt32( addressPattern_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: void ReceivedMessage::Init( const char *message, unsigned long size ) tomwalters@570: { tomwalters@570: if( size == 0 ) tomwalters@570: throw MalformedMessageException( "zero length messages not permitted" ); tomwalters@570: tomwalters@570: if( (size & 0x03L) != 0 ) tomwalters@570: throw MalformedMessageException( "message size must be multiple of four" ); tomwalters@570: tomwalters@570: const char *end = message + size; tomwalters@570: tomwalters@570: typeTagsBegin_ = FindStr4End( addressPattern_, end ); tomwalters@570: if( typeTagsBegin_ == 0 ){ tomwalters@570: // address pattern was not terminated before end tomwalters@570: throw MalformedMessageException( "unterminated address pattern" ); tomwalters@570: } tomwalters@570: tomwalters@570: if( typeTagsBegin_ == end ){ tomwalters@570: // message consists of only the address pattern - no arguments or type tags. tomwalters@570: typeTagsBegin_ = 0; tomwalters@570: typeTagsEnd_ = 0; tomwalters@570: arguments_ = 0; tomwalters@570: tomwalters@570: }else{ tomwalters@570: if( *typeTagsBegin_ != ',' ) tomwalters@570: throw MalformedMessageException( "type tags not present" ); tomwalters@570: tomwalters@570: if( *(typeTagsBegin_ + 1) == '\0' ){ tomwalters@570: // zero length type tags tomwalters@570: typeTagsBegin_ = 0; tomwalters@570: typeTagsEnd_ = 0; tomwalters@570: arguments_ = 0; tomwalters@570: tomwalters@570: }else{ tomwalters@570: // check that all arguments are present and well formed tomwalters@570: tomwalters@570: arguments_ = FindStr4End( typeTagsBegin_, end ); tomwalters@570: if( arguments_ == 0 ){ tomwalters@570: throw MalformedMessageException( "type tags were not terminated before end of message" ); tomwalters@570: } tomwalters@570: tomwalters@570: ++typeTagsBegin_; // advance past initial ',' tomwalters@570: tomwalters@570: const char *typeTag = typeTagsBegin_; tomwalters@570: const char *argument = arguments_; tomwalters@570: tomwalters@570: do{ tomwalters@570: switch( *typeTag ){ tomwalters@570: case TRUE_TYPE_TAG: tomwalters@570: case FALSE_TYPE_TAG: tomwalters@570: case NIL_TYPE_TAG: tomwalters@570: case INFINITUM_TYPE_TAG: tomwalters@570: tomwalters@570: // zero length tomwalters@570: break; tomwalters@570: tomwalters@570: case INT32_TYPE_TAG: tomwalters@570: case FLOAT_TYPE_TAG: tomwalters@570: case CHAR_TYPE_TAG: tomwalters@570: case RGBA_COLOR_TYPE_TAG: tomwalters@570: case MIDI_MESSAGE_TYPE_TAG: tomwalters@570: tomwalters@570: if( argument == end ) tomwalters@570: throw MalformedMessageException( "arguments exceed message size" ); tomwalters@570: argument += 4; tomwalters@570: if( argument > end ) tomwalters@570: throw MalformedMessageException( "arguments exceed message size" ); tomwalters@570: break; tomwalters@570: tomwalters@570: case INT64_TYPE_TAG: tomwalters@570: case TIME_TAG_TYPE_TAG: tomwalters@570: case DOUBLE_TYPE_TAG: tomwalters@570: tomwalters@570: if( argument == end ) tomwalters@570: throw MalformedMessageException( "arguments exceed message size" ); tomwalters@570: argument += 8; tomwalters@570: if( argument > end ) tomwalters@570: throw MalformedMessageException( "arguments exceed message size" ); tomwalters@570: break; tomwalters@570: tomwalters@570: case STRING_TYPE_TAG: tomwalters@570: case SYMBOL_TYPE_TAG: tomwalters@570: tomwalters@570: if( argument == end ) tomwalters@570: throw MalformedMessageException( "arguments exceed message size" ); tomwalters@570: argument = FindStr4End( argument, end ); tomwalters@570: if( argument == 0 ) tomwalters@570: throw MalformedMessageException( "unterminated string argument" ); tomwalters@570: break; tomwalters@570: tomwalters@570: case BLOB_TYPE_TAG: tomwalters@570: { tomwalters@570: if( argument + 4 > end ) tomwalters@570: MalformedMessageException( "arguments exceed message size" ); tomwalters@570: tomwalters@570: uint32 blobSize = ToUInt32( argument ); tomwalters@570: argument = argument + 4 + RoundUp4( blobSize ); tomwalters@570: if( argument > end ) tomwalters@570: MalformedMessageException( "arguments exceed message size" ); tomwalters@570: } tomwalters@570: break; tomwalters@570: tomwalters@570: default: tomwalters@570: throw MalformedMessageException( "unknown type tag" ); tomwalters@570: tomwalters@570: // not handled: tomwalters@570: // [ Indicates the beginning of an array. The tags following are for tomwalters@570: // data in the Array until a close brace tag is reached. tomwalters@570: // ] Indicates the end of an array. tomwalters@570: } tomwalters@570: tomwalters@570: }while( *++typeTag != '\0' ); tomwalters@570: typeTagsEnd_ = typeTag; tomwalters@570: } tomwalters@570: } tomwalters@570: } tomwalters@570: tomwalters@570: //------------------------------------------------------------------------------ tomwalters@570: tomwalters@570: ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet ) tomwalters@570: : elementCount_( 0 ) tomwalters@570: { tomwalters@570: Init( packet.Contents(), packet.Size() ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement ) tomwalters@570: : elementCount_( 0 ) tomwalters@570: { tomwalters@570: Init( bundleElement.Contents(), bundleElement.Size() ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: void ReceivedBundle::Init( const char *bundle, unsigned long size ) tomwalters@570: { tomwalters@570: if( size < 16 ) tomwalters@570: throw MalformedBundleException( "packet too short for bundle" ); tomwalters@570: tomwalters@570: if( (size & 0x03L) != 0 ) tomwalters@570: throw MalformedBundleException( "bundle size must be multiple of four" ); tomwalters@570: tomwalters@570: if( bundle[0] != '#' tomwalters@570: || bundle[1] != 'b' tomwalters@570: || bundle[2] != 'u' tomwalters@570: || bundle[3] != 'n' tomwalters@570: || bundle[4] != 'd' tomwalters@570: || bundle[5] != 'l' tomwalters@570: || bundle[6] != 'e' tomwalters@570: || bundle[7] != '\0' ) tomwalters@570: throw MalformedBundleException( "bad bundle address pattern" ); tomwalters@570: tomwalters@570: end_ = bundle + size; tomwalters@570: tomwalters@570: timeTag_ = bundle + 8; tomwalters@570: tomwalters@570: const char *p = timeTag_ + 8; tomwalters@570: tomwalters@570: while( p < end_ ){ tomwalters@570: if( p + 4 > end_ ) tomwalters@570: throw MalformedBundleException( "packet too short for elementSize" ); tomwalters@570: tomwalters@570: uint32 elementSize = ToUInt32( p ); tomwalters@570: if( (elementSize & 0x03L) != 0 ) tomwalters@570: throw MalformedBundleException( "bundle element size must be multiple of four" ); tomwalters@570: tomwalters@570: p += 4 + elementSize; tomwalters@570: if( p > end_ ) tomwalters@570: throw MalformedBundleException( "packet too short for bundle element" ); tomwalters@570: tomwalters@570: ++elementCount_; tomwalters@570: } tomwalters@570: tomwalters@570: if( p != end_ ) tomwalters@570: throw MalformedBundleException( "bundle contents " ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: uint64 ReceivedBundle::TimeTag() const tomwalters@570: { tomwalters@570: return ToUInt64( timeTag_ ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: } // namespace osc tomwalters@570: