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