tomwalters@509: /* tomwalters@509: oscpack -- Open Sound Control packet manipulation library tomwalters@509: http://www.audiomulch.com/~rossb/oscpack tomwalters@509: tomwalters@509: Copyright (c) 2004-2005 Ross Bencina tomwalters@509: tomwalters@509: Permission is hereby granted, free of charge, to any person obtaining tomwalters@509: a copy of this software and associated documentation files tomwalters@509: (the "Software"), to deal in the Software without restriction, tomwalters@509: including without limitation the rights to use, copy, modify, merge, tomwalters@509: publish, distribute, sublicense, and/or sell copies of the Software, tomwalters@509: and to permit persons to whom the Software is furnished to do so, tomwalters@509: subject to the following conditions: tomwalters@509: tomwalters@509: The above copyright notice and this permission notice shall be tomwalters@509: included in all copies or substantial portions of the Software. tomwalters@509: tomwalters@509: Any person wishing to distribute modifications to the Software is tomwalters@509: requested to send the modifications to the original developer so that tomwalters@509: they can be incorporated into the canonical version. tomwalters@509: tomwalters@509: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, tomwalters@509: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF tomwalters@509: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. tomwalters@509: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR tomwalters@509: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF tomwalters@509: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION tomwalters@509: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tomwalters@509: */ tomwalters@509: #ifndef INCLUDED_OSCRECEIVEDELEMENTS_H tomwalters@509: #define INCLUDED_OSCRECEIVEDELEMENTS_H tomwalters@509: tomwalters@509: #include "OscTypes.h" tomwalters@509: #include "OscException.h" tomwalters@509: tomwalters@509: tomwalters@509: namespace osc{ tomwalters@509: tomwalters@509: tomwalters@509: class MalformedMessageException : public Exception{ tomwalters@509: public: tomwalters@509: MalformedMessageException( const char *w="malformed message" ) tomwalters@509: : Exception( w ) {} tomwalters@509: }; tomwalters@509: tomwalters@509: class MalformedBundleException : public Exception{ tomwalters@509: public: tomwalters@509: MalformedBundleException( const char *w="malformed bundle" ) tomwalters@509: : Exception( w ) {} tomwalters@509: }; tomwalters@509: tomwalters@509: class WrongArgumentTypeException : public Exception{ tomwalters@509: public: tomwalters@509: WrongArgumentTypeException( const char *w="wrong argument type" ) tomwalters@509: : Exception( w ) {} tomwalters@509: }; tomwalters@509: tomwalters@509: class MissingArgumentException : public Exception{ tomwalters@509: public: tomwalters@509: MissingArgumentException( const char *w="missing argument" ) tomwalters@509: : Exception( w ) {} tomwalters@509: }; tomwalters@509: tomwalters@509: class ExcessArgumentException : public Exception{ tomwalters@509: public: tomwalters@509: ExcessArgumentException( const char *w="too many arguments" ) tomwalters@509: : Exception( w ) {} tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedPacket{ tomwalters@509: public: tomwalters@509: ReceivedPacket( const char *contents, int32 size ) tomwalters@509: : contents_( contents ) tomwalters@509: , size_( size ) {} tomwalters@509: tomwalters@509: bool IsMessage() const { return !IsBundle(); } tomwalters@509: bool IsBundle() const; tomwalters@509: tomwalters@509: int32 Size() const { return size_; } tomwalters@509: const char *Contents() const { return contents_; } tomwalters@509: tomwalters@509: private: tomwalters@509: const char *contents_; tomwalters@509: int32 size_; tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedBundleElement{ tomwalters@509: public: tomwalters@509: ReceivedBundleElement( const char *size ) tomwalters@509: : size_( size ) {} tomwalters@509: tomwalters@509: friend class ReceivedBundleElementIterator; tomwalters@509: tomwalters@509: bool IsMessage() const { return !IsBundle(); } tomwalters@509: bool IsBundle() const; tomwalters@509: tomwalters@509: int32 Size() const; tomwalters@509: const char *Contents() const { return size_ + 4; } tomwalters@509: tomwalters@509: private: tomwalters@509: const char *size_; tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedBundleElementIterator{ tomwalters@509: public: tomwalters@509: ReceivedBundleElementIterator( const char *sizePtr ) tomwalters@509: : value_( sizePtr ) {} tomwalters@509: tomwalters@509: ReceivedBundleElementIterator operator++() tomwalters@509: { tomwalters@509: Advance(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedBundleElementIterator operator++(int) tomwalters@509: { tomwalters@509: ReceivedBundleElementIterator old( *this ); tomwalters@509: Advance(); tomwalters@509: return old; tomwalters@509: } tomwalters@509: tomwalters@509: const ReceivedBundleElement& operator*() const { return value_; } tomwalters@509: tomwalters@509: const ReceivedBundleElement* operator->() const { return &value_; } tomwalters@509: tomwalters@509: friend bool operator==(const ReceivedBundleElementIterator& lhs, tomwalters@509: const ReceivedBundleElementIterator& rhs ); tomwalters@509: tomwalters@509: private: tomwalters@509: ReceivedBundleElement value_; tomwalters@509: tomwalters@509: void Advance() { value_.size_ = value_.Contents() + value_.Size(); } tomwalters@509: tomwalters@509: bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const tomwalters@509: { tomwalters@509: return value_.size_ == rhs.value_.size_; tomwalters@509: } tomwalters@509: }; tomwalters@509: tomwalters@509: inline bool operator==(const ReceivedBundleElementIterator& lhs, tomwalters@509: const ReceivedBundleElementIterator& rhs ) tomwalters@509: { tomwalters@509: return lhs.IsEqualTo( rhs ); tomwalters@509: } tomwalters@509: tomwalters@509: inline bool operator!=(const ReceivedBundleElementIterator& lhs, tomwalters@509: const ReceivedBundleElementIterator& rhs ) tomwalters@509: { tomwalters@509: return !( lhs == rhs ); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedMessageArgument{ tomwalters@509: public: tomwalters@509: ReceivedMessageArgument( const char *typeTag, const char *argument ) tomwalters@509: : typeTag_( typeTag ) tomwalters@509: , argument_( argument ) {} tomwalters@509: tomwalters@509: friend class ReceivedMessageArgumentIterator; tomwalters@509: tomwalters@509: const char TypeTag() const { return *typeTag_; } tomwalters@509: tomwalters@509: // the unchecked methods below don't check whether the argument actually tomwalters@509: // is of the specified type. they should only be used if you've already tomwalters@509: // checked the type tag or the associated IsType() method. tomwalters@509: tomwalters@509: bool IsBool() const tomwalters@509: { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; } tomwalters@509: bool AsBool() const; tomwalters@509: bool AsBoolUnchecked() const; tomwalters@509: tomwalters@509: bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; } tomwalters@509: bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; } tomwalters@509: tomwalters@509: bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; } tomwalters@509: int32 AsInt32() const; tomwalters@509: int32 AsInt32Unchecked() const; tomwalters@509: tomwalters@509: bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; } tomwalters@509: float AsFloat() const; tomwalters@509: float AsFloatUnchecked() const; tomwalters@509: tomwalters@509: bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; } tomwalters@509: char AsChar() const; tomwalters@509: char AsCharUnchecked() const; tomwalters@509: tomwalters@509: bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; } tomwalters@509: uint32 AsRgbaColor() const; tomwalters@509: uint32 AsRgbaColorUnchecked() const; tomwalters@509: tomwalters@509: bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; } tomwalters@509: uint32 AsMidiMessage() const; tomwalters@509: uint32 AsMidiMessageUnchecked() const; tomwalters@509: tomwalters@509: bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; } tomwalters@509: int64 AsInt64() const; tomwalters@509: int64 AsInt64Unchecked() const; tomwalters@509: tomwalters@509: bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; } tomwalters@509: uint64 AsTimeTag() const; tomwalters@509: uint64 AsTimeTagUnchecked() const; tomwalters@509: tomwalters@509: bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; } tomwalters@509: double AsDouble() const; tomwalters@509: double AsDoubleUnchecked() const; tomwalters@509: tomwalters@509: bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; } tomwalters@509: const char* AsString() const; tomwalters@509: const char* AsStringUnchecked() const { return argument_; } tomwalters@509: tomwalters@509: bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; } tomwalters@509: const char* AsSymbol() const; tomwalters@509: const char* AsSymbolUnchecked() const { return argument_; } tomwalters@509: tomwalters@509: bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; } tomwalters@509: void AsBlob( const void*& data, unsigned long& size ) const; tomwalters@509: void AsBlobUnchecked( const void*& data, unsigned long& size ) const; tomwalters@509: tomwalters@509: private: tomwalters@509: const char *typeTag_; tomwalters@509: const char *argument_; tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedMessageArgumentIterator{ tomwalters@509: public: tomwalters@509: ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) tomwalters@509: : value_( typeTags, arguments ) {} tomwalters@509: tomwalters@509: ReceivedMessageArgumentIterator operator++() tomwalters@509: { tomwalters@509: Advance(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentIterator operator++(int) tomwalters@509: { tomwalters@509: ReceivedMessageArgumentIterator old( *this ); tomwalters@509: Advance(); tomwalters@509: return old; tomwalters@509: } tomwalters@509: tomwalters@509: const ReceivedMessageArgument& operator*() const { return value_; } tomwalters@509: tomwalters@509: const ReceivedMessageArgument* operator->() const { return &value_; } tomwalters@509: tomwalters@509: friend bool operator==(const ReceivedMessageArgumentIterator& lhs, tomwalters@509: const ReceivedMessageArgumentIterator& rhs ); tomwalters@509: tomwalters@509: private: tomwalters@509: ReceivedMessageArgument value_; tomwalters@509: tomwalters@509: void Advance(); tomwalters@509: tomwalters@509: bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const tomwalters@509: { tomwalters@509: return value_.typeTag_ == rhs.value_.typeTag_; tomwalters@509: } tomwalters@509: }; tomwalters@509: tomwalters@509: inline bool operator==(const ReceivedMessageArgumentIterator& lhs, tomwalters@509: const ReceivedMessageArgumentIterator& rhs ) tomwalters@509: { tomwalters@509: return lhs.IsEqualTo( rhs ); tomwalters@509: } tomwalters@509: tomwalters@509: inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, tomwalters@509: const ReceivedMessageArgumentIterator& rhs ) tomwalters@509: { tomwalters@509: return !( lhs == rhs ); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedMessageArgumentStream{ tomwalters@509: friend class ReceivedMessage; tomwalters@509: ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, tomwalters@509: const ReceivedMessageArgumentIterator& end ) tomwalters@509: : p_( begin ) tomwalters@509: , end_( end ) {} tomwalters@509: tomwalters@509: ReceivedMessageArgumentIterator p_, end_; tomwalters@509: tomwalters@509: public: tomwalters@509: tomwalters@509: // end of stream tomwalters@509: bool Eos() const { return p_ == end_; } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( bool& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsBool(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: // not sure if it would be useful to stream Nil and Infinitum tomwalters@509: // for now it's not possible tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( int32& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsInt32(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( float& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsFloat(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( char& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsChar(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs.value = (*p_++).AsRgbaColor(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs.value = (*p_++).AsMidiMessage(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( int64& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsInt64(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs.value = (*p_++).AsTimeTag(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( double& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsDouble(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( Blob& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: (*p_++).AsBlob( rhs.data, rhs.size ); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( const char*& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs = (*p_++).AsString(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) tomwalters@509: { tomwalters@509: if( Eos() ) tomwalters@509: throw MissingArgumentException(); tomwalters@509: tomwalters@509: rhs.value = (*p_++).AsSymbol(); tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) tomwalters@509: { tomwalters@509: if( !Eos() ) tomwalters@509: throw ExcessArgumentException(); tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedMessage{ tomwalters@509: void Init( const char *bundle, unsigned long size ); tomwalters@509: public: tomwalters@509: explicit ReceivedMessage( const ReceivedPacket& packet ); tomwalters@509: explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); tomwalters@509: tomwalters@509: const char *AddressPattern() const { return addressPattern_; } tomwalters@509: tomwalters@509: // Support for non-standad SuperCollider integer address patterns: tomwalters@509: bool AddressPatternIsUInt32() const; tomwalters@509: uint32 AddressPatternAsUInt32() const; tomwalters@509: tomwalters@509: unsigned long ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } tomwalters@509: tomwalters@509: const char *TypeTags() const { return typeTagsBegin_; } tomwalters@509: tomwalters@509: tomwalters@509: typedef ReceivedMessageArgumentIterator const_iterator; tomwalters@509: tomwalters@509: ReceivedMessageArgumentIterator ArgumentsBegin() const tomwalters@509: { tomwalters@509: return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentIterator ArgumentsEnd() const tomwalters@509: { tomwalters@509: return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedMessageArgumentStream ArgumentStream() const tomwalters@509: { tomwalters@509: return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); tomwalters@509: } tomwalters@509: tomwalters@509: private: tomwalters@509: const char *addressPattern_; tomwalters@509: const char *typeTagsBegin_; tomwalters@509: const char *typeTagsEnd_; tomwalters@509: const char *arguments_; tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: class ReceivedBundle{ tomwalters@509: void Init( const char *message, unsigned long size ); tomwalters@509: public: tomwalters@509: explicit ReceivedBundle( const ReceivedPacket& packet ); tomwalters@509: explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); tomwalters@509: tomwalters@509: uint64 TimeTag() const; tomwalters@509: tomwalters@509: unsigned long ElementCount() const { return elementCount_; } tomwalters@509: tomwalters@509: typedef ReceivedBundleElementIterator const_iterator; tomwalters@509: tomwalters@509: ReceivedBundleElementIterator ElementsBegin() const tomwalters@509: { tomwalters@509: return ReceivedBundleElementIterator( timeTag_ + 8 ); tomwalters@509: } tomwalters@509: tomwalters@509: ReceivedBundleElementIterator ElementsEnd() const tomwalters@509: { tomwalters@509: return ReceivedBundleElementIterator( end_ ); tomwalters@509: } tomwalters@509: tomwalters@509: private: tomwalters@509: const char *timeTag_; tomwalters@509: const char *end_; tomwalters@509: unsigned long elementCount_; tomwalters@509: }; tomwalters@509: tomwalters@509: tomwalters@509: } // namespace osc tomwalters@509: tomwalters@509: tomwalters@509: #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */