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