37 #include "OscOutboundPacketStream.h"
39 #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
50 #include "OscHostEndianness.h"
52 #if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
60 static void FromInt32(
char *p, int32 x )
62 #ifdef OSC_HOST_LITTLE_ENDIAN
75 *
reinterpret_cast<int32*
>(p) = x;
80 static void FromUInt32(
char *p, uint32 x )
82 #ifdef OSC_HOST_LITTLE_ENDIAN
95 *
reinterpret_cast<uint32*
>(p) = x;
100 static void FromInt64(
char *p, int64 x )
102 #ifdef OSC_HOST_LITTLE_ENDIAN
119 *
reinterpret_cast<int64*
>(p) = x;
124 static void FromUInt64(
char *p, uint64 x )
126 #ifdef OSC_HOST_LITTLE_ENDIAN
143 *
reinterpret_cast<uint64*
>(p) = x;
149 static inline std::size_t RoundUp4( std::size_t x )
151 return (x + 3) & ~((std::size_t)0x03);
155 OutboundPacketStream::OutboundPacketStream(
char *buffer, std::size_t capacity )
157 , end_( data_ + capacity )
158 , typeTagsCurrent_( end_ )
159 , messageCursor_( data_ )
160 , argumentCurrent_( data_ )
161 , elementSizePtr_( 0 )
162 , messageIsInProgress_( false )
166 assert(
sizeof(osc::int32) == 4 );
167 assert(
sizeof(osc::uint32) == 4 );
168 assert(
sizeof(osc::int64) == 8 );
169 assert(
sizeof(osc::uint64) == 8 );
173 OutboundPacketStream::~OutboundPacketStream()
179 char *OutboundPacketStream::BeginElement(
char *beginPtr )
181 if( elementSizePtr_ == 0 ){
183 elementSizePtr_ =
reinterpret_cast<uint32*
>(data_);
190 *
reinterpret_cast<uint32*
>(beginPtr) =
191 (uint32)(
reinterpret_cast<char*
>(elementSizePtr_) - data_);
193 elementSizePtr_ =
reinterpret_cast<uint32*
>(beginPtr);
200 void OutboundPacketStream::EndElement(
char *endPtr )
202 assert( elementSizePtr_ != 0 );
204 if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
212 uint32 *previousElementSizePtr =
213 reinterpret_cast<uint32*
>(data_ + *elementSizePtr_);
218 std::ptrdiff_t d = endPtr -
reinterpret_cast<char*
>(elementSizePtr_);
221 uint32 elementSize =
static_cast<uint32
>(d - 4);
222 FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
225 elementSizePtr_ = previousElementSizePtr;
230 bool OutboundPacketStream::ElementSizeSlotRequired()
const
232 return (elementSizePtr_ != 0);
236 void OutboundPacketStream::CheckForAvailableBundleSpace()
238 std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
240 if( required > Capacity() )
241 throw OutOfBufferMemoryException();
245 void OutboundPacketStream::CheckForAvailableMessageSpace(
const char *addressPattern )
248 std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0)
249 + RoundUp4(std::strlen(addressPattern) + 1) + 4;
251 if( required > Capacity() )
252 throw OutOfBufferMemoryException();
256 void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength )
259 std::size_t required = (argumentCurrent_ - data_) + argumentLength
260 + RoundUp4( (end_ - typeTagsCurrent_) + 3 );
262 if( required > Capacity() )
263 throw OutOfBufferMemoryException();
267 void OutboundPacketStream::Clear()
269 typeTagsCurrent_ = end_;
270 messageCursor_ = data_;
271 argumentCurrent_ = data_;
273 messageIsInProgress_ =
false;
277 std::size_t OutboundPacketStream::Capacity()
const
283 std::size_t OutboundPacketStream::Size()
const
285 std::size_t result = argumentCurrent_ - data_;
286 if( IsMessageInProgress() ){
289 result += RoundUp4( (end_ - typeTagsCurrent_) + 2 );
296 const char *OutboundPacketStream::Data()
const
302 bool OutboundPacketStream::IsReady()
const
304 return (!IsMessageInProgress() && !IsBundleInProgress());
308 bool OutboundPacketStream::IsMessageInProgress()
const
310 return messageIsInProgress_;
314 bool OutboundPacketStream::IsBundleInProgress()
const
316 return (elementSizePtr_ != 0);
320 OutboundPacketStream& OutboundPacketStream::operator<<(
const BundleInitiator& rhs )
322 if( IsMessageInProgress() )
323 throw MessageInProgressException();
325 CheckForAvailableBundleSpace();
327 messageCursor_ = BeginElement( messageCursor_ );
329 std::memcpy( messageCursor_,
"#bundle\0", 8 );
330 FromUInt64( messageCursor_ + 8, rhs.timeTag );
332 messageCursor_ += 16;
333 argumentCurrent_ = messageCursor_;
339 OutboundPacketStream& OutboundPacketStream::operator<<(
const BundleTerminator& rhs )
343 if( !IsBundleInProgress() )
344 throw BundleNotInProgressException();
345 if( IsMessageInProgress() )
346 throw MessageInProgressException();
348 EndElement( messageCursor_ );
354 OutboundPacketStream& OutboundPacketStream::operator<<(
const BeginMessage& rhs )
356 if( IsMessageInProgress() )
357 throw MessageInProgressException();
359 CheckForAvailableMessageSpace( rhs.addressPattern );
361 messageCursor_ = BeginElement( messageCursor_ );
363 std::strcpy( messageCursor_, rhs.addressPattern );
364 std::size_t rhsLength = std::strlen(rhs.addressPattern);
365 messageCursor_ += rhsLength + 1;
368 std::size_t i = rhsLength + 1;
370 *messageCursor_++ =
'\0';
374 argumentCurrent_ = messageCursor_;
375 typeTagsCurrent_ = end_;
377 messageIsInProgress_ =
true;
383 OutboundPacketStream& OutboundPacketStream::operator<<(
const MessageTerminator& rhs )
387 if( !IsMessageInProgress() )
388 throw MessageNotInProgressException();
390 std::size_t typeTagsCount = end_ - typeTagsCurrent_;
394 char *tempTypeTags = (
char*)alloca(typeTagsCount);
395 std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
398 std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
400 std::size_t argumentsSize = argumentCurrent_ - messageCursor_;
402 std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
404 messageCursor_[0] =
',';
406 for( std::size_t i=0; i < typeTagsCount; ++i )
407 messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
409 char *p = messageCursor_ + 1 + typeTagsCount;
410 for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
413 typeTagsCurrent_ = end_;
416 messageCursor_ += typeTagSlotSize + argumentsSize;
420 std::memcpy( messageCursor_,
",\0\0\0", 4 );
426 argumentCurrent_ = messageCursor_;
428 EndElement( messageCursor_ );
430 messageIsInProgress_ =
false;
436 OutboundPacketStream& OutboundPacketStream::operator<<(
bool rhs )
438 CheckForAvailableArgumentSpace(0);
440 *(--typeTagsCurrent_) = (
char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
446 OutboundPacketStream& OutboundPacketStream::operator<<(
const NilType& rhs )
449 CheckForAvailableArgumentSpace(0);
451 *(--typeTagsCurrent_) = NIL_TYPE_TAG;
457 OutboundPacketStream& OutboundPacketStream::operator<<(
const InfinitumType& rhs )
460 CheckForAvailableArgumentSpace(0);
462 *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
468 OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
470 CheckForAvailableArgumentSpace(4);
472 *(--typeTagsCurrent_) = INT32_TYPE_TAG;
473 FromInt32( argumentCurrent_, rhs );
474 argumentCurrent_ += 4;
480 OutboundPacketStream& OutboundPacketStream::operator<<(
float rhs )
482 CheckForAvailableArgumentSpace(4);
484 *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
486 #ifdef OSC_HOST_LITTLE_ENDIAN
494 argumentCurrent_[3] = u.c[0];
495 argumentCurrent_[2] = u.c[1];
496 argumentCurrent_[1] = u.c[2];
497 argumentCurrent_[0] = u.c[3];
499 *
reinterpret_cast<float*
>(argumentCurrent_) = rhs;
502 argumentCurrent_ += 4;
508 OutboundPacketStream& OutboundPacketStream::operator<<(
char rhs )
510 CheckForAvailableArgumentSpace(4);
512 *(--typeTagsCurrent_) = CHAR_TYPE_TAG;
513 FromInt32( argumentCurrent_, rhs );
514 argumentCurrent_ += 4;
520 OutboundPacketStream& OutboundPacketStream::operator<<(
const RgbaColor& rhs )
522 CheckForAvailableArgumentSpace(4);
524 *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
525 FromUInt32( argumentCurrent_, rhs );
526 argumentCurrent_ += 4;
532 OutboundPacketStream& OutboundPacketStream::operator<<(
const MidiMessage& rhs )
534 CheckForAvailableArgumentSpace(4);
536 *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
537 FromUInt32( argumentCurrent_, rhs );
538 argumentCurrent_ += 4;
544 OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
546 CheckForAvailableArgumentSpace(8);
548 *(--typeTagsCurrent_) = INT64_TYPE_TAG;
549 FromInt64( argumentCurrent_, rhs );
550 argumentCurrent_ += 8;
556 OutboundPacketStream& OutboundPacketStream::operator<<(
const TimeTag& rhs )
558 CheckForAvailableArgumentSpace(8);
560 *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
561 FromUInt64( argumentCurrent_, rhs );
562 argumentCurrent_ += 8;
568 OutboundPacketStream& OutboundPacketStream::operator<<(
double rhs )
570 CheckForAvailableArgumentSpace(8);
572 *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
574 #ifdef OSC_HOST_LITTLE_ENDIAN
582 argumentCurrent_[7] = u.c[0];
583 argumentCurrent_[6] = u.c[1];
584 argumentCurrent_[5] = u.c[2];
585 argumentCurrent_[4] = u.c[3];
586 argumentCurrent_[3] = u.c[4];
587 argumentCurrent_[2] = u.c[5];
588 argumentCurrent_[1] = u.c[6];
589 argumentCurrent_[0] = u.c[7];
591 *
reinterpret_cast<double*
>(argumentCurrent_) = rhs;
594 argumentCurrent_ += 8;
600 OutboundPacketStream& OutboundPacketStream::operator<<(
const char *rhs )
602 CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
604 *(--typeTagsCurrent_) = STRING_TYPE_TAG;
605 std::strcpy( argumentCurrent_, rhs );
606 std::size_t rhsLength = std::strlen(rhs);
607 argumentCurrent_ += rhsLength + 1;
610 std::size_t i = rhsLength + 1;
612 *argumentCurrent_++ =
'\0';
620 OutboundPacketStream& OutboundPacketStream::operator<<(
const Symbol& rhs )
622 CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
624 *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
625 std::strcpy( argumentCurrent_, rhs );
626 std::size_t rhsLength = std::strlen(rhs);
627 argumentCurrent_ += rhsLength + 1;
630 std::size_t i = rhsLength + 1;
632 *argumentCurrent_++ =
'\0';
640 OutboundPacketStream& OutboundPacketStream::operator<<(
const Blob& rhs )
642 CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
644 *(--typeTagsCurrent_) = BLOB_TYPE_TAG;
645 FromUInt32( argumentCurrent_, rhs.size );
646 argumentCurrent_ += 4;
648 std::memcpy( argumentCurrent_, rhs.data, rhs.size );
649 argumentCurrent_ += rhs.size;
652 unsigned long i = rhs.size;
654 *argumentCurrent_++ =
'\0';
661 OutboundPacketStream& OutboundPacketStream::operator<<(
const ArrayInitiator& rhs )
664 CheckForAvailableArgumentSpace(0);
666 *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
671 OutboundPacketStream& OutboundPacketStream::operator<<(
const ArrayTerminator& rhs )
674 CheckForAvailableArgumentSpace(0);
676 *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;