annotate oscpack/osc/OscReceivedElements.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 "OscReceivedElements.h"
rob@76 38
rob@76 39 #include "OscHostEndianness.h"
rob@76 40
rob@76 41 #include <cstddef> // ptrdiff_t
rob@76 42
rob@76 43 namespace osc{
rob@76 44
rob@76 45
rob@76 46 // return the first 4 byte boundary after the end of a str4
rob@76 47 // be careful about calling this version if you don't know whether
rob@76 48 // the string is terminated correctly.
rob@76 49 static inline const char* FindStr4End( const char *p )
rob@76 50 {
rob@76 51 if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
rob@76 52 return p + 4;
rob@76 53
rob@76 54 p += 3;
rob@76 55
rob@76 56 while( *p )
rob@76 57 p += 4;
rob@76 58
rob@76 59 return p + 1;
rob@76 60 }
rob@76 61
rob@76 62
rob@76 63 // return the first 4 byte boundary after the end of a str4
rob@76 64 // returns 0 if p == end or if the string is unterminated
rob@76 65 static inline const char* FindStr4End( const char *p, const char *end )
rob@76 66 {
rob@76 67 if( p >= end )
rob@76 68 return 0;
rob@76 69
rob@76 70 if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
rob@76 71 return p + 4;
rob@76 72
rob@76 73 p += 3;
rob@76 74 end -= 1;
rob@76 75
rob@76 76 while( p < end && *p )
rob@76 77 p += 4;
rob@76 78
rob@76 79 if( *p )
rob@76 80 return 0;
rob@76 81 else
rob@76 82 return p + 1;
rob@76 83 }
rob@76 84
rob@76 85
rob@76 86 // round up to the next highest multiple of 4. unless x is already a multiple of 4
rob@76 87 static inline uint32 RoundUp4( uint32 x )
rob@76 88 {
rob@76 89 return (x + 3) & ~((uint32)0x03);
rob@76 90 }
rob@76 91
rob@76 92
rob@76 93 static inline int32 ToInt32( const char *p )
rob@76 94 {
rob@76 95 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 96 union{
rob@76 97 osc::int32 i;
rob@76 98 char c[4];
rob@76 99 } u;
rob@76 100
rob@76 101 u.c[0] = p[3];
rob@76 102 u.c[1] = p[2];
rob@76 103 u.c[2] = p[1];
rob@76 104 u.c[3] = p[0];
rob@76 105
rob@76 106 return u.i;
rob@76 107 #else
rob@76 108 return *(int32*)p;
rob@76 109 #endif
rob@76 110 }
rob@76 111
rob@76 112
rob@76 113 static inline uint32 ToUInt32( const char *p )
rob@76 114 {
rob@76 115 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 116 union{
rob@76 117 osc::uint32 i;
rob@76 118 char c[4];
rob@76 119 } u;
rob@76 120
rob@76 121 u.c[0] = p[3];
rob@76 122 u.c[1] = p[2];
rob@76 123 u.c[2] = p[1];
rob@76 124 u.c[3] = p[0];
rob@76 125
rob@76 126 return u.i;
rob@76 127 #else
rob@76 128 return *(uint32*)p;
rob@76 129 #endif
rob@76 130 }
rob@76 131
rob@76 132
rob@76 133 static inline int64 ToInt64( const char *p )
rob@76 134 {
rob@76 135 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 136 union{
rob@76 137 osc::int64 i;
rob@76 138 char c[8];
rob@76 139 } u;
rob@76 140
rob@76 141 u.c[0] = p[7];
rob@76 142 u.c[1] = p[6];
rob@76 143 u.c[2] = p[5];
rob@76 144 u.c[3] = p[4];
rob@76 145 u.c[4] = p[3];
rob@76 146 u.c[5] = p[2];
rob@76 147 u.c[6] = p[1];
rob@76 148 u.c[7] = p[0];
rob@76 149
rob@76 150 return u.i;
rob@76 151 #else
rob@76 152 return *(int64*)p;
rob@76 153 #endif
rob@76 154 }
rob@76 155
rob@76 156
rob@76 157 static inline uint64 ToUInt64( const char *p )
rob@76 158 {
rob@76 159 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 160 union{
rob@76 161 osc::uint64 i;
rob@76 162 char c[8];
rob@76 163 } u;
rob@76 164
rob@76 165 u.c[0] = p[7];
rob@76 166 u.c[1] = p[6];
rob@76 167 u.c[2] = p[5];
rob@76 168 u.c[3] = p[4];
rob@76 169 u.c[4] = p[3];
rob@76 170 u.c[5] = p[2];
rob@76 171 u.c[6] = p[1];
rob@76 172 u.c[7] = p[0];
rob@76 173
rob@76 174 return u.i;
rob@76 175 #else
rob@76 176 return *(uint64*)p;
rob@76 177 #endif
rob@76 178 }
rob@76 179
rob@76 180 //------------------------------------------------------------------------------
rob@76 181
rob@76 182 bool ReceivedPacket::IsBundle() const
rob@76 183 {
rob@76 184 return (Size() > 0 && Contents()[0] == '#');
rob@76 185 }
rob@76 186
rob@76 187 //------------------------------------------------------------------------------
rob@76 188
rob@76 189 bool ReceivedBundleElement::IsBundle() const
rob@76 190 {
rob@76 191 return (Size() > 0 && Contents()[0] == '#');
rob@76 192 }
rob@76 193
rob@76 194
rob@76 195 osc_bundle_element_size_t ReceivedBundleElement::Size() const
rob@76 196 {
rob@76 197 return ToInt32( sizePtr_ );
rob@76 198 }
rob@76 199
rob@76 200 //------------------------------------------------------------------------------
rob@76 201
rob@76 202 bool ReceivedMessageArgument::AsBool() const
rob@76 203 {
rob@76 204 if( !typeTagPtr_ )
rob@76 205 throw MissingArgumentException();
rob@76 206 else if( *typeTagPtr_ == TRUE_TYPE_TAG )
rob@76 207 return true;
rob@76 208 else if( *typeTagPtr_ == FALSE_TYPE_TAG )
rob@76 209 return false;
rob@76 210 else
rob@76 211 throw WrongArgumentTypeException();
rob@76 212 }
rob@76 213
rob@76 214
rob@76 215 bool ReceivedMessageArgument::AsBoolUnchecked() const
rob@76 216 {
rob@76 217 if( !typeTagPtr_ )
rob@76 218 throw MissingArgumentException();
rob@76 219 else if( *typeTagPtr_ == TRUE_TYPE_TAG )
rob@76 220 return true;
rob@76 221 else
rob@76 222 return false;
rob@76 223 }
rob@76 224
rob@76 225
rob@76 226 int32 ReceivedMessageArgument::AsInt32() const
rob@76 227 {
rob@76 228 if( !typeTagPtr_ )
rob@76 229 throw MissingArgumentException();
rob@76 230 else if( *typeTagPtr_ == INT32_TYPE_TAG )
rob@76 231 return AsInt32Unchecked();
rob@76 232 else
rob@76 233 throw WrongArgumentTypeException();
rob@76 234 }
rob@76 235
rob@76 236
rob@76 237 int32 ReceivedMessageArgument::AsInt32Unchecked() const
rob@76 238 {
rob@76 239 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 240 union{
rob@76 241 osc::int32 i;
rob@76 242 char c[4];
rob@76 243 } u;
rob@76 244
rob@76 245 u.c[0] = argumentPtr_[3];
rob@76 246 u.c[1] = argumentPtr_[2];
rob@76 247 u.c[2] = argumentPtr_[1];
rob@76 248 u.c[3] = argumentPtr_[0];
rob@76 249
rob@76 250 return u.i;
rob@76 251 #else
rob@76 252 return *(int32*)argument_;
rob@76 253 #endif
rob@76 254 }
rob@76 255
rob@76 256
rob@76 257 float ReceivedMessageArgument::AsFloat() const
rob@76 258 {
rob@76 259 if( !typeTagPtr_ )
rob@76 260 throw MissingArgumentException();
rob@76 261 else if( *typeTagPtr_ == FLOAT_TYPE_TAG )
rob@76 262 return AsFloatUnchecked();
rob@76 263 else
rob@76 264 throw WrongArgumentTypeException();
rob@76 265 }
rob@76 266
rob@76 267
rob@76 268 float ReceivedMessageArgument::AsFloatUnchecked() const
rob@76 269 {
rob@76 270 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 271 union{
rob@76 272 float f;
rob@76 273 char c[4];
rob@76 274 } u;
rob@76 275
rob@76 276 u.c[0] = argumentPtr_[3];
rob@76 277 u.c[1] = argumentPtr_[2];
rob@76 278 u.c[2] = argumentPtr_[1];
rob@76 279 u.c[3] = argumentPtr_[0];
rob@76 280
rob@76 281 return u.f;
rob@76 282 #else
rob@76 283 return *(float*)argument_;
rob@76 284 #endif
rob@76 285 }
rob@76 286
rob@76 287
rob@76 288 char ReceivedMessageArgument::AsChar() const
rob@76 289 {
rob@76 290 if( !typeTagPtr_ )
rob@76 291 throw MissingArgumentException();
rob@76 292 else if( *typeTagPtr_ == CHAR_TYPE_TAG )
rob@76 293 return AsCharUnchecked();
rob@76 294 else
rob@76 295 throw WrongArgumentTypeException();
rob@76 296 }
rob@76 297
rob@76 298
rob@76 299 char ReceivedMessageArgument::AsCharUnchecked() const
rob@76 300 {
rob@76 301 return (char)ToInt32( argumentPtr_ );
rob@76 302 }
rob@76 303
rob@76 304
rob@76 305 uint32 ReceivedMessageArgument::AsRgbaColor() const
rob@76 306 {
rob@76 307 if( !typeTagPtr_ )
rob@76 308 throw MissingArgumentException();
rob@76 309 else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG )
rob@76 310 return AsRgbaColorUnchecked();
rob@76 311 else
rob@76 312 throw WrongArgumentTypeException();
rob@76 313 }
rob@76 314
rob@76 315
rob@76 316 uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
rob@76 317 {
rob@76 318 return ToUInt32( argumentPtr_ );
rob@76 319 }
rob@76 320
rob@76 321
rob@76 322 uint32 ReceivedMessageArgument::AsMidiMessage() const
rob@76 323 {
rob@76 324 if( !typeTagPtr_ )
rob@76 325 throw MissingArgumentException();
rob@76 326 else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG )
rob@76 327 return AsMidiMessageUnchecked();
rob@76 328 else
rob@76 329 throw WrongArgumentTypeException();
rob@76 330 }
rob@76 331
rob@76 332
rob@76 333 uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
rob@76 334 {
rob@76 335 return ToUInt32( argumentPtr_ );
rob@76 336 }
rob@76 337
rob@76 338
rob@76 339 int64 ReceivedMessageArgument::AsInt64() const
rob@76 340 {
rob@76 341 if( !typeTagPtr_ )
rob@76 342 throw MissingArgumentException();
rob@76 343 else if( *typeTagPtr_ == INT64_TYPE_TAG )
rob@76 344 return AsInt64Unchecked();
rob@76 345 else
rob@76 346 throw WrongArgumentTypeException();
rob@76 347 }
rob@76 348
rob@76 349
rob@76 350 int64 ReceivedMessageArgument::AsInt64Unchecked() const
rob@76 351 {
rob@76 352 return ToInt64( argumentPtr_ );
rob@76 353 }
rob@76 354
rob@76 355
rob@76 356 uint64 ReceivedMessageArgument::AsTimeTag() const
rob@76 357 {
rob@76 358 if( !typeTagPtr_ )
rob@76 359 throw MissingArgumentException();
rob@76 360 else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG )
rob@76 361 return AsTimeTagUnchecked();
rob@76 362 else
rob@76 363 throw WrongArgumentTypeException();
rob@76 364 }
rob@76 365
rob@76 366
rob@76 367 uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
rob@76 368 {
rob@76 369 return ToUInt64( argumentPtr_ );
rob@76 370 }
rob@76 371
rob@76 372
rob@76 373 double ReceivedMessageArgument::AsDouble() const
rob@76 374 {
rob@76 375 if( !typeTagPtr_ )
rob@76 376 throw MissingArgumentException();
rob@76 377 else if( *typeTagPtr_ == DOUBLE_TYPE_TAG )
rob@76 378 return AsDoubleUnchecked();
rob@76 379 else
rob@76 380 throw WrongArgumentTypeException();
rob@76 381 }
rob@76 382
rob@76 383
rob@76 384 double ReceivedMessageArgument::AsDoubleUnchecked() const
rob@76 385 {
rob@76 386 #ifdef OSC_HOST_LITTLE_ENDIAN
rob@76 387 union{
rob@76 388 double d;
rob@76 389 char c[8];
rob@76 390 } u;
rob@76 391
rob@76 392 u.c[0] = argumentPtr_[7];
rob@76 393 u.c[1] = argumentPtr_[6];
rob@76 394 u.c[2] = argumentPtr_[5];
rob@76 395 u.c[3] = argumentPtr_[4];
rob@76 396 u.c[4] = argumentPtr_[3];
rob@76 397 u.c[5] = argumentPtr_[2];
rob@76 398 u.c[6] = argumentPtr_[1];
rob@76 399 u.c[7] = argumentPtr_[0];
rob@76 400
rob@76 401 return u.d;
rob@76 402 #else
rob@76 403 return *(double*)argument_;
rob@76 404 #endif
rob@76 405 }
rob@76 406
rob@76 407
rob@76 408 const char* ReceivedMessageArgument::AsString() const
rob@76 409 {
rob@76 410 if( !typeTagPtr_ )
rob@76 411 throw MissingArgumentException();
rob@76 412 else if( *typeTagPtr_ == STRING_TYPE_TAG )
rob@76 413 return argumentPtr_;
rob@76 414 else
rob@76 415 throw WrongArgumentTypeException();
rob@76 416 }
rob@76 417
rob@76 418
rob@76 419 const char* ReceivedMessageArgument::AsSymbol() const
rob@76 420 {
rob@76 421 if( !typeTagPtr_ )
rob@76 422 throw MissingArgumentException();
rob@76 423 else if( *typeTagPtr_ == SYMBOL_TYPE_TAG )
rob@76 424 return argumentPtr_;
rob@76 425 else
rob@76 426 throw WrongArgumentTypeException();
rob@76 427 }
rob@76 428
rob@76 429
rob@76 430 void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const
rob@76 431 {
rob@76 432 if( !typeTagPtr_ )
rob@76 433 throw MissingArgumentException();
rob@76 434 else if( *typeTagPtr_ == BLOB_TYPE_TAG )
rob@76 435 AsBlobUnchecked( data, size );
rob@76 436 else
rob@76 437 throw WrongArgumentTypeException();
rob@76 438 }
rob@76 439
rob@76 440
rob@76 441 void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const
rob@76 442 {
rob@76 443 // read blob size as an unsigned int then validate
rob@76 444 osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ );
rob@76 445 if( !IsValidElementSizeValue(sizeResult) )
rob@76 446 throw MalformedMessageException("invalid blob size");
rob@76 447
rob@76 448 size = sizeResult;
rob@76 449 data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32);
rob@76 450 }
rob@76 451
rob@76 452 std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const
rob@76 453 {
rob@76 454 // it is only valid to call ComputeArrayItemCount when the argument is the array start marker
rob@76 455 if( !IsArrayBegin() )
rob@76 456 throw WrongArgumentTypeException();
rob@76 457
rob@76 458 std::size_t result = 0;
rob@76 459 unsigned int level = 0;
rob@76 460 const char *typeTag = typeTagPtr_ + 1;
rob@76 461
rob@76 462 // iterate through all type tags. note that ReceivedMessage::Init
rob@76 463 // has already checked that the message is well formed.
rob@76 464 while( *typeTag ) {
rob@76 465 switch( *typeTag++ ) {
rob@76 466 case ARRAY_BEGIN_TYPE_TAG:
rob@76 467 level += 1;
rob@76 468 break;
rob@76 469
rob@76 470 case ARRAY_END_TYPE_TAG:
rob@76 471 if(level == 0)
rob@76 472 return result;
rob@76 473 level -= 1;
rob@76 474 break;
rob@76 475
rob@76 476 default:
rob@76 477 if( level == 0 ) // only count items at level 0
rob@76 478 ++result;
rob@76 479 }
rob@76 480 }
rob@76 481
rob@76 482 return result;
rob@76 483 }
rob@76 484
rob@76 485 //------------------------------------------------------------------------------
rob@76 486
rob@76 487 void ReceivedMessageArgumentIterator::Advance()
rob@76 488 {
rob@76 489 if( !value_.typeTagPtr_ )
rob@76 490 return;
rob@76 491
rob@76 492 switch( *value_.typeTagPtr_++ ){
rob@76 493 case '\0':
rob@76 494 // don't advance past end
rob@76 495 --value_.typeTagPtr_;
rob@76 496 break;
rob@76 497
rob@76 498 case TRUE_TYPE_TAG:
rob@76 499 case FALSE_TYPE_TAG:
rob@76 500 case NIL_TYPE_TAG:
rob@76 501 case INFINITUM_TYPE_TAG:
rob@76 502
rob@76 503 // zero length
rob@76 504 break;
rob@76 505
rob@76 506 case INT32_TYPE_TAG:
rob@76 507 case FLOAT_TYPE_TAG:
rob@76 508 case CHAR_TYPE_TAG:
rob@76 509 case RGBA_COLOR_TYPE_TAG:
rob@76 510 case MIDI_MESSAGE_TYPE_TAG:
rob@76 511
rob@76 512 value_.argumentPtr_ += 4;
rob@76 513 break;
rob@76 514
rob@76 515 case INT64_TYPE_TAG:
rob@76 516 case TIME_TAG_TYPE_TAG:
rob@76 517 case DOUBLE_TYPE_TAG:
rob@76 518
rob@76 519 value_.argumentPtr_ += 8;
rob@76 520 break;
rob@76 521
rob@76 522 case STRING_TYPE_TAG:
rob@76 523 case SYMBOL_TYPE_TAG:
rob@76 524
rob@76 525 // we use the unsafe function FindStr4End(char*) here because all of
rob@76 526 // the arguments have already been validated in
rob@76 527 // ReceivedMessage::Init() below.
rob@76 528
rob@76 529 value_.argumentPtr_ = FindStr4End( value_.argumentPtr_ );
rob@76 530 break;
rob@76 531
rob@76 532 case BLOB_TYPE_TAG:
rob@76 533 {
rob@76 534 // treat blob size as an unsigned int for the purposes of this calculation
rob@76 535 uint32 blobSize = ToUInt32( value_.argumentPtr_ );
rob@76 536 value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
rob@76 537 }
rob@76 538 break;
rob@76 539
rob@76 540 case ARRAY_BEGIN_TYPE_TAG:
rob@76 541 case ARRAY_END_TYPE_TAG:
rob@76 542
rob@76 543 // [ Indicates the beginning of an array. The tags following are for
rob@76 544 // data in the Array until a close brace tag is reached.
rob@76 545 // ] Indicates the end of an array.
rob@76 546
rob@76 547 // zero length, don't advance argument ptr
rob@76 548 break;
rob@76 549
rob@76 550 default: // unknown type tag
rob@76 551 // don't advance
rob@76 552 --value_.typeTagPtr_;
rob@76 553 break;
rob@76 554 }
rob@76 555 }
rob@76 556
rob@76 557 //------------------------------------------------------------------------------
rob@76 558
rob@76 559 ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
rob@76 560 : addressPattern_( packet.Contents() )
rob@76 561 {
rob@76 562 Init( packet.Contents(), packet.Size() );
rob@76 563 }
rob@76 564
rob@76 565
rob@76 566 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
rob@76 567 : addressPattern_( bundleElement.Contents() )
rob@76 568 {
rob@76 569 Init( bundleElement.Contents(), bundleElement.Size() );
rob@76 570 }
rob@76 571
rob@76 572
rob@76 573 bool ReceivedMessage::AddressPatternIsUInt32() const
rob@76 574 {
rob@76 575 return (addressPattern_[0] == '\0');
rob@76 576 }
rob@76 577
rob@76 578
rob@76 579 uint32 ReceivedMessage::AddressPatternAsUInt32() const
rob@76 580 {
rob@76 581 return ToUInt32( addressPattern_ );
rob@76 582 }
rob@76 583
rob@76 584
rob@76 585 void ReceivedMessage::Init( const char *message, osc_bundle_element_size_t size )
rob@76 586 {
rob@76 587 if( !IsValidElementSizeValue(size) )
rob@76 588 throw MalformedMessageException( "invalid message size" );
rob@76 589
rob@76 590 if( size == 0 )
rob@76 591 throw MalformedMessageException( "zero length messages not permitted" );
rob@76 592
rob@76 593 if( !IsMultipleOf4(size) )
rob@76 594 throw MalformedMessageException( "message size must be multiple of four" );
rob@76 595
rob@76 596 const char *end = message + size;
rob@76 597
rob@76 598 typeTagsBegin_ = FindStr4End( addressPattern_, end );
rob@76 599 if( typeTagsBegin_ == 0 ){
rob@76 600 // address pattern was not terminated before end
rob@76 601 throw MalformedMessageException( "unterminated address pattern" );
rob@76 602 }
rob@76 603
rob@76 604 if( typeTagsBegin_ == end ){
rob@76 605 // message consists of only the address pattern - no arguments or type tags.
rob@76 606 typeTagsBegin_ = 0;
rob@76 607 typeTagsEnd_ = 0;
rob@76 608 arguments_ = 0;
rob@76 609
rob@76 610 }else{
rob@76 611 if( *typeTagsBegin_ != ',' )
rob@76 612 throw MalformedMessageException( "type tags not present" );
rob@76 613
rob@76 614 if( *(typeTagsBegin_ + 1) == '\0' ){
rob@76 615 // zero length type tags
rob@76 616 typeTagsBegin_ = 0;
rob@76 617 typeTagsEnd_ = 0;
rob@76 618 arguments_ = 0;
rob@76 619
rob@76 620 }else{
rob@76 621 // check that all arguments are present and well formed
rob@76 622
rob@76 623 arguments_ = FindStr4End( typeTagsBegin_, end );
rob@76 624 if( arguments_ == 0 ){
rob@76 625 throw MalformedMessageException( "type tags were not terminated before end of message" );
rob@76 626 }
rob@76 627
rob@76 628 ++typeTagsBegin_; // advance past initial ','
rob@76 629
rob@76 630 const char *typeTag = typeTagsBegin_;
rob@76 631 const char *argument = arguments_;
rob@76 632 unsigned int arrayLevel = 0;
rob@76 633
rob@76 634 do{
rob@76 635 switch( *typeTag ){
rob@76 636 case TRUE_TYPE_TAG:
rob@76 637 case FALSE_TYPE_TAG:
rob@76 638 case NIL_TYPE_TAG:
rob@76 639 case INFINITUM_TYPE_TAG:
rob@76 640 // zero length
rob@76 641 break;
rob@76 642
rob@76 643 // [ Indicates the beginning of an array. The tags following are for
rob@76 644 // data in the Array until a close brace tag is reached.
rob@76 645 // ] Indicates the end of an array.
rob@76 646 case ARRAY_BEGIN_TYPE_TAG:
rob@76 647 ++arrayLevel;
rob@76 648 // (zero length argument data)
rob@76 649 break;
rob@76 650
rob@76 651 case ARRAY_END_TYPE_TAG:
rob@76 652 --arrayLevel;
rob@76 653 // (zero length argument data)
rob@76 654 break;
rob@76 655
rob@76 656 case INT32_TYPE_TAG:
rob@76 657 case FLOAT_TYPE_TAG:
rob@76 658 case CHAR_TYPE_TAG:
rob@76 659 case RGBA_COLOR_TYPE_TAG:
rob@76 660 case MIDI_MESSAGE_TYPE_TAG:
rob@76 661
rob@76 662 if( argument == end )
rob@76 663 throw MalformedMessageException( "arguments exceed message size" );
rob@76 664 argument += 4;
rob@76 665 if( argument > end )
rob@76 666 throw MalformedMessageException( "arguments exceed message size" );
rob@76 667 break;
rob@76 668
rob@76 669 case INT64_TYPE_TAG:
rob@76 670 case TIME_TAG_TYPE_TAG:
rob@76 671 case DOUBLE_TYPE_TAG:
rob@76 672
rob@76 673 if( argument == end )
rob@76 674 throw MalformedMessageException( "arguments exceed message size" );
rob@76 675 argument += 8;
rob@76 676 if( argument > end )
rob@76 677 throw MalformedMessageException( "arguments exceed message size" );
rob@76 678 break;
rob@76 679
rob@76 680 case STRING_TYPE_TAG:
rob@76 681 case SYMBOL_TYPE_TAG:
rob@76 682
rob@76 683 if( argument == end )
rob@76 684 throw MalformedMessageException( "arguments exceed message size" );
rob@76 685 argument = FindStr4End( argument, end );
rob@76 686 if( argument == 0 )
rob@76 687 throw MalformedMessageException( "unterminated string argument" );
rob@76 688 break;
rob@76 689
rob@76 690 case BLOB_TYPE_TAG:
rob@76 691 {
rob@76 692 if( argument + osc::OSC_SIZEOF_INT32 > end )
rob@76 693 MalformedMessageException( "arguments exceed message size" );
rob@76 694
rob@76 695 // treat blob size as an unsigned int for the purposes of this calculation
rob@76 696 uint32 blobSize = ToUInt32( argument );
rob@76 697 argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize );
rob@76 698 if( argument > end )
rob@76 699 MalformedMessageException( "arguments exceed message size" );
rob@76 700 }
rob@76 701 break;
rob@76 702
rob@76 703 default:
rob@76 704 throw MalformedMessageException( "unknown type tag" );
rob@76 705 }
rob@76 706
rob@76 707 }while( *++typeTag != '\0' );
rob@76 708 typeTagsEnd_ = typeTag;
rob@76 709
rob@76 710 if( arrayLevel != 0 )
rob@76 711 throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" );
rob@76 712 }
rob@76 713
rob@76 714 // These invariants should be guaranteed by the above code.
rob@76 715 // we depend on them in the implementation of ArgumentCount()
rob@76 716 #ifndef NDEBUG
rob@76 717 std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_;
rob@76 718 assert( argumentCount >= 0 );
rob@76 719 assert( argumentCount <= OSC_INT32_MAX );
rob@76 720 #endif
rob@76 721 }
rob@76 722 }
rob@76 723
rob@76 724 //------------------------------------------------------------------------------
rob@76 725
rob@76 726 ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
rob@76 727 : elementCount_( 0 )
rob@76 728 {
rob@76 729 Init( packet.Contents(), packet.Size() );
rob@76 730 }
rob@76 731
rob@76 732
rob@76 733 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
rob@76 734 : elementCount_( 0 )
rob@76 735 {
rob@76 736 Init( bundleElement.Contents(), bundleElement.Size() );
rob@76 737 }
rob@76 738
rob@76 739
rob@76 740 void ReceivedBundle::Init( const char *bundle, osc_bundle_element_size_t size )
rob@76 741 {
rob@76 742
rob@76 743 if( !IsValidElementSizeValue(size) )
rob@76 744 throw MalformedBundleException( "invalid bundle size" );
rob@76 745
rob@76 746 if( size < 16 )
rob@76 747 throw MalformedBundleException( "packet too short for bundle" );
rob@76 748
rob@76 749 if( !IsMultipleOf4(size) )
rob@76 750 throw MalformedBundleException( "bundle size must be multiple of four" );
rob@76 751
rob@76 752 if( bundle[0] != '#'
rob@76 753 || bundle[1] != 'b'
rob@76 754 || bundle[2] != 'u'
rob@76 755 || bundle[3] != 'n'
rob@76 756 || bundle[4] != 'd'
rob@76 757 || bundle[5] != 'l'
rob@76 758 || bundle[6] != 'e'
rob@76 759 || bundle[7] != '\0' )
rob@76 760 throw MalformedBundleException( "bad bundle address pattern" );
rob@76 761
rob@76 762 end_ = bundle + size;
rob@76 763
rob@76 764 timeTag_ = bundle + 8;
rob@76 765
rob@76 766 const char *p = timeTag_ + 8;
rob@76 767
rob@76 768 while( p < end_ ){
rob@76 769 if( p + osc::OSC_SIZEOF_INT32 > end_ )
rob@76 770 throw MalformedBundleException( "packet too short for elementSize" );
rob@76 771
rob@76 772 // treat element size as an unsigned int for the purposes of this calculation
rob@76 773 uint32 elementSize = ToUInt32( p );
rob@76 774 if( (elementSize & ((uint32)0x03)) != 0 )
rob@76 775 throw MalformedBundleException( "bundle element size must be multiple of four" );
rob@76 776
rob@76 777 p += osc::OSC_SIZEOF_INT32 + elementSize;
rob@76 778 if( p > end_ )
rob@76 779 throw MalformedBundleException( "packet too short for bundle element" );
rob@76 780
rob@76 781 ++elementCount_;
rob@76 782 }
rob@76 783
rob@76 784 if( p != end_ )
rob@76 785 throw MalformedBundleException( "bundle contents " );
rob@76 786 }
rob@76 787
rob@76 788
rob@76 789 uint64 ReceivedBundle::TimeTag() const
rob@76 790 {
rob@76 791 return ToUInt64( timeTag_ );
rob@76 792 }
rob@76 793
rob@76 794
rob@76 795 } // namespace osc
rob@76 796