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: #ifndef INCLUDED_OSCRECEIVEDELEMENTS_H tomwalters@570: #define INCLUDED_OSCRECEIVEDELEMENTS_H tomwalters@570: tomwalters@570: #include "OscTypes.h" tomwalters@570: #include "OscException.h" tomwalters@570: tomwalters@570: tomwalters@570: namespace osc{ tomwalters@570: tomwalters@570: tomwalters@570: class MalformedMessageException : public Exception{ tomwalters@570: public: tomwalters@570: MalformedMessageException( const char *w="malformed message" ) tomwalters@570: : Exception( w ) {} tomwalters@570: }; tomwalters@570: tomwalters@570: class MalformedBundleException : public Exception{ tomwalters@570: public: tomwalters@570: MalformedBundleException( const char *w="malformed bundle" ) tomwalters@570: : Exception( w ) {} tomwalters@570: }; tomwalters@570: tomwalters@570: class WrongArgumentTypeException : public Exception{ tomwalters@570: public: tomwalters@570: WrongArgumentTypeException( const char *w="wrong argument type" ) tomwalters@570: : Exception( w ) {} tomwalters@570: }; tomwalters@570: tomwalters@570: class MissingArgumentException : public Exception{ tomwalters@570: public: tomwalters@570: MissingArgumentException( const char *w="missing argument" ) tomwalters@570: : Exception( w ) {} tomwalters@570: }; tomwalters@570: tomwalters@570: class ExcessArgumentException : public Exception{ tomwalters@570: public: tomwalters@570: ExcessArgumentException( const char *w="too many arguments" ) tomwalters@570: : Exception( w ) {} tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedPacket{ tomwalters@570: public: tomwalters@570: ReceivedPacket( const char *contents, int32 size ) tomwalters@570: : contents_( contents ) tomwalters@570: , size_( size ) {} tomwalters@570: tomwalters@570: bool IsMessage() const { return !IsBundle(); } tomwalters@570: bool IsBundle() const; tomwalters@570: tomwalters@570: int32 Size() const { return size_; } tomwalters@570: const char *Contents() const { return contents_; } tomwalters@570: tomwalters@570: private: tomwalters@570: const char *contents_; tomwalters@570: int32 size_; tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedBundleElement{ tomwalters@570: public: tomwalters@570: ReceivedBundleElement( const char *size ) tomwalters@570: : size_( size ) {} tomwalters@570: tomwalters@570: friend class ReceivedBundleElementIterator; tomwalters@570: tomwalters@570: bool IsMessage() const { return !IsBundle(); } tomwalters@570: bool IsBundle() const; tomwalters@570: tomwalters@570: int32 Size() const; tomwalters@570: const char *Contents() const { return size_ + 4; } tomwalters@570: tomwalters@570: private: tomwalters@570: const char *size_; tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedBundleElementIterator{ tomwalters@570: public: tomwalters@570: ReceivedBundleElementIterator( const char *sizePtr ) tomwalters@570: : value_( sizePtr ) {} tomwalters@570: tomwalters@570: ReceivedBundleElementIterator operator++() tomwalters@570: { tomwalters@570: Advance(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedBundleElementIterator operator++(int) tomwalters@570: { tomwalters@570: ReceivedBundleElementIterator old( *this ); tomwalters@570: Advance(); tomwalters@570: return old; tomwalters@570: } tomwalters@570: tomwalters@570: const ReceivedBundleElement& operator*() const { return value_; } tomwalters@570: tomwalters@570: const ReceivedBundleElement* operator->() const { return &value_; } tomwalters@570: tomwalters@570: friend bool operator==(const ReceivedBundleElementIterator& lhs, tomwalters@570: const ReceivedBundleElementIterator& rhs ); tomwalters@570: tomwalters@570: private: tomwalters@570: ReceivedBundleElement value_; tomwalters@570: tomwalters@570: void Advance() { value_.size_ = value_.Contents() + value_.Size(); } tomwalters@570: tomwalters@570: bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const tomwalters@570: { tomwalters@570: return value_.size_ == rhs.value_.size_; tomwalters@570: } tomwalters@570: }; tomwalters@570: tomwalters@570: inline bool operator==(const ReceivedBundleElementIterator& lhs, tomwalters@570: const ReceivedBundleElementIterator& rhs ) tomwalters@570: { tomwalters@570: return lhs.IsEqualTo( rhs ); tomwalters@570: } tomwalters@570: tomwalters@570: inline bool operator!=(const ReceivedBundleElementIterator& lhs, tomwalters@570: const ReceivedBundleElementIterator& rhs ) tomwalters@570: { tomwalters@570: return !( lhs == rhs ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedMessageArgument{ tomwalters@570: public: tomwalters@570: ReceivedMessageArgument( const char *typeTag, const char *argument ) tomwalters@570: : typeTag_( typeTag ) tomwalters@570: , argument_( argument ) {} tomwalters@570: tomwalters@570: friend class ReceivedMessageArgumentIterator; tomwalters@570: tomwalters@570: const char TypeTag() const { return *typeTag_; } tomwalters@570: tomwalters@570: // the unchecked methods below don't check whether the argument actually tomwalters@570: // is of the specified type. they should only be used if you've already tomwalters@570: // checked the type tag or the associated IsType() method. tomwalters@570: tomwalters@570: bool IsBool() const tomwalters@570: { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; } tomwalters@570: bool AsBool() const; tomwalters@570: bool AsBoolUnchecked() const; tomwalters@570: tomwalters@570: bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; } tomwalters@570: bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; } tomwalters@570: tomwalters@570: bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; } tomwalters@570: int32 AsInt32() const; tomwalters@570: int32 AsInt32Unchecked() const; tomwalters@570: tomwalters@570: bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; } tomwalters@570: float AsFloat() const; tomwalters@570: float AsFloatUnchecked() const; tomwalters@570: tomwalters@570: bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; } tomwalters@570: char AsChar() const; tomwalters@570: char AsCharUnchecked() const; tomwalters@570: tomwalters@570: bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; } tomwalters@570: uint32 AsRgbaColor() const; tomwalters@570: uint32 AsRgbaColorUnchecked() const; tomwalters@570: tomwalters@570: bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; } tomwalters@570: uint32 AsMidiMessage() const; tomwalters@570: uint32 AsMidiMessageUnchecked() const; tomwalters@570: tomwalters@570: bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; } tomwalters@570: int64 AsInt64() const; tomwalters@570: int64 AsInt64Unchecked() const; tomwalters@570: tomwalters@570: bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; } tomwalters@570: uint64 AsTimeTag() const; tomwalters@570: uint64 AsTimeTagUnchecked() const; tomwalters@570: tomwalters@570: bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; } tomwalters@570: double AsDouble() const; tomwalters@570: double AsDoubleUnchecked() const; tomwalters@570: tomwalters@570: bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; } tomwalters@570: const char* AsString() const; tomwalters@570: const char* AsStringUnchecked() const { return argument_; } tomwalters@570: tomwalters@570: bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; } tomwalters@570: const char* AsSymbol() const; tomwalters@570: const char* AsSymbolUnchecked() const { return argument_; } tomwalters@570: tomwalters@570: bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; } tomwalters@570: void AsBlob( const void*& data, unsigned long& size ) const; tomwalters@570: void AsBlobUnchecked( const void*& data, unsigned long& size ) const; tomwalters@570: tomwalters@570: private: tomwalters@570: const char *typeTag_; tomwalters@570: const char *argument_; tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedMessageArgumentIterator{ tomwalters@570: public: tomwalters@570: ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) tomwalters@570: : value_( typeTags, arguments ) {} tomwalters@570: tomwalters@570: ReceivedMessageArgumentIterator operator++() tomwalters@570: { tomwalters@570: Advance(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentIterator operator++(int) tomwalters@570: { tomwalters@570: ReceivedMessageArgumentIterator old( *this ); tomwalters@570: Advance(); tomwalters@570: return old; tomwalters@570: } tomwalters@570: tomwalters@570: const ReceivedMessageArgument& operator*() const { return value_; } tomwalters@570: tomwalters@570: const ReceivedMessageArgument* operator->() const { return &value_; } tomwalters@570: tomwalters@570: friend bool operator==(const ReceivedMessageArgumentIterator& lhs, tomwalters@570: const ReceivedMessageArgumentIterator& rhs ); tomwalters@570: tomwalters@570: private: tomwalters@570: ReceivedMessageArgument value_; tomwalters@570: tomwalters@570: void Advance(); tomwalters@570: tomwalters@570: bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const tomwalters@570: { tomwalters@570: return value_.typeTag_ == rhs.value_.typeTag_; tomwalters@570: } tomwalters@570: }; tomwalters@570: tomwalters@570: inline bool operator==(const ReceivedMessageArgumentIterator& lhs, tomwalters@570: const ReceivedMessageArgumentIterator& rhs ) tomwalters@570: { tomwalters@570: return lhs.IsEqualTo( rhs ); tomwalters@570: } tomwalters@570: tomwalters@570: inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, tomwalters@570: const ReceivedMessageArgumentIterator& rhs ) tomwalters@570: { tomwalters@570: return !( lhs == rhs ); tomwalters@570: } tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedMessageArgumentStream{ tomwalters@570: friend class ReceivedMessage; tomwalters@570: ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, tomwalters@570: const ReceivedMessageArgumentIterator& end ) tomwalters@570: : p_( begin ) tomwalters@570: , end_( end ) {} tomwalters@570: tomwalters@570: ReceivedMessageArgumentIterator p_, end_; tomwalters@570: tomwalters@570: public: tomwalters@570: tomwalters@570: // end of stream tomwalters@570: bool Eos() const { return p_ == end_; } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( bool& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsBool(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: // not sure if it would be useful to stream Nil and Infinitum tomwalters@570: // for now it's not possible tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( int32& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsInt32(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( float& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsFloat(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( char& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsChar(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs.value = (*p_++).AsRgbaColor(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs.value = (*p_++).AsMidiMessage(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( int64& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsInt64(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs.value = (*p_++).AsTimeTag(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( double& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsDouble(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( Blob& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: (*p_++).AsBlob( rhs.data, rhs.size ); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( const char*& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs = (*p_++).AsString(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) tomwalters@570: { tomwalters@570: if( Eos() ) tomwalters@570: throw MissingArgumentException(); tomwalters@570: tomwalters@570: rhs.value = (*p_++).AsSymbol(); tomwalters@570: return *this; tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) tomwalters@570: { tomwalters@570: if( !Eos() ) tomwalters@570: throw ExcessArgumentException(); tomwalters@570: tomwalters@570: return *this; tomwalters@570: } tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedMessage{ tomwalters@570: void Init( const char *bundle, unsigned long size ); tomwalters@570: public: tomwalters@570: explicit ReceivedMessage( const ReceivedPacket& packet ); tomwalters@570: explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); tomwalters@570: tomwalters@570: const char *AddressPattern() const { return addressPattern_; } tomwalters@570: tomwalters@570: // Support for non-standad SuperCollider integer address patterns: tomwalters@570: bool AddressPatternIsUInt32() const; tomwalters@570: uint32 AddressPatternAsUInt32() const; tomwalters@570: tomwalters@570: unsigned long ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } tomwalters@570: tomwalters@570: const char *TypeTags() const { return typeTagsBegin_; } tomwalters@570: tomwalters@570: tomwalters@570: typedef ReceivedMessageArgumentIterator const_iterator; tomwalters@570: tomwalters@570: ReceivedMessageArgumentIterator ArgumentsBegin() const tomwalters@570: { tomwalters@570: return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentIterator ArgumentsEnd() const tomwalters@570: { tomwalters@570: return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedMessageArgumentStream ArgumentStream() const tomwalters@570: { tomwalters@570: return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); tomwalters@570: } tomwalters@570: tomwalters@570: private: tomwalters@570: const char *addressPattern_; tomwalters@570: const char *typeTagsBegin_; tomwalters@570: const char *typeTagsEnd_; tomwalters@570: const char *arguments_; tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: class ReceivedBundle{ tomwalters@570: void Init( const char *message, unsigned long size ); tomwalters@570: public: tomwalters@570: explicit ReceivedBundle( const ReceivedPacket& packet ); tomwalters@570: explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); tomwalters@570: tomwalters@570: uint64 TimeTag() const; tomwalters@570: tomwalters@570: unsigned long ElementCount() const { return elementCount_; } tomwalters@570: tomwalters@570: typedef ReceivedBundleElementIterator const_iterator; tomwalters@570: tomwalters@570: ReceivedBundleElementIterator ElementsBegin() const tomwalters@570: { tomwalters@570: return ReceivedBundleElementIterator( timeTag_ + 8 ); tomwalters@570: } tomwalters@570: tomwalters@570: ReceivedBundleElementIterator ElementsEnd() const tomwalters@570: { tomwalters@570: return ReceivedBundleElementIterator( end_ ); tomwalters@570: } tomwalters@570: tomwalters@570: private: tomwalters@570: const char *timeTag_; tomwalters@570: const char *end_; tomwalters@570: unsigned long elementCount_; tomwalters@570: }; tomwalters@570: tomwalters@570: tomwalters@570: } // namespace osc tomwalters@570: tomwalters@570: tomwalters@570: #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */