annotate external/oscpack/osc/OscReceivedElements.cpp @ 509:0284d2152e17

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