annotate trunk/external/oscpack/osc/OscReceivedElements.cpp @ 706:f8e90b5d85fd tip

Delete CARFAC code from this repository. It has been moved to https://github.com/google/carfac Please email me with your github username to get access. I've also created a new mailing list to discuss CARFAC development: https://groups.google.com/forum/#!forum/carfac-dev
author ronw@google.com
date Thu, 18 Jul 2013 20:56:51 +0000
parents 4b37b53105a3
children
rev   line source
tomwalters@570 1 /*
tomwalters@570 2 oscpack -- Open Sound Control packet manipulation library
tomwalters@570 3 http://www.audiomulch.com/~rossb/oscpack
tomwalters@570 4
tomwalters@570 5 Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
tomwalters@570 6
tomwalters@570 7 Permission is hereby granted, free of charge, to any person obtaining
tomwalters@570 8 a copy of this software and associated documentation files
tomwalters@570 9 (the "Software"), to deal in the Software without restriction,
tomwalters@570 10 including without limitation the rights to use, copy, modify, merge,
tomwalters@570 11 publish, distribute, sublicense, and/or sell copies of the Software,
tomwalters@570 12 and to permit persons to whom the Software is furnished to do so,
tomwalters@570 13 subject to the following conditions:
tomwalters@570 14
tomwalters@570 15 The above copyright notice and this permission notice shall be
tomwalters@570 16 included in all copies or substantial portions of the Software.
tomwalters@570 17
tomwalters@570 18 Any person wishing to distribute modifications to the Software is
tomwalters@570 19 requested to send the modifications to the original developer so that
tomwalters@570 20 they can be incorporated into the canonical version.
tomwalters@570 21
tomwalters@570 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
tomwalters@570 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
tomwalters@570 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
tomwalters@570 25 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
tomwalters@570 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
tomwalters@570 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
tomwalters@570 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
tomwalters@570 29 */
tomwalters@570 30 #include "OscReceivedElements.h"
tomwalters@570 31
tomwalters@570 32 #include <cassert>
tomwalters@570 33
tomwalters@570 34 #include "OscHostEndianness.h"
tomwalters@570 35
tomwalters@570 36
tomwalters@570 37 namespace osc{
tomwalters@570 38
tomwalters@570 39
tomwalters@570 40 // return the first 4 byte boundary after the end of a str4
tomwalters@570 41 // be careful about calling this version if you don't know whether
tomwalters@570 42 // the string is terminated correctly.
tomwalters@570 43 static inline const char* FindStr4End( const char *p )
tomwalters@570 44 {
tomwalters@570 45 if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
tomwalters@570 46 return p + 4;
tomwalters@570 47
tomwalters@570 48 p += 3;
tomwalters@570 49
tomwalters@570 50 while( *p )
tomwalters@570 51 p += 4;
tomwalters@570 52
tomwalters@570 53 return p + 1;
tomwalters@570 54 }
tomwalters@570 55
tomwalters@570 56
tomwalters@570 57 // return the first 4 byte boundary after the end of a str4
tomwalters@570 58 // returns 0 if p == end or if the string is unterminated
tomwalters@570 59 static inline const char* FindStr4End( const char *p, const char *end )
tomwalters@570 60 {
tomwalters@570 61 if( p >= end )
tomwalters@570 62 return 0;
tomwalters@570 63
tomwalters@570 64 if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
tomwalters@570 65 return p + 4;
tomwalters@570 66
tomwalters@570 67 p += 3;
tomwalters@570 68 end -= 1;
tomwalters@570 69
tomwalters@570 70 while( p < end && *p )
tomwalters@570 71 p += 4;
tomwalters@570 72
tomwalters@570 73 if( *p )
tomwalters@570 74 return 0;
tomwalters@570 75 else
tomwalters@570 76 return p + 1;
tomwalters@570 77 }
tomwalters@570 78
tomwalters@570 79
tomwalters@570 80 static inline unsigned long RoundUp4( unsigned long x )
tomwalters@570 81 {
tomwalters@570 82 unsigned long remainder = x & 0x3UL;
tomwalters@570 83 if( remainder )
tomwalters@570 84 return x + (4 - remainder);
tomwalters@570 85 else
tomwalters@570 86 return x;
tomwalters@570 87 }
tomwalters@570 88
tomwalters@570 89
tomwalters@570 90 static inline int32 ToInt32( const char *p )
tomwalters@570 91 {
tomwalters@570 92 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 93 union{
tomwalters@570 94 osc::int32 i;
tomwalters@570 95 char c[4];
tomwalters@570 96 } u;
tomwalters@570 97
tomwalters@570 98 u.c[0] = p[3];
tomwalters@570 99 u.c[1] = p[2];
tomwalters@570 100 u.c[2] = p[1];
tomwalters@570 101 u.c[3] = p[0];
tomwalters@570 102
tomwalters@570 103 return u.i;
tomwalters@570 104 #else
tomwalters@570 105 return *(int32*)p;
tomwalters@570 106 #endif
tomwalters@570 107 }
tomwalters@570 108
tomwalters@570 109
tomwalters@570 110 static inline uint32 ToUInt32( const char *p )
tomwalters@570 111 {
tomwalters@570 112 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 113 union{
tomwalters@570 114 osc::uint32 i;
tomwalters@570 115 char c[4];
tomwalters@570 116 } u;
tomwalters@570 117
tomwalters@570 118 u.c[0] = p[3];
tomwalters@570 119 u.c[1] = p[2];
tomwalters@570 120 u.c[2] = p[1];
tomwalters@570 121 u.c[3] = p[0];
tomwalters@570 122
tomwalters@570 123 return u.i;
tomwalters@570 124 #else
tomwalters@570 125 return *(uint32*)p;
tomwalters@570 126 #endif
tomwalters@570 127 }
tomwalters@570 128
tomwalters@570 129
tomwalters@570 130 int64 ToInt64( const char *p )
tomwalters@570 131 {
tomwalters@570 132 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 133 union{
tomwalters@570 134 osc::int64 i;
tomwalters@570 135 char c[4];
tomwalters@570 136 } u;
tomwalters@570 137
tomwalters@570 138 u.c[0] = p[7];
tomwalters@570 139 u.c[1] = p[6];
tomwalters@570 140 u.c[2] = p[5];
tomwalters@570 141 u.c[3] = p[4];
tomwalters@570 142 u.c[4] = p[3];
tomwalters@570 143 u.c[5] = p[2];
tomwalters@570 144 u.c[6] = p[1];
tomwalters@570 145 u.c[7] = p[0];
tomwalters@570 146
tomwalters@570 147 return u.i;
tomwalters@570 148 #else
tomwalters@570 149 return *(int64*)p;
tomwalters@570 150 #endif
tomwalters@570 151 }
tomwalters@570 152
tomwalters@570 153
tomwalters@570 154 uint64 ToUInt64( const char *p )
tomwalters@570 155 {
tomwalters@570 156 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 157 union{
tomwalters@570 158 osc::uint64 i;
tomwalters@570 159 char c[4];
tomwalters@570 160 } u;
tomwalters@570 161
tomwalters@570 162 u.c[0] = p[7];
tomwalters@570 163 u.c[1] = p[6];
tomwalters@570 164 u.c[2] = p[5];
tomwalters@570 165 u.c[3] = p[4];
tomwalters@570 166 u.c[4] = p[3];
tomwalters@570 167 u.c[5] = p[2];
tomwalters@570 168 u.c[6] = p[1];
tomwalters@570 169 u.c[7] = p[0];
tomwalters@570 170
tomwalters@570 171 return u.i;
tomwalters@570 172 #else
tomwalters@570 173 return *(uint64*)p;
tomwalters@570 174 #endif
tomwalters@570 175 }
tomwalters@570 176
tomwalters@570 177 //------------------------------------------------------------------------------
tomwalters@570 178
tomwalters@570 179 bool ReceivedPacket::IsBundle() const
tomwalters@570 180 {
tomwalters@570 181 return (Size() > 0 && Contents()[0] == '#');
tomwalters@570 182 }
tomwalters@570 183
tomwalters@570 184 //------------------------------------------------------------------------------
tomwalters@570 185
tomwalters@570 186 bool ReceivedBundleElement::IsBundle() const
tomwalters@570 187 {
tomwalters@570 188 return (Size() > 0 && Contents()[0] == '#');
tomwalters@570 189 }
tomwalters@570 190
tomwalters@570 191
tomwalters@570 192 int32 ReceivedBundleElement::Size() const
tomwalters@570 193 {
tomwalters@570 194 return ToUInt32( size_ );
tomwalters@570 195 }
tomwalters@570 196
tomwalters@570 197 //------------------------------------------------------------------------------
tomwalters@570 198
tomwalters@570 199 bool ReceivedMessageArgument::AsBool() const
tomwalters@570 200 {
tomwalters@570 201 if( !typeTag_ )
tomwalters@570 202 throw MissingArgumentException();
tomwalters@570 203 else if( *typeTag_ == TRUE_TYPE_TAG )
tomwalters@570 204 return true;
tomwalters@570 205 else if( *typeTag_ == FALSE_TYPE_TAG )
tomwalters@570 206 return false;
tomwalters@570 207 else
tomwalters@570 208 throw WrongArgumentTypeException();
tomwalters@570 209 }
tomwalters@570 210
tomwalters@570 211
tomwalters@570 212 bool ReceivedMessageArgument::AsBoolUnchecked() const
tomwalters@570 213 {
tomwalters@570 214 if( !typeTag_ )
tomwalters@570 215 throw MissingArgumentException();
tomwalters@570 216 else if( *typeTag_ == TRUE_TYPE_TAG )
tomwalters@570 217 return true;
tomwalters@570 218 else
tomwalters@570 219 return false;
tomwalters@570 220 }
tomwalters@570 221
tomwalters@570 222
tomwalters@570 223 int32 ReceivedMessageArgument::AsInt32() const
tomwalters@570 224 {
tomwalters@570 225 if( !typeTag_ )
tomwalters@570 226 throw MissingArgumentException();
tomwalters@570 227 else if( *typeTag_ == INT32_TYPE_TAG )
tomwalters@570 228 return AsInt32Unchecked();
tomwalters@570 229 else
tomwalters@570 230 throw WrongArgumentTypeException();
tomwalters@570 231 }
tomwalters@570 232
tomwalters@570 233
tomwalters@570 234 int32 ReceivedMessageArgument::AsInt32Unchecked() const
tomwalters@570 235 {
tomwalters@570 236 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 237 union{
tomwalters@570 238 osc::int32 i;
tomwalters@570 239 char c[4];
tomwalters@570 240 } u;
tomwalters@570 241
tomwalters@570 242 u.c[0] = argument_[3];
tomwalters@570 243 u.c[1] = argument_[2];
tomwalters@570 244 u.c[2] = argument_[1];
tomwalters@570 245 u.c[3] = argument_[0];
tomwalters@570 246
tomwalters@570 247 return u.i;
tomwalters@570 248 #else
tomwalters@570 249 return *(int32*)argument_;
tomwalters@570 250 #endif
tomwalters@570 251 }
tomwalters@570 252
tomwalters@570 253
tomwalters@570 254 float ReceivedMessageArgument::AsFloat() const
tomwalters@570 255 {
tomwalters@570 256 if( !typeTag_ )
tomwalters@570 257 throw MissingArgumentException();
tomwalters@570 258 else if( *typeTag_ == FLOAT_TYPE_TAG )
tomwalters@570 259 return AsFloatUnchecked();
tomwalters@570 260 else
tomwalters@570 261 throw WrongArgumentTypeException();
tomwalters@570 262 }
tomwalters@570 263
tomwalters@570 264
tomwalters@570 265 float ReceivedMessageArgument::AsFloatUnchecked() const
tomwalters@570 266 {
tomwalters@570 267 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 268 union{
tomwalters@570 269 float f;
tomwalters@570 270 char c[4];
tomwalters@570 271 } u;
tomwalters@570 272
tomwalters@570 273 u.c[0] = argument_[3];
tomwalters@570 274 u.c[1] = argument_[2];
tomwalters@570 275 u.c[2] = argument_[1];
tomwalters@570 276 u.c[3] = argument_[0];
tomwalters@570 277
tomwalters@570 278 return u.f;
tomwalters@570 279 #else
tomwalters@570 280 return *(float*)argument_;
tomwalters@570 281 #endif
tomwalters@570 282 }
tomwalters@570 283
tomwalters@570 284
tomwalters@570 285 char ReceivedMessageArgument::AsChar() const
tomwalters@570 286 {
tomwalters@570 287 if( !typeTag_ )
tomwalters@570 288 throw MissingArgumentException();
tomwalters@570 289 else if( *typeTag_ == CHAR_TYPE_TAG )
tomwalters@570 290 return AsCharUnchecked();
tomwalters@570 291 else
tomwalters@570 292 throw WrongArgumentTypeException();
tomwalters@570 293 }
tomwalters@570 294
tomwalters@570 295
tomwalters@570 296 char ReceivedMessageArgument::AsCharUnchecked() const
tomwalters@570 297 {
tomwalters@570 298 return (char)ToInt32( argument_ );
tomwalters@570 299 }
tomwalters@570 300
tomwalters@570 301
tomwalters@570 302 uint32 ReceivedMessageArgument::AsRgbaColor() const
tomwalters@570 303 {
tomwalters@570 304 if( !typeTag_ )
tomwalters@570 305 throw MissingArgumentException();
tomwalters@570 306 else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
tomwalters@570 307 return AsRgbaColorUnchecked();
tomwalters@570 308 else
tomwalters@570 309 throw WrongArgumentTypeException();
tomwalters@570 310 }
tomwalters@570 311
tomwalters@570 312
tomwalters@570 313 uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
tomwalters@570 314 {
tomwalters@570 315 return ToUInt32( argument_ );
tomwalters@570 316 }
tomwalters@570 317
tomwalters@570 318
tomwalters@570 319 uint32 ReceivedMessageArgument::AsMidiMessage() const
tomwalters@570 320 {
tomwalters@570 321 if( !typeTag_ )
tomwalters@570 322 throw MissingArgumentException();
tomwalters@570 323 else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
tomwalters@570 324 return AsMidiMessageUnchecked();
tomwalters@570 325 else
tomwalters@570 326 throw WrongArgumentTypeException();
tomwalters@570 327 }
tomwalters@570 328
tomwalters@570 329
tomwalters@570 330 uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
tomwalters@570 331 {
tomwalters@570 332 return ToUInt32( argument_ );
tomwalters@570 333 }
tomwalters@570 334
tomwalters@570 335
tomwalters@570 336 int64 ReceivedMessageArgument::AsInt64() const
tomwalters@570 337 {
tomwalters@570 338 if( !typeTag_ )
tomwalters@570 339 throw MissingArgumentException();
tomwalters@570 340 else if( *typeTag_ == INT64_TYPE_TAG )
tomwalters@570 341 return AsInt64Unchecked();
tomwalters@570 342 else
tomwalters@570 343 throw WrongArgumentTypeException();
tomwalters@570 344 }
tomwalters@570 345
tomwalters@570 346
tomwalters@570 347 int64 ReceivedMessageArgument::AsInt64Unchecked() const
tomwalters@570 348 {
tomwalters@570 349 return ToInt64( argument_ );
tomwalters@570 350 }
tomwalters@570 351
tomwalters@570 352
tomwalters@570 353 uint64 ReceivedMessageArgument::AsTimeTag() const
tomwalters@570 354 {
tomwalters@570 355 if( !typeTag_ )
tomwalters@570 356 throw MissingArgumentException();
tomwalters@570 357 else if( *typeTag_ == TIME_TAG_TYPE_TAG )
tomwalters@570 358 return AsTimeTagUnchecked();
tomwalters@570 359 else
tomwalters@570 360 throw WrongArgumentTypeException();
tomwalters@570 361 }
tomwalters@570 362
tomwalters@570 363
tomwalters@570 364 uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
tomwalters@570 365 {
tomwalters@570 366 return ToUInt64( argument_ );
tomwalters@570 367 }
tomwalters@570 368
tomwalters@570 369
tomwalters@570 370 double ReceivedMessageArgument::AsDouble() const
tomwalters@570 371 {
tomwalters@570 372 if( !typeTag_ )
tomwalters@570 373 throw MissingArgumentException();
tomwalters@570 374 else if( *typeTag_ == DOUBLE_TYPE_TAG )
tomwalters@570 375 return AsDoubleUnchecked();
tomwalters@570 376 else
tomwalters@570 377 throw WrongArgumentTypeException();
tomwalters@570 378 }
tomwalters@570 379
tomwalters@570 380
tomwalters@570 381 double ReceivedMessageArgument::AsDoubleUnchecked() const
tomwalters@570 382 {
tomwalters@570 383 #ifdef OSC_HOST_LITTLE_ENDIAN
tomwalters@570 384 union{
tomwalters@570 385 double d;
tomwalters@570 386 char c[8];
tomwalters@570 387 } u;
tomwalters@570 388
tomwalters@570 389 u.c[0] = argument_[7];
tomwalters@570 390 u.c[1] = argument_[6];
tomwalters@570 391 u.c[2] = argument_[5];
tomwalters@570 392 u.c[3] = argument_[4];
tomwalters@570 393 u.c[4] = argument_[3];
tomwalters@570 394 u.c[5] = argument_[2];
tomwalters@570 395 u.c[6] = argument_[1];
tomwalters@570 396 u.c[7] = argument_[0];
tomwalters@570 397
tomwalters@570 398 return u.d;
tomwalters@570 399 #else
tomwalters@570 400 return *(double*)argument_;
tomwalters@570 401 #endif
tomwalters@570 402 }
tomwalters@570 403
tomwalters@570 404
tomwalters@570 405 const char* ReceivedMessageArgument::AsString() const
tomwalters@570 406 {
tomwalters@570 407 if( !typeTag_ )
tomwalters@570 408 throw MissingArgumentException();
tomwalters@570 409 else if( *typeTag_ == STRING_TYPE_TAG )
tomwalters@570 410 return argument_;
tomwalters@570 411 else
tomwalters@570 412 throw WrongArgumentTypeException();
tomwalters@570 413 }
tomwalters@570 414
tomwalters@570 415
tomwalters@570 416 const char* ReceivedMessageArgument::AsSymbol() const
tomwalters@570 417 {
tomwalters@570 418 if( !typeTag_ )
tomwalters@570 419 throw MissingArgumentException();
tomwalters@570 420 else if( *typeTag_ == SYMBOL_TYPE_TAG )
tomwalters@570 421 return argument_;
tomwalters@570 422 else
tomwalters@570 423 throw WrongArgumentTypeException();
tomwalters@570 424 }
tomwalters@570 425
tomwalters@570 426
tomwalters@570 427 void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
tomwalters@570 428 {
tomwalters@570 429 if( !typeTag_ )
tomwalters@570 430 throw MissingArgumentException();
tomwalters@570 431 else if( *typeTag_ == BLOB_TYPE_TAG )
tomwalters@570 432 AsBlobUnchecked( data, size );
tomwalters@570 433 else
tomwalters@570 434 throw WrongArgumentTypeException();
tomwalters@570 435 }
tomwalters@570 436
tomwalters@570 437
tomwalters@570 438 void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
tomwalters@570 439 {
tomwalters@570 440 size = ToUInt32( argument_ );
tomwalters@570 441 data = (void*)(argument_+4);
tomwalters@570 442 }
tomwalters@570 443
tomwalters@570 444 //------------------------------------------------------------------------------
tomwalters@570 445
tomwalters@570 446 void ReceivedMessageArgumentIterator::Advance()
tomwalters@570 447 {
tomwalters@570 448 if( !value_.typeTag_ )
tomwalters@570 449 return;
tomwalters@570 450
tomwalters@570 451 switch( *value_.typeTag_++ ){
tomwalters@570 452 case '\0':
tomwalters@570 453 // don't advance past end
tomwalters@570 454 --value_.typeTag_;
tomwalters@570 455 break;
tomwalters@570 456
tomwalters@570 457 case TRUE_TYPE_TAG:
tomwalters@570 458 case FALSE_TYPE_TAG:
tomwalters@570 459 case NIL_TYPE_TAG:
tomwalters@570 460 case INFINITUM_TYPE_TAG:
tomwalters@570 461
tomwalters@570 462 // zero length
tomwalters@570 463 break;
tomwalters@570 464
tomwalters@570 465 case INT32_TYPE_TAG:
tomwalters@570 466 case FLOAT_TYPE_TAG:
tomwalters@570 467 case CHAR_TYPE_TAG:
tomwalters@570 468 case RGBA_COLOR_TYPE_TAG:
tomwalters@570 469 case MIDI_MESSAGE_TYPE_TAG:
tomwalters@570 470
tomwalters@570 471 value_.argument_ += 4;
tomwalters@570 472 break;
tomwalters@570 473
tomwalters@570 474 case INT64_TYPE_TAG:
tomwalters@570 475 case TIME_TAG_TYPE_TAG:
tomwalters@570 476 case DOUBLE_TYPE_TAG:
tomwalters@570 477
tomwalters@570 478 value_.argument_ += 8;
tomwalters@570 479 break;
tomwalters@570 480
tomwalters@570 481 case STRING_TYPE_TAG:
tomwalters@570 482 case SYMBOL_TYPE_TAG:
tomwalters@570 483
tomwalters@570 484 // we use the unsafe function FindStr4End(char*) here because all of
tomwalters@570 485 // the arguments have already been validated in
tomwalters@570 486 // ReceivedMessage::Init() below.
tomwalters@570 487
tomwalters@570 488 value_.argument_ = FindStr4End( value_.argument_ );
tomwalters@570 489 break;
tomwalters@570 490
tomwalters@570 491 case BLOB_TYPE_TAG:
tomwalters@570 492 {
tomwalters@570 493 uint32 blobSize = ToUInt32( value_.argument_ );
tomwalters@570 494 value_.argument_ = value_.argument_ + 4 + RoundUp4( blobSize );
tomwalters@570 495 }
tomwalters@570 496 break;
tomwalters@570 497
tomwalters@570 498 default: // unknown type tag
tomwalters@570 499 // don't advance
tomwalters@570 500 --value_.typeTag_;
tomwalters@570 501 break;
tomwalters@570 502
tomwalters@570 503
tomwalters@570 504 // not handled:
tomwalters@570 505 // [ Indicates the beginning of an array. The tags following are for
tomwalters@570 506 // data in the Array until a close brace tag is reached.
tomwalters@570 507 // ] Indicates the end of an array.
tomwalters@570 508 }
tomwalters@570 509 }
tomwalters@570 510
tomwalters@570 511 //------------------------------------------------------------------------------
tomwalters@570 512
tomwalters@570 513 ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
tomwalters@570 514 : addressPattern_( packet.Contents() )
tomwalters@570 515 {
tomwalters@570 516 Init( packet.Contents(), packet.Size() );
tomwalters@570 517 }
tomwalters@570 518
tomwalters@570 519
tomwalters@570 520 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
tomwalters@570 521 : addressPattern_( bundleElement.Contents() )
tomwalters@570 522 {
tomwalters@570 523 Init( bundleElement.Contents(), bundleElement.Size() );
tomwalters@570 524 }
tomwalters@570 525
tomwalters@570 526
tomwalters@570 527 bool ReceivedMessage::AddressPatternIsUInt32() const
tomwalters@570 528 {
tomwalters@570 529 return (addressPattern_[0] == '\0');
tomwalters@570 530 }
tomwalters@570 531
tomwalters@570 532
tomwalters@570 533 uint32 ReceivedMessage::AddressPatternAsUInt32() const
tomwalters@570 534 {
tomwalters@570 535 return ToUInt32( addressPattern_ );
tomwalters@570 536 }
tomwalters@570 537
tomwalters@570 538
tomwalters@570 539 void ReceivedMessage::Init( const char *message, unsigned long size )
tomwalters@570 540 {
tomwalters@570 541 if( size == 0 )
tomwalters@570 542 throw MalformedMessageException( "zero length messages not permitted" );
tomwalters@570 543
tomwalters@570 544 if( (size & 0x03L) != 0 )
tomwalters@570 545 throw MalformedMessageException( "message size must be multiple of four" );
tomwalters@570 546
tomwalters@570 547 const char *end = message + size;
tomwalters@570 548
tomwalters@570 549 typeTagsBegin_ = FindStr4End( addressPattern_, end );
tomwalters@570 550 if( typeTagsBegin_ == 0 ){
tomwalters@570 551 // address pattern was not terminated before end
tomwalters@570 552 throw MalformedMessageException( "unterminated address pattern" );
tomwalters@570 553 }
tomwalters@570 554
tomwalters@570 555 if( typeTagsBegin_ == end ){
tomwalters@570 556 // message consists of only the address pattern - no arguments or type tags.
tomwalters@570 557 typeTagsBegin_ = 0;
tomwalters@570 558 typeTagsEnd_ = 0;
tomwalters@570 559 arguments_ = 0;
tomwalters@570 560
tomwalters@570 561 }else{
tomwalters@570 562 if( *typeTagsBegin_ != ',' )
tomwalters@570 563 throw MalformedMessageException( "type tags not present" );
tomwalters@570 564
tomwalters@570 565 if( *(typeTagsBegin_ + 1) == '\0' ){
tomwalters@570 566 // zero length type tags
tomwalters@570 567 typeTagsBegin_ = 0;
tomwalters@570 568 typeTagsEnd_ = 0;
tomwalters@570 569 arguments_ = 0;
tomwalters@570 570
tomwalters@570 571 }else{
tomwalters@570 572 // check that all arguments are present and well formed
tomwalters@570 573
tomwalters@570 574 arguments_ = FindStr4End( typeTagsBegin_, end );
tomwalters@570 575 if( arguments_ == 0 ){
tomwalters@570 576 throw MalformedMessageException( "type tags were not terminated before end of message" );
tomwalters@570 577 }
tomwalters@570 578
tomwalters@570 579 ++typeTagsBegin_; // advance past initial ','
tomwalters@570 580
tomwalters@570 581 const char *typeTag = typeTagsBegin_;
tomwalters@570 582 const char *argument = arguments_;
tomwalters@570 583
tomwalters@570 584 do{
tomwalters@570 585 switch( *typeTag ){
tomwalters@570 586 case TRUE_TYPE_TAG:
tomwalters@570 587 case FALSE_TYPE_TAG:
tomwalters@570 588 case NIL_TYPE_TAG:
tomwalters@570 589 case INFINITUM_TYPE_TAG:
tomwalters@570 590
tomwalters@570 591 // zero length
tomwalters@570 592 break;
tomwalters@570 593
tomwalters@570 594 case INT32_TYPE_TAG:
tomwalters@570 595 case FLOAT_TYPE_TAG:
tomwalters@570 596 case CHAR_TYPE_TAG:
tomwalters@570 597 case RGBA_COLOR_TYPE_TAG:
tomwalters@570 598 case MIDI_MESSAGE_TYPE_TAG:
tomwalters@570 599
tomwalters@570 600 if( argument == end )
tomwalters@570 601 throw MalformedMessageException( "arguments exceed message size" );
tomwalters@570 602 argument += 4;
tomwalters@570 603 if( argument > end )
tomwalters@570 604 throw MalformedMessageException( "arguments exceed message size" );
tomwalters@570 605 break;
tomwalters@570 606
tomwalters@570 607 case INT64_TYPE_TAG:
tomwalters@570 608 case TIME_TAG_TYPE_TAG:
tomwalters@570 609 case DOUBLE_TYPE_TAG:
tomwalters@570 610
tomwalters@570 611 if( argument == end )
tomwalters@570 612 throw MalformedMessageException( "arguments exceed message size" );
tomwalters@570 613 argument += 8;
tomwalters@570 614 if( argument > end )
tomwalters@570 615 throw MalformedMessageException( "arguments exceed message size" );
tomwalters@570 616 break;
tomwalters@570 617
tomwalters@570 618 case STRING_TYPE_TAG:
tomwalters@570 619 case SYMBOL_TYPE_TAG:
tomwalters@570 620
tomwalters@570 621 if( argument == end )
tomwalters@570 622 throw MalformedMessageException( "arguments exceed message size" );
tomwalters@570 623 argument = FindStr4End( argument, end );
tomwalters@570 624 if( argument == 0 )
tomwalters@570 625 throw MalformedMessageException( "unterminated string argument" );
tomwalters@570 626 break;
tomwalters@570 627
tomwalters@570 628 case BLOB_TYPE_TAG:
tomwalters@570 629 {
tomwalters@570 630 if( argument + 4 > end )
tomwalters@570 631 MalformedMessageException( "arguments exceed message size" );
tomwalters@570 632
tomwalters@570 633 uint32 blobSize = ToUInt32( argument );
tomwalters@570 634 argument = argument + 4 + RoundUp4( blobSize );
tomwalters@570 635 if( argument > end )
tomwalters@570 636 MalformedMessageException( "arguments exceed message size" );
tomwalters@570 637 }
tomwalters@570 638 break;
tomwalters@570 639
tomwalters@570 640 default:
tomwalters@570 641 throw MalformedMessageException( "unknown type tag" );
tomwalters@570 642
tomwalters@570 643 // not handled:
tomwalters@570 644 // [ Indicates the beginning of an array. The tags following are for
tomwalters@570 645 // data in the Array until a close brace tag is reached.
tomwalters@570 646 // ] Indicates the end of an array.
tomwalters@570 647 }
tomwalters@570 648
tomwalters@570 649 }while( *++typeTag != '\0' );
tomwalters@570 650 typeTagsEnd_ = typeTag;
tomwalters@570 651 }
tomwalters@570 652 }
tomwalters@570 653 }
tomwalters@570 654
tomwalters@570 655 //------------------------------------------------------------------------------
tomwalters@570 656
tomwalters@570 657 ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
tomwalters@570 658 : elementCount_( 0 )
tomwalters@570 659 {
tomwalters@570 660 Init( packet.Contents(), packet.Size() );
tomwalters@570 661 }
tomwalters@570 662
tomwalters@570 663
tomwalters@570 664 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
tomwalters@570 665 : elementCount_( 0 )
tomwalters@570 666 {
tomwalters@570 667 Init( bundleElement.Contents(), bundleElement.Size() );
tomwalters@570 668 }
tomwalters@570 669
tomwalters@570 670
tomwalters@570 671 void ReceivedBundle::Init( const char *bundle, unsigned long size )
tomwalters@570 672 {
tomwalters@570 673 if( size < 16 )
tomwalters@570 674 throw MalformedBundleException( "packet too short for bundle" );
tomwalters@570 675
tomwalters@570 676 if( (size & 0x03L) != 0 )
tomwalters@570 677 throw MalformedBundleException( "bundle size must be multiple of four" );
tomwalters@570 678
tomwalters@570 679 if( bundle[0] != '#'
tomwalters@570 680 || bundle[1] != 'b'
tomwalters@570 681 || bundle[2] != 'u'
tomwalters@570 682 || bundle[3] != 'n'
tomwalters@570 683 || bundle[4] != 'd'
tomwalters@570 684 || bundle[5] != 'l'
tomwalters@570 685 || bundle[6] != 'e'
tomwalters@570 686 || bundle[7] != '\0' )
tomwalters@570 687 throw MalformedBundleException( "bad bundle address pattern" );
tomwalters@570 688
tomwalters@570 689 end_ = bundle + size;
tomwalters@570 690
tomwalters@570 691 timeTag_ = bundle + 8;
tomwalters@570 692
tomwalters@570 693 const char *p = timeTag_ + 8;
tomwalters@570 694
tomwalters@570 695 while( p < end_ ){
tomwalters@570 696 if( p + 4 > end_ )
tomwalters@570 697 throw MalformedBundleException( "packet too short for elementSize" );
tomwalters@570 698
tomwalters@570 699 uint32 elementSize = ToUInt32( p );
tomwalters@570 700 if( (elementSize & 0x03L) != 0 )
tomwalters@570 701 throw MalformedBundleException( "bundle element size must be multiple of four" );
tomwalters@570 702
tomwalters@570 703 p += 4 + elementSize;
tomwalters@570 704 if( p > end_ )
tomwalters@570 705 throw MalformedBundleException( "packet too short for bundle element" );
tomwalters@570 706
tomwalters@570 707 ++elementCount_;
tomwalters@570 708 }
tomwalters@570 709
tomwalters@570 710 if( p != end_ )
tomwalters@570 711 throw MalformedBundleException( "bundle contents " );
tomwalters@570 712 }
tomwalters@570 713
tomwalters@570 714
tomwalters@570 715 uint64 ReceivedBundle::TimeTag() const
tomwalters@570 716 {
tomwalters@570 717 return ToUInt64( timeTag_ );
tomwalters@570 718 }
tomwalters@570 719
tomwalters@570 720
tomwalters@570 721 } // namespace osc
tomwalters@570 722