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