annotate oscpack/osc/OscOutboundPacketStream.cpp @ 101:52e44ee1c791 tip master

enabled all scores in autostart script
author Rob Canning <rc@kiben.net>
date Tue, 21 Apr 2015 16:20:57 +0100
parents 0ae87af84e2f
children
rev   line source
rob@76 1 /*
rob@76 2 oscpack -- Open Sound Control (OSC) packet manipulation library
rob@76 3 http://www.rossbencina.com/code/oscpack
rob@76 4
rob@76 5 Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
rob@76 6
rob@76 7 Permission is hereby granted, free of charge, to any person obtaining
rob@76 8 a copy of this software and associated documentation files
rob@76 9 (the "Software"), to deal in the Software without restriction,
rob@76 10 including without limitation the rights to use, copy, modify, merge,
rob@76 11 publish, distribute, sublicense, and/or sell copies of the Software,
rob@76 12 and to permit persons to whom the Software is furnished to do so,
rob@76 13 subject to the following conditions:
rob@76 14
rob@76 15 The above copyright notice and this permission notice shall be
rob@76 16 included in all copies or substantial portions of the Software.
rob@76 17
rob@76 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
rob@76 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
rob@76 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
rob@76 21 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
rob@76 22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
rob@76 23 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
rob@76 24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
rob@76 25 */
rob@76 26
rob@76 27 /*
rob@76 28 The text above constitutes the entire oscpack license; however,
rob@76 29 the oscpack developer(s) also make the following non-binding requests:
rob@76 30
rob@76 31 Any person wishing to distribute modifications to the Software is
rob@76 32 requested to send the modifications to the original developer so that
rob@76 33 they can be incorporated into the canonical version. It is also
rob@76 34 requested that these non-binding requests be included whenever the
rob@76 35 above license is reproduced.
rob@76 36 */
rob@76 37 #include "OscOutboundPacketStream.h"
rob@76 38
rob@76 39 #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
rob@76 40 #include <malloc.h> // for alloca
rob@76 41 #else
rob@76 42 //#include <alloca.h> // alloca on Linux (also OSX)
rob@76 43 #include <stdlib.h> // alloca on OSX and FreeBSD (and Linux?)
rob@76 44 #endif
rob@76 45
rob@76 46 #include <cassert>
rob@76 47 #include <cstring> // memcpy, memmove, strcpy, strlen
rob@76 48 #include <cstddef> // ptrdiff_t
rob@76 49
rob@76 50 #include "OscHostEndianness.h"
rob@76 51
rob@76 52 #if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
rob@76 53 namespace std {
rob@76 54 using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
rob@76 55 }
rob@76 56 #endif
rob@76 57
rob@76 58 namespace osc{
rob@76 59
rob@76 60 static void FromInt32( char *p, int32 x )
rob@76 61 {
rob@76 62 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 63 union{
rob@76 64 osc::int32 i;
rob@76 65 char c[4];
rob@76 66 } u;
rob@76 67
rob@76 68 u.i = x;
rob@76 69
rob@76 70 p[3] = u.c[0];
rob@76 71 p[2] = u.c[1];
rob@76 72 p[1] = u.c[2];
rob@76 73 p[0] = u.c[3];
rob@76 74 #else
rob@76 75 *reinterpret_cast<int32*>(p) = x;
rob@76 76 #endif
rob@76 77 }
rob@76 78
rob@76 79
rob@76 80 static void FromUInt32( char *p, uint32 x )
rob@76 81 {
rob@76 82 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 83 union{
rob@76 84 osc::uint32 i;
rob@76 85 char c[4];
rob@76 86 } u;
rob@76 87
rob@76 88 u.i = x;
rob@76 89
rob@76 90 p[3] = u.c[0];
rob@76 91 p[2] = u.c[1];
rob@76 92 p[1] = u.c[2];
rob@76 93 p[0] = u.c[3];
rob@76 94 #else
rob@76 95 *reinterpret_cast<uint32*>(p) = x;
rob@76 96 #endif
rob@76 97 }
rob@76 98
rob@76 99
rob@76 100 static void FromInt64( char *p, int64 x )
rob@76 101 {
rob@76 102 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 103 union{
rob@76 104 osc::int64 i;
rob@76 105 char c[8];
rob@76 106 } u;
rob@76 107
rob@76 108 u.i = x;
rob@76 109
rob@76 110 p[7] = u.c[0];
rob@76 111 p[6] = u.c[1];
rob@76 112 p[5] = u.c[2];
rob@76 113 p[4] = u.c[3];
rob@76 114 p[3] = u.c[4];
rob@76 115 p[2] = u.c[5];
rob@76 116 p[1] = u.c[6];
rob@76 117 p[0] = u.c[7];
rob@76 118 #else
rob@76 119 *reinterpret_cast<int64*>(p) = x;
rob@76 120 #endif
rob@76 121 }
rob@76 122
rob@76 123
rob@76 124 static void FromUInt64( char *p, uint64 x )
rob@76 125 {
rob@76 126 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 127 union{
rob@76 128 osc::uint64 i;
rob@76 129 char c[8];
rob@76 130 } u;
rob@76 131
rob@76 132 u.i = x;
rob@76 133
rob@76 134 p[7] = u.c[0];
rob@76 135 p[6] = u.c[1];
rob@76 136 p[5] = u.c[2];
rob@76 137 p[4] = u.c[3];
rob@76 138 p[3] = u.c[4];
rob@76 139 p[2] = u.c[5];
rob@76 140 p[1] = u.c[6];
rob@76 141 p[0] = u.c[7];
rob@76 142 #else
rob@76 143 *reinterpret_cast<uint64*>(p) = x;
rob@76 144 #endif
rob@76 145 }
rob@76 146
rob@76 147
rob@76 148 // round up to the next highest multiple of 4. unless x is already a multiple of 4
rob@76 149 static inline std::size_t RoundUp4( std::size_t x )
rob@76 150 {
rob@76 151 return (x + 3) & ~((std::size_t)0x03);
rob@76 152 }
rob@76 153
rob@76 154
rob@76 155 OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
rob@76 156 : data_( buffer )
rob@76 157 , end_( data_ + capacity )
rob@76 158 , typeTagsCurrent_( end_ )
rob@76 159 , messageCursor_( data_ )
rob@76 160 , argumentCurrent_( data_ )
rob@76 161 , elementSizePtr_( 0 )
rob@76 162 , messageIsInProgress_( false )
rob@76 163 {
rob@76 164 // sanity check integer types declared in OscTypes.h
rob@76 165 // you'll need to fix OscTypes.h if any of these asserts fail
rob@76 166 assert( sizeof(osc::int32) == 4 );
rob@76 167 assert( sizeof(osc::uint32) == 4 );
rob@76 168 assert( sizeof(osc::int64) == 8 );
rob@76 169 assert( sizeof(osc::uint64) == 8 );
rob@76 170 }
rob@76 171
rob@76 172
rob@76 173 OutboundPacketStream::~OutboundPacketStream()
rob@76 174 {
rob@76 175
rob@76 176 }
rob@76 177
rob@76 178
rob@76 179 char *OutboundPacketStream::BeginElement( char *beginPtr )
rob@76 180 {
rob@76 181 if( elementSizePtr_ == 0 ){
rob@76 182
rob@76 183 elementSizePtr_ = reinterpret_cast<uint32*>(data_);
rob@76 184
rob@76 185 return beginPtr;
rob@76 186
rob@76 187 }else{
rob@76 188 // store an offset to the old element size ptr in the element size slot
rob@76 189 // we store an offset rather than the actual pointer to be 64 bit clean.
rob@76 190 *reinterpret_cast<uint32*>(beginPtr) =
rob@76 191 (uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
rob@76 192
rob@76 193 elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
rob@76 194
rob@76 195 return beginPtr + 4;
rob@76 196 }
rob@76 197 }
rob@76 198
rob@76 199
rob@76 200 void OutboundPacketStream::EndElement( char *endPtr )
rob@76 201 {
rob@76 202 assert( elementSizePtr_ != 0 );
rob@76 203
rob@76 204 if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
rob@76 205
rob@76 206 elementSizePtr_ = 0;
rob@76 207
rob@76 208 }else{
rob@76 209 // while building an element, an offset to the containing element's
rob@76 210 // size slot is stored in the elements size slot (or a ptr to data_
rob@76 211 // if there is no containing element). We retrieve that here
rob@76 212 uint32 *previousElementSizePtr =
rob@76 213 reinterpret_cast<uint32*>(data_ + *elementSizePtr_);
rob@76 214
rob@76 215 // then we store the element size in the slot. note that the element
rob@76 216 // size does not include the size slot, hence the - 4 below.
rob@76 217
rob@76 218 std::ptrdiff_t d = endPtr - reinterpret_cast<char*>(elementSizePtr_);
rob@76 219 // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb
rob@76 220
rob@76 221 uint32 elementSize = static_cast<uint32>(d - 4);
rob@76 222 FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
rob@76 223
rob@76 224 // finally, we reset the element size ptr to the containing element
rob@76 225 elementSizePtr_ = previousElementSizePtr;
rob@76 226 }
rob@76 227 }
rob@76 228
rob@76 229
rob@76 230 bool OutboundPacketStream::ElementSizeSlotRequired() const
rob@76 231 {
rob@76 232 return (elementSizePtr_ != 0);
rob@76 233 }
rob@76 234
rob@76 235
rob@76 236 void OutboundPacketStream::CheckForAvailableBundleSpace()
rob@76 237 {
rob@76 238 std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
rob@76 239
rob@76 240 if( required > Capacity() )
rob@76 241 throw OutOfBufferMemoryException();
rob@76 242 }
rob@76 243
rob@76 244
rob@76 245 void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
rob@76 246 {
rob@76 247 // plus 4 for at least four bytes of type tag
rob@76 248 std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0)
rob@76 249 + RoundUp4(std::strlen(addressPattern) + 1) + 4;
rob@76 250
rob@76 251 if( required > Capacity() )
rob@76 252 throw OutOfBufferMemoryException();
rob@76 253 }
rob@76 254
rob@76 255
rob@76 256 void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength )
rob@76 257 {
rob@76 258 // plus three for extra type tag, comma and null terminator
rob@76 259 std::size_t required = (argumentCurrent_ - data_) + argumentLength
rob@76 260 + RoundUp4( (end_ - typeTagsCurrent_) + 3 );
rob@76 261
rob@76 262 if( required > Capacity() )
rob@76 263 throw OutOfBufferMemoryException();
rob@76 264 }
rob@76 265
rob@76 266
rob@76 267 void OutboundPacketStream::Clear()
rob@76 268 {
rob@76 269 typeTagsCurrent_ = end_;
rob@76 270 messageCursor_ = data_;
rob@76 271 argumentCurrent_ = data_;
rob@76 272 elementSizePtr_ = 0;
rob@76 273 messageIsInProgress_ = false;
rob@76 274 }
rob@76 275
rob@76 276
rob@76 277 std::size_t OutboundPacketStream::Capacity() const
rob@76 278 {
rob@76 279 return end_ - data_;
rob@76 280 }
rob@76 281
rob@76 282
rob@76 283 std::size_t OutboundPacketStream::Size() const
rob@76 284 {
rob@76 285 std::size_t result = argumentCurrent_ - data_;
rob@76 286 if( IsMessageInProgress() ){
rob@76 287 // account for the length of the type tag string. the total type tag
rob@76 288 // includes an initial comma, plus at least one terminating \0
rob@76 289 result += RoundUp4( (end_ - typeTagsCurrent_) + 2 );
rob@76 290 }
rob@76 291
rob@76 292 return result;
rob@76 293 }
rob@76 294
rob@76 295
rob@76 296 const char *OutboundPacketStream::Data() const
rob@76 297 {
rob@76 298 return data_;
rob@76 299 }
rob@76 300
rob@76 301
rob@76 302 bool OutboundPacketStream::IsReady() const
rob@76 303 {
rob@76 304 return (!IsMessageInProgress() && !IsBundleInProgress());
rob@76 305 }
rob@76 306
rob@76 307
rob@76 308 bool OutboundPacketStream::IsMessageInProgress() const
rob@76 309 {
rob@76 310 return messageIsInProgress_;
rob@76 311 }
rob@76 312
rob@76 313
rob@76 314 bool OutboundPacketStream::IsBundleInProgress() const
rob@76 315 {
rob@76 316 return (elementSizePtr_ != 0);
rob@76 317 }
rob@76 318
rob@76 319
rob@76 320 OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
rob@76 321 {
rob@76 322 if( IsMessageInProgress() )
rob@76 323 throw MessageInProgressException();
rob@76 324
rob@76 325 CheckForAvailableBundleSpace();
rob@76 326
rob@76 327 messageCursor_ = BeginElement( messageCursor_ );
rob@76 328
rob@76 329 std::memcpy( messageCursor_, "#bundle\0", 8 );
rob@76 330 FromUInt64( messageCursor_ + 8, rhs.timeTag );
rob@76 331
rob@76 332 messageCursor_ += 16;
rob@76 333 argumentCurrent_ = messageCursor_;
rob@76 334
rob@76 335 return *this;
rob@76 336 }
rob@76 337
rob@76 338
rob@76 339 OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )
rob@76 340 {
rob@76 341 (void) rhs;
rob@76 342
rob@76 343 if( !IsBundleInProgress() )
rob@76 344 throw BundleNotInProgressException();
rob@76 345 if( IsMessageInProgress() )
rob@76 346 throw MessageInProgressException();
rob@76 347
rob@76 348 EndElement( messageCursor_ );
rob@76 349
rob@76 350 return *this;
rob@76 351 }
rob@76 352
rob@76 353
rob@76 354 OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
rob@76 355 {
rob@76 356 if( IsMessageInProgress() )
rob@76 357 throw MessageInProgressException();
rob@76 358
rob@76 359 CheckForAvailableMessageSpace( rhs.addressPattern );
rob@76 360
rob@76 361 messageCursor_ = BeginElement( messageCursor_ );
rob@76 362
rob@76 363 std::strcpy( messageCursor_, rhs.addressPattern );
rob@76 364 std::size_t rhsLength = std::strlen(rhs.addressPattern);
rob@76 365 messageCursor_ += rhsLength + 1;
rob@76 366
rob@76 367 // zero pad to 4-byte boundary
rob@76 368 std::size_t i = rhsLength + 1;
rob@76 369 while( i & 0x3 ){
rob@76 370 *messageCursor_++ = '\0';
rob@76 371 ++i;
rob@76 372 }
rob@76 373
rob@76 374 argumentCurrent_ = messageCursor_;
rob@76 375 typeTagsCurrent_ = end_;
rob@76 376
rob@76 377 messageIsInProgress_ = true;
rob@76 378
rob@76 379 return *this;
rob@76 380 }
rob@76 381
rob@76 382
rob@76 383 OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )
rob@76 384 {
rob@76 385 (void) rhs;
rob@76 386
rob@76 387 if( !IsMessageInProgress() )
rob@76 388 throw MessageNotInProgressException();
rob@76 389
rob@76 390 std::size_t typeTagsCount = end_ - typeTagsCurrent_;
rob@76 391
rob@76 392 if( typeTagsCount ){
rob@76 393
rob@76 394 char *tempTypeTags = (char*)alloca(typeTagsCount);
rob@76 395 std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
rob@76 396
rob@76 397 // slot size includes comma and null terminator
rob@76 398 std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
rob@76 399
rob@76 400 std::size_t argumentsSize = argumentCurrent_ - messageCursor_;
rob@76 401
rob@76 402 std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
rob@76 403
rob@76 404 messageCursor_[0] = ',';
rob@76 405 // copy type tags in reverse (really forward) order
rob@76 406 for( std::size_t i=0; i < typeTagsCount; ++i )
rob@76 407 messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
rob@76 408
rob@76 409 char *p = messageCursor_ + 1 + typeTagsCount;
rob@76 410 for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
rob@76 411 *p++ = '\0';
rob@76 412
rob@76 413 typeTagsCurrent_ = end_;
rob@76 414
rob@76 415 // advance messageCursor_ for next message
rob@76 416 messageCursor_ += typeTagSlotSize + argumentsSize;
rob@76 417
rob@76 418 }else{
rob@76 419 // send an empty type tags string
rob@76 420 std::memcpy( messageCursor_, ",\0\0\0", 4 );
rob@76 421
rob@76 422 // advance messageCursor_ for next message
rob@76 423 messageCursor_ += 4;
rob@76 424 }
rob@76 425
rob@76 426 argumentCurrent_ = messageCursor_;
rob@76 427
rob@76 428 EndElement( messageCursor_ );
rob@76 429
rob@76 430 messageIsInProgress_ = false;
rob@76 431
rob@76 432 return *this;
rob@76 433 }
rob@76 434
rob@76 435
rob@76 436 OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
rob@76 437 {
rob@76 438 CheckForAvailableArgumentSpace(0);
rob@76 439
rob@76 440 *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
rob@76 441
rob@76 442 return *this;
rob@76 443 }
rob@76 444
rob@76 445
rob@76 446 OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
rob@76 447 {
rob@76 448 (void) rhs;
rob@76 449 CheckForAvailableArgumentSpace(0);
rob@76 450
rob@76 451 *(--typeTagsCurrent_) = NIL_TYPE_TAG;
rob@76 452
rob@76 453 return *this;
rob@76 454 }
rob@76 455
rob@76 456
rob@76 457 OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
rob@76 458 {
rob@76 459 (void) rhs;
rob@76 460 CheckForAvailableArgumentSpace(0);
rob@76 461
rob@76 462 *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
rob@76 463
rob@76 464 return *this;
rob@76 465 }
rob@76 466
rob@76 467
rob@76 468 OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
rob@76 469 {
rob@76 470 CheckForAvailableArgumentSpace(4);
rob@76 471
rob@76 472 *(--typeTagsCurrent_) = INT32_TYPE_TAG;
rob@76 473 FromInt32( argumentCurrent_, rhs );
rob@76 474 argumentCurrent_ += 4;
rob@76 475
rob@76 476 return *this;
rob@76 477 }
rob@76 478
rob@76 479
rob@76 480 OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
rob@76 481 {
rob@76 482 CheckForAvailableArgumentSpace(4);
rob@76 483
rob@76 484 *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
rob@76 485
rob@76 486 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 487 union{
rob@76 488 float f;
rob@76 489 char c[4];
rob@76 490 } u;
rob@76 491
rob@76 492 u.f = rhs;
rob@76 493
rob@76 494 argumentCurrent_[3] = u.c[0];
rob@76 495 argumentCurrent_[2] = u.c[1];
rob@76 496 argumentCurrent_[1] = u.c[2];
rob@76 497 argumentCurrent_[0] = u.c[3];
rob@76 498 #else
rob@76 499 *reinterpret_cast<float*>(argumentCurrent_) = rhs;
rob@76 500 #endif
rob@76 501
rob@76 502 argumentCurrent_ += 4;
rob@76 503
rob@76 504 return *this;
rob@76 505 }
rob@76 506
rob@76 507
rob@76 508 OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
rob@76 509 {
rob@76 510 CheckForAvailableArgumentSpace(4);
rob@76 511
rob@76 512 *(--typeTagsCurrent_) = CHAR_TYPE_TAG;
rob@76 513 FromInt32( argumentCurrent_, rhs );
rob@76 514 argumentCurrent_ += 4;
rob@76 515
rob@76 516 return *this;
rob@76 517 }
rob@76 518
rob@76 519
rob@76 520 OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
rob@76 521 {
rob@76 522 CheckForAvailableArgumentSpace(4);
rob@76 523
rob@76 524 *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
rob@76 525 FromUInt32( argumentCurrent_, rhs );
rob@76 526 argumentCurrent_ += 4;
rob@76 527
rob@76 528 return *this;
rob@76 529 }
rob@76 530
rob@76 531
rob@76 532 OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
rob@76 533 {
rob@76 534 CheckForAvailableArgumentSpace(4);
rob@76 535
rob@76 536 *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
rob@76 537 FromUInt32( argumentCurrent_, rhs );
rob@76 538 argumentCurrent_ += 4;
rob@76 539
rob@76 540 return *this;
rob@76 541 }
rob@76 542
rob@76 543
rob@76 544 OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
rob@76 545 {
rob@76 546 CheckForAvailableArgumentSpace(8);
rob@76 547
rob@76 548 *(--typeTagsCurrent_) = INT64_TYPE_TAG;
rob@76 549 FromInt64( argumentCurrent_, rhs );
rob@76 550 argumentCurrent_ += 8;
rob@76 551
rob@76 552 return *this;
rob@76 553 }
rob@76 554
rob@76 555
rob@76 556 OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
rob@76 557 {
rob@76 558 CheckForAvailableArgumentSpace(8);
rob@76 559
rob@76 560 *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
rob@76 561 FromUInt64( argumentCurrent_, rhs );
rob@76 562 argumentCurrent_ += 8;
rob@76 563
rob@76 564 return *this;
rob@76 565 }
rob@76 566
rob@76 567
rob@76 568 OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
rob@76 569 {
rob@76 570 CheckForAvailableArgumentSpace(8);
rob@76 571
rob@76 572 *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
rob@76 573
rob@76 574 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 575 union{
rob@76 576 double f;
rob@76 577 char c[8];
rob@76 578 } u;
rob@76 579
rob@76 580 u.f = rhs;
rob@76 581
rob@76 582 argumentCurrent_[7] = u.c[0];
rob@76 583 argumentCurrent_[6] = u.c[1];
rob@76 584 argumentCurrent_[5] = u.c[2];
rob@76 585 argumentCurrent_[4] = u.c[3];
rob@76 586 argumentCurrent_[3] = u.c[4];
rob@76 587 argumentCurrent_[2] = u.c[5];
rob@76 588 argumentCurrent_[1] = u.c[6];
rob@76 589 argumentCurrent_[0] = u.c[7];
rob@76 590 #else
rob@76 591 *reinterpret_cast<double*>(argumentCurrent_) = rhs;
rob@76 592 #endif
rob@76 593
rob@76 594 argumentCurrent_ += 8;
rob@76 595
rob@76 596 return *this;
rob@76 597 }
rob@76 598
rob@76 599
rob@76 600 OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
rob@76 601 {
rob@76 602 CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
rob@76 603
rob@76 604 *(--typeTagsCurrent_) = STRING_TYPE_TAG;
rob@76 605 std::strcpy( argumentCurrent_, rhs );
rob@76 606 std::size_t rhsLength = std::strlen(rhs);
rob@76 607 argumentCurrent_ += rhsLength + 1;
rob@76 608
rob@76 609 // zero pad to 4-byte boundary
rob@76 610 std::size_t i = rhsLength + 1;
rob@76 611 while( i & 0x3 ){
rob@76 612 *argumentCurrent_++ = '\0';
rob@76 613 ++i;
rob@76 614 }
rob@76 615
rob@76 616 return *this;
rob@76 617 }
rob@76 618
rob@76 619
rob@76 620 OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
rob@76 621 {
rob@76 622 CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
rob@76 623
rob@76 624 *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
rob@76 625 std::strcpy( argumentCurrent_, rhs );
rob@76 626 std::size_t rhsLength = std::strlen(rhs);
rob@76 627 argumentCurrent_ += rhsLength + 1;
rob@76 628
rob@76 629 // zero pad to 4-byte boundary
rob@76 630 std::size_t i = rhsLength + 1;
rob@76 631 while( i & 0x3 ){
rob@76 632 *argumentCurrent_++ = '\0';
rob@76 633 ++i;
rob@76 634 }
rob@76 635
rob@76 636 return *this;
rob@76 637 }
rob@76 638
rob@76 639
rob@76 640 OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
rob@76 641 {
rob@76 642 CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
rob@76 643
rob@76 644 *(--typeTagsCurrent_) = BLOB_TYPE_TAG;
rob@76 645 FromUInt32( argumentCurrent_, rhs.size );
rob@76 646 argumentCurrent_ += 4;
rob@76 647
rob@76 648 std::memcpy( argumentCurrent_, rhs.data, rhs.size );
rob@76 649 argumentCurrent_ += rhs.size;
rob@76 650
rob@76 651 // zero pad to 4-byte boundary
rob@76 652 unsigned long i = rhs.size;
rob@76 653 while( i & 0x3 ){
rob@76 654 *argumentCurrent_++ = '\0';
rob@76 655 ++i;
rob@76 656 }
rob@76 657
rob@76 658 return *this;
rob@76 659 }
rob@76 660
rob@76 661 OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs )
rob@76 662 {
rob@76 663 (void) rhs;
rob@76 664 CheckForAvailableArgumentSpace(0);
rob@76 665
rob@76 666 *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
rob@76 667
rob@76 668 return *this;
rob@76 669 }
rob@76 670
rob@76 671 OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
rob@76 672 {
rob@76 673 (void) rhs;
rob@76 674 CheckForAvailableArgumentSpace(0);
rob@76 675
rob@76 676 *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;
rob@76 677
rob@76 678 return *this;
rob@76 679 }
rob@76 680
rob@76 681 } // namespace osc
rob@76 682
rob@76 683