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