cmake build system: visiblity support for clang
[supercollider.git] / external_libraries / oscpack / osc / OscReceivedElements.cpp
blobb2248cdcd4f9bc7c900f61ccaec1db7c665ab702
1 /*
2 oscpack -- Open Sound Control packet manipulation library
3 http://www.audiomulch.com/~rossb/oscpack
5 Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
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:
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
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.
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.
30 #include "OscReceivedElements.h"
32 #include <cassert>
34 #include "OscHostEndianness.h"
37 namespace osc{
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 )
45 if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
46 return p + 4;
48 p += 3;
50 while( *p )
51 p += 4;
53 return p + 1;
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 )
61 if( p >= end )
62 return 0;
64 if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
65 return p + 4;
67 p += 3;
68 end -= 1;
70 while( p < end && *p )
71 p += 4;
73 if( *p )
74 return 0;
75 else
76 return p + 1;
80 static inline unsigned long RoundUp4( unsigned long x )
82 unsigned long remainder = x & 0x3UL;
83 if( remainder )
84 return x + (4 - remainder);
85 else
86 return x;
90 static inline int32 ToInt32( const char *p )
92 #ifdef OSC_HOST_LITTLE_ENDIAN
93 union{
94 osc::int32 i;
95 char c[4];
96 } u;
98 u.c[0] = p[3];
99 u.c[1] = p[2];
100 u.c[2] = p[1];
101 u.c[3] = p[0];
103 return u.i;
104 #else
105 return *(int32*)p;
106 #endif
110 static inline uint32 ToUInt32( const char *p )
112 #ifdef OSC_HOST_LITTLE_ENDIAN
113 union{
114 osc::uint32 i;
115 char c[4];
116 } u;
118 u.c[0] = p[3];
119 u.c[1] = p[2];
120 u.c[2] = p[1];
121 u.c[3] = p[0];
123 return u.i;
124 #else
125 return *(uint32*)p;
126 #endif
130 int64 ToInt64( const char *p )
132 #ifdef OSC_HOST_LITTLE_ENDIAN
133 union{
134 osc::int64 i;
135 char c[8];
136 } u;
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];
147 return u.i;
148 #else
149 return *(int64*)p;
150 #endif
154 uint64 ToUInt64( const char *p )
156 #ifdef OSC_HOST_LITTLE_ENDIAN
157 union{
158 osc::uint64 i;
159 char c[8];
160 } u;
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];
171 return u.i;
172 #else
173 return *(uint64*)p;
174 #endif
177 //------------------------------------------------------------------------------
179 bool ReceivedPacket::IsBundle() const
181 return (Size() > 0 && Contents()[0] == '#');
184 //------------------------------------------------------------------------------
186 bool ReceivedBundleElement::IsBundle() const
188 return (Size() > 0 && Contents()[0] == '#');
192 int32 ReceivedBundleElement::Size() const
194 return ToUInt32( size_ );
197 //------------------------------------------------------------------------------
199 bool ReceivedMessageArgument::AsBool() const
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();
212 bool ReceivedMessageArgument::AsBoolUnchecked() const
214 if( !typeTag_ )
215 throw MissingArgumentException();
216 else if( *typeTag_ == TRUE_TYPE_TAG )
217 return true;
218 else
219 return false;
223 int32 ReceivedMessageArgument::AsInt32() const
225 if( !typeTag_ )
226 throw MissingArgumentException();
227 else if( *typeTag_ == INT32_TYPE_TAG )
228 return AsInt32Unchecked();
229 else
230 throw WrongArgumentTypeException();
234 int32 ReceivedMessageArgument::AsInt32Unchecked() const
236 #ifdef OSC_HOST_LITTLE_ENDIAN
237 union{
238 osc::int32 i;
239 char c[4];
240 } u;
242 u.c[0] = argument_[3];
243 u.c[1] = argument_[2];
244 u.c[2] = argument_[1];
245 u.c[3] = argument_[0];
247 return u.i;
248 #else
249 return *(int32*)argument_;
250 #endif
254 float ReceivedMessageArgument::AsFloat() const
256 if( !typeTag_ )
257 throw MissingArgumentException();
258 else if( *typeTag_ == FLOAT_TYPE_TAG )
259 return AsFloatUnchecked();
260 else
261 throw WrongArgumentTypeException();
265 float ReceivedMessageArgument::AsFloatUnchecked() const
267 #ifdef OSC_HOST_LITTLE_ENDIAN
268 union{
269 float f;
270 char c[4];
271 } u;
273 u.c[0] = argument_[3];
274 u.c[1] = argument_[2];
275 u.c[2] = argument_[1];
276 u.c[3] = argument_[0];
278 return u.f;
279 #else
280 return *(float*)argument_;
281 #endif
285 char ReceivedMessageArgument::AsChar() const
287 if( !typeTag_ )
288 throw MissingArgumentException();
289 else if( *typeTag_ == CHAR_TYPE_TAG )
290 return AsCharUnchecked();
291 else
292 throw WrongArgumentTypeException();
296 char ReceivedMessageArgument::AsCharUnchecked() const
298 return (char)ToInt32( argument_ );
302 uint32 ReceivedMessageArgument::AsRgbaColor() const
304 if( !typeTag_ )
305 throw MissingArgumentException();
306 else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
307 return AsRgbaColorUnchecked();
308 else
309 throw WrongArgumentTypeException();
313 uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
315 return ToUInt32( argument_ );
319 uint32 ReceivedMessageArgument::AsMidiMessage() const
321 if( !typeTag_ )
322 throw MissingArgumentException();
323 else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
324 return AsMidiMessageUnchecked();
325 else
326 throw WrongArgumentTypeException();
330 uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
332 return ToUInt32( argument_ );
336 int64 ReceivedMessageArgument::AsInt64() const
338 if( !typeTag_ )
339 throw MissingArgumentException();
340 else if( *typeTag_ == INT64_TYPE_TAG )
341 return AsInt64Unchecked();
342 else
343 throw WrongArgumentTypeException();
347 int64 ReceivedMessageArgument::AsInt64Unchecked() const
349 return ToInt64( argument_ );
353 uint64 ReceivedMessageArgument::AsTimeTag() const
355 if( !typeTag_ )
356 throw MissingArgumentException();
357 else if( *typeTag_ == TIME_TAG_TYPE_TAG )
358 return AsTimeTagUnchecked();
359 else
360 throw WrongArgumentTypeException();
364 uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
366 return ToUInt64( argument_ );
370 double ReceivedMessageArgument::AsDouble() const
372 if( !typeTag_ )
373 throw MissingArgumentException();
374 else if( *typeTag_ == DOUBLE_TYPE_TAG )
375 return AsDoubleUnchecked();
376 else
377 throw WrongArgumentTypeException();
381 double ReceivedMessageArgument::AsDoubleUnchecked() const
383 #ifdef OSC_HOST_LITTLE_ENDIAN
384 union{
385 double d;
386 char c[8];
387 } u;
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];
398 return u.d;
399 #else
400 return *(double*)argument_;
401 #endif
405 const char* ReceivedMessageArgument::AsString() const
407 if( !typeTag_ )
408 throw MissingArgumentException();
409 else if( *typeTag_ == STRING_TYPE_TAG )
410 return argument_;
411 else
412 throw WrongArgumentTypeException();
416 const char* ReceivedMessageArgument::AsSymbol() const
418 if( !typeTag_ )
419 throw MissingArgumentException();
420 else if( *typeTag_ == SYMBOL_TYPE_TAG )
421 return argument_;
422 else
423 throw WrongArgumentTypeException();
427 void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
429 if( !typeTag_ )
430 throw MissingArgumentException();
431 else if( *typeTag_ == BLOB_TYPE_TAG )
432 AsBlobUnchecked( data, size );
433 else
434 throw WrongArgumentTypeException();
438 void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
440 size = ToUInt32( argument_ );
441 data = (void*)(argument_+4);
444 std::size_t ReceivedMessageArgument::ArraySize() const
446 std::size_t ret = 0;
447 unsigned int level = 0;
448 const char * type_tag = typeTag_ + 1;
450 while( *type_tag ) {
451 switch (*type_tag++) {
452 case ARRAY_START_TYPE_TAG:
453 level += 1;
454 break;
456 case ARRAY_END_TYPE_TAG:
457 if (level == 0)
458 return ret;
459 level -= 1;
460 break;
462 default:
463 ret += 1;
466 return ret;
470 //------------------------------------------------------------------------------
472 void ReceivedMessageArgumentIterator::Advance()
474 if( !value_.typeTag_ )
475 return;
477 switch( *value_.typeTag_++ ){
478 case '\0':
479 // don't advance past end
480 --value_.typeTag_;
481 break;
483 case TRUE_TYPE_TAG:
484 case FALSE_TYPE_TAG:
485 case NIL_TYPE_TAG:
486 case INFINITUM_TYPE_TAG:
487 case ARRAY_START_TYPE_TAG:
488 case ARRAY_END_TYPE_TAG:
490 // zero length
491 break;
493 case INT32_TYPE_TAG:
494 case FLOAT_TYPE_TAG:
495 case CHAR_TYPE_TAG:
496 case RGBA_COLOR_TYPE_TAG:
497 case MIDI_MESSAGE_TYPE_TAG:
499 value_.argument_ += 4;
500 break;
502 case INT64_TYPE_TAG:
503 case TIME_TAG_TYPE_TAG:
504 case DOUBLE_TYPE_TAG:
506 value_.argument_ += 8;
507 break;
509 case STRING_TYPE_TAG:
510 case SYMBOL_TYPE_TAG:
512 // we use the unsafe function FindStr4End(char*) here because all of
513 // the arguments have already been validated in
514 // ReceivedMessage::Init() below.
516 value_.argument_ = FindStr4End( value_.argument_ );
517 break;
519 case BLOB_TYPE_TAG:
521 uint32 blobSize = ToUInt32( value_.argument_ );
522 value_.argument_ = value_.argument_ + 4 + RoundUp4( (unsigned long)blobSize );
524 break;
526 default: // unknown type tag
527 // don't advance
528 --value_.typeTag_;
529 break;
533 //------------------------------------------------------------------------------
535 ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
536 : addressPattern_( packet.Contents() )
538 Init( packet.Contents(), packet.Size() );
542 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
543 : addressPattern_( bundleElement.Contents() )
545 Init( bundleElement.Contents(), bundleElement.Size() );
549 bool ReceivedMessage::AddressPatternIsUInt32() const
551 return (addressPattern_[0] == '\0');
555 uint32 ReceivedMessage::AddressPatternAsUInt32() const
557 return ToUInt32( addressPattern_ );
561 void ReceivedMessage::Init( const char *message, unsigned long size )
563 if( size == 0 )
564 throw MalformedMessageException( "zero length messages not permitted" );
566 if( (size & 0x03L) != 0 )
567 throw MalformedMessageException( "message size must be multiple of four" );
569 const char *end = message + size;
571 typeTagsBegin_ = FindStr4End( addressPattern_, end );
572 if( typeTagsBegin_ == 0 ){
573 // address pattern was not terminated before end
574 throw MalformedMessageException( "unterminated address pattern" );
577 if( typeTagsBegin_ == end ){
578 // message consists of only the address pattern - no arguments or type tags.
579 typeTagsBegin_ = 0;
580 typeTagsEnd_ = 0;
581 arguments_ = 0;
583 }else{
584 if( *typeTagsBegin_ != ',' )
585 throw MalformedMessageException( "type tags not present" );
587 if( *(typeTagsBegin_ + 1) == '\0' ){
588 // zero length type tags
589 typeTagsBegin_ = 0;
590 typeTagsEnd_ = 0;
591 arguments_ = 0;
593 }else{
594 // check that all arguments are present and well formed
596 arguments_ = FindStr4End( typeTagsBegin_, end );
597 if( arguments_ == 0 ){
598 throw MalformedMessageException( "type tags were not terminated before end of message" );
601 ++typeTagsBegin_; // advance past initial ','
603 const char *typeTag = typeTagsBegin_;
604 const char *argument = arguments_;
607 switch( *typeTag ){
608 case TRUE_TYPE_TAG:
609 case FALSE_TYPE_TAG:
610 case NIL_TYPE_TAG:
611 case INFINITUM_TYPE_TAG:
612 case ARRAY_START_TYPE_TAG:
613 case ARRAY_END_TYPE_TAG:
615 // zero length
616 break;
618 case INT32_TYPE_TAG:
619 case FLOAT_TYPE_TAG:
620 case CHAR_TYPE_TAG:
621 case RGBA_COLOR_TYPE_TAG:
622 case MIDI_MESSAGE_TYPE_TAG:
624 if( argument == end )
625 throw MalformedMessageException( "arguments exceed message size" );
626 argument += 4;
627 if( argument > end )
628 throw MalformedMessageException( "arguments exceed message size" );
629 break;
631 case INT64_TYPE_TAG:
632 case TIME_TAG_TYPE_TAG:
633 case DOUBLE_TYPE_TAG:
635 if( argument == end )
636 throw MalformedMessageException( "arguments exceed message size" );
637 argument += 8;
638 if( argument > end )
639 throw MalformedMessageException( "arguments exceed message size" );
640 break;
642 case STRING_TYPE_TAG:
643 case SYMBOL_TYPE_TAG:
645 if( argument == end )
646 throw MalformedMessageException( "arguments exceed message size" );
647 argument = FindStr4End( argument, end );
648 if( argument == 0 )
649 throw MalformedMessageException( "unterminated string argument" );
650 break;
652 case BLOB_TYPE_TAG:
654 if( argument + 4 > end )
655 MalformedMessageException( "arguments exceed message size" );
657 uint32 blobSize = ToUInt32( argument );
658 argument = argument + 4 + RoundUp4( (unsigned long)blobSize );
659 if( argument > end )
660 MalformedMessageException( "arguments exceed message size" );
662 break;
664 default:
665 throw MalformedMessageException( "unknown type tag" );
667 // not handled:
668 // [ Indicates the beginning of an array. The tags following are for
669 // data in the Array until a close brace tag is reached.
670 // ] Indicates the end of an array.
673 }while( *++typeTag != '\0' );
674 typeTagsEnd_ = typeTag;
679 //------------------------------------------------------------------------------
681 ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
682 : elementCount_( 0 )
684 Init( packet.Contents(), packet.Size() );
688 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
689 : elementCount_( 0 )
691 Init( bundleElement.Contents(), bundleElement.Size() );
695 void ReceivedBundle::Init( const char *bundle, unsigned long size )
697 if( size < 16 )
698 throw MalformedBundleException( "packet too short for bundle" );
700 if( (size & 0x03L) != 0 )
701 throw MalformedBundleException( "bundle size must be multiple of four" );
703 if( bundle[0] != '#'
704 || bundle[1] != 'b'
705 || bundle[2] != 'u'
706 || bundle[3] != 'n'
707 || bundle[4] != 'd'
708 || bundle[5] != 'l'
709 || bundle[6] != 'e'
710 || bundle[7] != '\0' )
711 throw MalformedBundleException( "bad bundle address pattern" );
713 end_ = bundle + size;
715 timeTag_ = bundle + 8;
717 const char *p = timeTag_ + 8;
719 while( p < end_ ){
720 if( p + 4 > end_ )
721 throw MalformedBundleException( "packet too short for elementSize" );
723 uint32 elementSize = ToUInt32( p );
724 if( (elementSize & 0x03L) != 0 )
725 throw MalformedBundleException( "bundle element size must be multiple of four" );
727 p += 4 + elementSize;
728 if( p > end_ )
729 throw MalformedBundleException( "packet too short for bundle element" );
731 ++elementCount_;
734 if( p != end_ )
735 throw MalformedBundleException( "bundle contents " );
739 uint64 ReceivedBundle::TimeTag() const
741 return ToUInt64( timeTag_ );
745 } // namespace osc