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: #include "OscOutboundPacketStream.h" tomwalters@509: tomwalters@509: #include tomwalters@509: #include tomwalters@509: #include tomwalters@509: tomwalters@509: #if defined(__WIN32__) || defined(WIN32) tomwalters@509: #include // for alloca tomwalters@509: #endif tomwalters@509: tomwalters@509: #include "OscHostEndianness.h" tomwalters@509: tomwalters@509: tomwalters@509: namespace osc{ tomwalters@509: tomwalters@509: static void FromInt32( char *p, int32 x ) tomwalters@509: { tomwalters@509: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@509: union{ tomwalters@509: osc::int32 i; tomwalters@509: char c[4]; tomwalters@509: } u; tomwalters@509: tomwalters@509: u.i = x; tomwalters@509: tomwalters@509: p[3] = u.c[0]; tomwalters@509: p[2] = u.c[1]; tomwalters@509: p[1] = u.c[2]; tomwalters@509: p[0] = u.c[3]; tomwalters@509: #else tomwalters@509: *reinterpret_cast(p) = x; tomwalters@509: #endif tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: static void FromUInt32( char *p, uint32 x ) tomwalters@509: { tomwalters@509: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@509: union{ tomwalters@509: osc::uint32 i; tomwalters@509: char c[4]; tomwalters@509: } u; tomwalters@509: tomwalters@509: u.i = x; tomwalters@509: tomwalters@509: p[3] = u.c[0]; tomwalters@509: p[2] = u.c[1]; tomwalters@509: p[1] = u.c[2]; tomwalters@509: p[0] = u.c[3]; tomwalters@509: #else tomwalters@509: *reinterpret_cast(p) = x; tomwalters@509: #endif tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: static void FromInt64( char *p, int64 x ) tomwalters@509: { tomwalters@509: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@509: union{ tomwalters@509: osc::int64 i; tomwalters@509: char c[8]; tomwalters@509: } u; tomwalters@509: tomwalters@509: u.i = x; tomwalters@509: tomwalters@509: p[7] = u.c[0]; tomwalters@509: p[6] = u.c[1]; tomwalters@509: p[5] = u.c[2]; tomwalters@509: p[4] = u.c[3]; tomwalters@509: p[3] = u.c[4]; tomwalters@509: p[2] = u.c[5]; tomwalters@509: p[1] = u.c[6]; tomwalters@509: p[0] = u.c[7]; tomwalters@509: #else tomwalters@509: *reinterpret_cast(p) = x; tomwalters@509: #endif tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: static void FromUInt64( char *p, uint64 x ) tomwalters@509: { tomwalters@509: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@509: union{ tomwalters@509: osc::uint64 i; tomwalters@509: char c[8]; tomwalters@509: } u; tomwalters@509: tomwalters@509: u.i = x; tomwalters@509: tomwalters@509: p[7] = u.c[0]; tomwalters@509: p[6] = u.c[1]; tomwalters@509: p[5] = u.c[2]; tomwalters@509: p[4] = u.c[3]; tomwalters@509: p[3] = u.c[4]; tomwalters@509: p[2] = u.c[5]; tomwalters@509: p[1] = u.c[6]; tomwalters@509: p[0] = u.c[7]; tomwalters@509: #else tomwalters@509: *reinterpret_cast(p) = x; tomwalters@509: #endif tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: static inline long RoundUp4( long x ) tomwalters@509: { tomwalters@509: return ((x-1) & (~0x03L)) + 4; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity ) tomwalters@509: : data_( buffer ) tomwalters@509: , end_( data_ + capacity ) tomwalters@509: , typeTagsCurrent_( end_ ) tomwalters@509: , messageCursor_( data_ ) tomwalters@509: , argumentCurrent_( data_ ) tomwalters@509: , elementSizePtr_( 0 ) tomwalters@509: , messageIsInProgress_( false ) tomwalters@509: { tomwalters@509: tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream::~OutboundPacketStream() tomwalters@509: { tomwalters@509: tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: char *OutboundPacketStream::BeginElement( char *beginPtr ) tomwalters@509: { tomwalters@509: if( elementSizePtr_ == 0 ){ tomwalters@509: tomwalters@509: elementSizePtr_ = reinterpret_cast(data_); tomwalters@509: tomwalters@509: return beginPtr; tomwalters@509: tomwalters@509: }else{ tomwalters@509: // store an offset to the old element size ptr in the element size slot tomwalters@509: // we store an offset rather than the actual pointer to be 64 bit clean. tomwalters@509: *reinterpret_cast(beginPtr) = tomwalters@509: (uint32)(reinterpret_cast(elementSizePtr_) - data_); tomwalters@509: tomwalters@509: elementSizePtr_ = reinterpret_cast(beginPtr); tomwalters@509: tomwalters@509: return beginPtr + 4; tomwalters@509: } tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: void OutboundPacketStream::EndElement( char *endPtr ) tomwalters@509: { tomwalters@509: assert( elementSizePtr_ != 0 ); tomwalters@509: tomwalters@509: if( elementSizePtr_ == reinterpret_cast(data_) ){ tomwalters@509: tomwalters@509: elementSizePtr_ = 0; tomwalters@509: tomwalters@509: }else{ tomwalters@509: // while building an element, an offset to the containing element's tomwalters@509: // size slot is stored in the elements size slot (or a ptr to data_ tomwalters@509: // if there is no containing element). We retrieve that here tomwalters@509: uint32 *previousElementSizePtr = tomwalters@509: (uint32*)(data_ + *reinterpret_cast(elementSizePtr_)); tomwalters@509: tomwalters@509: // then we store the element size in the slot, note that the element tomwalters@509: // size does not include the size slot, hence the - 4 below. tomwalters@509: uint32 elementSize = tomwalters@509: (endPtr - reinterpret_cast(elementSizePtr_)) - 4; tomwalters@509: FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); tomwalters@509: tomwalters@509: // finally, we reset the element size ptr to the containing element tomwalters@509: elementSizePtr_ = previousElementSizePtr; tomwalters@509: } tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: bool OutboundPacketStream::ElementSizeSlotRequired() const tomwalters@509: { tomwalters@509: return (elementSizePtr_ != 0); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: void OutboundPacketStream::CheckForAvailableBundleSpace() tomwalters@509: { tomwalters@509: unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; tomwalters@509: tomwalters@509: if( required > Capacity() ) tomwalters@509: throw OutOfBufferMemoryException(); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) tomwalters@509: { tomwalters@509: // plus 4 for at least four bytes of type tag tomwalters@509: unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) tomwalters@509: + RoundUp4(strlen(addressPattern) + 1) + 4; tomwalters@509: tomwalters@509: if( required > Capacity() ) tomwalters@509: throw OutOfBufferMemoryException(); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength ) tomwalters@509: { tomwalters@509: // plus three for extra type tag, comma and null terminator tomwalters@509: unsigned long required = (argumentCurrent_ - data_) + argumentLength tomwalters@509: + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); tomwalters@509: tomwalters@509: if( required > Capacity() ) tomwalters@509: throw OutOfBufferMemoryException(); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: void OutboundPacketStream::Clear() tomwalters@509: { tomwalters@509: typeTagsCurrent_ = end_; tomwalters@509: messageCursor_ = data_; tomwalters@509: argumentCurrent_ = data_; tomwalters@509: elementSizePtr_ = 0; tomwalters@509: messageIsInProgress_ = false; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: unsigned int OutboundPacketStream::Capacity() const tomwalters@509: { tomwalters@509: return end_ - data_; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: unsigned int OutboundPacketStream::Size() const tomwalters@509: { tomwalters@509: unsigned int result = argumentCurrent_ - data_; tomwalters@509: if( IsMessageInProgress() ){ tomwalters@509: // account for the length of the type tag string. the total type tag tomwalters@509: // includes an initial comma, plus at least one terminating \0 tomwalters@509: result += RoundUp4( (end_ - typeTagsCurrent_) + 2 ); tomwalters@509: } tomwalters@509: tomwalters@509: return result; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: const char *OutboundPacketStream::Data() const tomwalters@509: { tomwalters@509: return data_; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: bool OutboundPacketStream::IsReady() const tomwalters@509: { tomwalters@509: return (!IsMessageInProgress() && !IsBundleInProgress()); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: bool OutboundPacketStream::IsMessageInProgress() const tomwalters@509: { tomwalters@509: return messageIsInProgress_; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: bool OutboundPacketStream::IsBundleInProgress() const tomwalters@509: { tomwalters@509: return (elementSizePtr_ != 0); tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) tomwalters@509: { tomwalters@509: if( IsMessageInProgress() ) tomwalters@509: throw MessageInProgressException(); tomwalters@509: tomwalters@509: CheckForAvailableBundleSpace(); tomwalters@509: tomwalters@509: messageCursor_ = BeginElement( messageCursor_ ); tomwalters@509: tomwalters@509: memcpy( messageCursor_, "#bundle\0", 8 ); tomwalters@509: FromUInt64( messageCursor_ + 8, rhs.timeTag ); tomwalters@509: tomwalters@509: messageCursor_ += 16; tomwalters@509: argumentCurrent_ = messageCursor_; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs ) tomwalters@509: { tomwalters@509: (void) rhs; tomwalters@509: tomwalters@509: if( !IsBundleInProgress() ) tomwalters@509: throw BundleNotInProgressException(); tomwalters@509: if( IsMessageInProgress() ) tomwalters@509: throw MessageInProgressException(); tomwalters@509: tomwalters@509: EndElement( messageCursor_ ); tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) tomwalters@509: { tomwalters@509: if( IsMessageInProgress() ) tomwalters@509: throw MessageInProgressException(); tomwalters@509: tomwalters@509: CheckForAvailableMessageSpace( rhs.addressPattern ); tomwalters@509: tomwalters@509: messageCursor_ = BeginElement( messageCursor_ ); tomwalters@509: tomwalters@509: strcpy( messageCursor_, rhs.addressPattern ); tomwalters@509: unsigned long rhsLength = strlen(rhs.addressPattern); tomwalters@509: messageCursor_ += rhsLength + 1; tomwalters@509: tomwalters@509: // zero pad to 4-byte boundary tomwalters@509: unsigned long i = rhsLength + 1; tomwalters@509: while( i & 0x3 ){ tomwalters@509: *messageCursor_++ = '\0'; tomwalters@509: ++i; tomwalters@509: } tomwalters@509: tomwalters@509: argumentCurrent_ = messageCursor_; tomwalters@509: typeTagsCurrent_ = end_; tomwalters@509: tomwalters@509: messageIsInProgress_ = true; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs ) tomwalters@509: { tomwalters@509: (void) rhs; tomwalters@509: tomwalters@509: if( !IsMessageInProgress() ) tomwalters@509: throw MessageNotInProgressException(); tomwalters@509: tomwalters@509: int typeTagsCount = end_ - typeTagsCurrent_; tomwalters@509: tomwalters@509: if( typeTagsCount ){ tomwalters@509: tomwalters@509: char *tempTypeTags = (char*)alloca(typeTagsCount); tomwalters@509: memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); tomwalters@509: tomwalters@509: // slot size includes comma and null terminator tomwalters@509: int typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); tomwalters@509: tomwalters@509: uint32 argumentsSize = argumentCurrent_ - messageCursor_; tomwalters@509: tomwalters@509: memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); tomwalters@509: tomwalters@509: messageCursor_[0] = ','; tomwalters@509: // copy type tags in reverse (really forward) order tomwalters@509: for( int i=0; i < typeTagsCount; ++i ) tomwalters@509: messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; tomwalters@509: tomwalters@509: char *p = messageCursor_ + 1 + typeTagsCount; tomwalters@509: for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) tomwalters@509: *p++ = '\0'; tomwalters@509: tomwalters@509: typeTagsCurrent_ = end_; tomwalters@509: tomwalters@509: // advance messageCursor_ for next message tomwalters@509: messageCursor_ += typeTagSlotSize + argumentsSize; tomwalters@509: tomwalters@509: }else{ tomwalters@509: // send an empty type tags string tomwalters@509: memcpy( messageCursor_, ",\0\0\0", 4 ); tomwalters@509: tomwalters@509: // advance messageCursor_ for next message tomwalters@509: messageCursor_ += 4; tomwalters@509: } tomwalters@509: tomwalters@509: argumentCurrent_ = messageCursor_; tomwalters@509: tomwalters@509: EndElement( messageCursor_ ); tomwalters@509: tomwalters@509: messageIsInProgress_ = false; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(0); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG); tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) tomwalters@509: { tomwalters@509: (void) rhs; tomwalters@509: CheckForAvailableArgumentSpace(0); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = NIL_TYPE_TAG; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) tomwalters@509: { tomwalters@509: (void) rhs; tomwalters@509: CheckForAvailableArgumentSpace(0); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(4); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = INT32_TYPE_TAG; tomwalters@509: FromInt32( argumentCurrent_, rhs ); tomwalters@509: argumentCurrent_ += 4; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(4); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = FLOAT_TYPE_TAG; tomwalters@509: tomwalters@509: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@509: union{ tomwalters@509: float f; tomwalters@509: char c[4]; tomwalters@509: } u; tomwalters@509: tomwalters@509: u.f = rhs; tomwalters@509: tomwalters@509: argumentCurrent_[3] = u.c[0]; tomwalters@509: argumentCurrent_[2] = u.c[1]; tomwalters@509: argumentCurrent_[1] = u.c[2]; tomwalters@509: argumentCurrent_[0] = u.c[3]; tomwalters@509: #else tomwalters@509: *reinterpret_cast(argumentCurrent_) = rhs; tomwalters@509: #endif tomwalters@509: tomwalters@509: argumentCurrent_ += 4; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(4); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = CHAR_TYPE_TAG; tomwalters@509: FromInt32( argumentCurrent_, rhs ); tomwalters@509: argumentCurrent_ += 4; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(4); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG; tomwalters@509: FromUInt32( argumentCurrent_, rhs ); tomwalters@509: argumentCurrent_ += 4; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(4); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG; tomwalters@509: FromUInt32( argumentCurrent_, rhs ); tomwalters@509: argumentCurrent_ += 4; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(8); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = INT64_TYPE_TAG; tomwalters@509: FromInt64( argumentCurrent_, rhs ); tomwalters@509: argumentCurrent_ += 8; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(8); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG; tomwalters@509: FromUInt64( argumentCurrent_, rhs ); tomwalters@509: argumentCurrent_ += 8; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace(8); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG; tomwalters@509: tomwalters@509: #ifdef OSC_HOST_LITTLE_ENDIAN tomwalters@509: union{ tomwalters@509: double f; tomwalters@509: char c[8]; tomwalters@509: } u; tomwalters@509: tomwalters@509: u.f = rhs; tomwalters@509: tomwalters@509: argumentCurrent_[7] = u.c[0]; tomwalters@509: argumentCurrent_[6] = u.c[1]; tomwalters@509: argumentCurrent_[5] = u.c[2]; tomwalters@509: argumentCurrent_[4] = u.c[3]; tomwalters@509: argumentCurrent_[3] = u.c[4]; tomwalters@509: argumentCurrent_[2] = u.c[5]; tomwalters@509: argumentCurrent_[1] = u.c[6]; tomwalters@509: argumentCurrent_[0] = u.c[7]; tomwalters@509: #else tomwalters@509: *reinterpret_cast(argumentCurrent_) = rhs; tomwalters@509: #endif tomwalters@509: tomwalters@509: argumentCurrent_ += 8; tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) ); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = STRING_TYPE_TAG; tomwalters@509: strcpy( argumentCurrent_, rhs ); tomwalters@509: unsigned long rhsLength = strlen(rhs); tomwalters@509: argumentCurrent_ += rhsLength + 1; tomwalters@509: tomwalters@509: // zero pad to 4-byte boundary tomwalters@509: unsigned long i = rhsLength + 1; tomwalters@509: while( i & 0x3 ){ tomwalters@509: *argumentCurrent_++ = '\0'; tomwalters@509: ++i; tomwalters@509: } tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) ); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; tomwalters@509: strcpy( argumentCurrent_, rhs ); tomwalters@509: unsigned long rhsLength = strlen(rhs); tomwalters@509: argumentCurrent_ += rhsLength + 1; tomwalters@509: tomwalters@509: // zero pad to 4-byte boundary tomwalters@509: unsigned long i = rhsLength + 1; tomwalters@509: while( i & 0x3 ){ tomwalters@509: *argumentCurrent_++ = '\0'; tomwalters@509: ++i; tomwalters@509: } tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: tomwalters@509: OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) tomwalters@509: { tomwalters@509: CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); tomwalters@509: tomwalters@509: *(--typeTagsCurrent_) = BLOB_TYPE_TAG; tomwalters@509: FromUInt32( argumentCurrent_, rhs.size ); tomwalters@509: argumentCurrent_ += 4; tomwalters@509: tomwalters@509: memcpy( argumentCurrent_, rhs.data, rhs.size ); tomwalters@509: argumentCurrent_ += rhs.size; tomwalters@509: tomwalters@509: // zero pad to 4-byte boundary tomwalters@509: unsigned long i = rhs.size; tomwalters@509: while( i & 0x3 ){ tomwalters@509: *argumentCurrent_++ = '\0'; tomwalters@509: ++i; tomwalters@509: } tomwalters@509: tomwalters@509: return *this; tomwalters@509: } tomwalters@509: tomwalters@509: } // namespace osc tomwalters@509: tomwalters@509: