You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

549 lines
15KB

  1. /*
  2. oscpack -- Open Sound Control (OSC) packet manipulation library
  3. http://www.rossbencina.com/code/oscpack
  4. Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
  5. Permission is hereby granted, free of charge, to any person obtaining
  6. a copy of this software and associated documentation files
  7. (the "Software"), to deal in the Software without restriction,
  8. including without limitation the rights to use, copy, modify, merge,
  9. publish, distribute, sublicense, and/or sell copies of the Software,
  10. and to permit persons to whom the Software is furnished to do so,
  11. subject to the following conditions:
  12. The above copyright notice and this permission notice shall be
  13. included in all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  17. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  18. ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. /*
  23. The text above constitutes the entire oscpack license; however,
  24. the oscpack developer(s) also make the following non-binding requests:
  25. Any person wishing to distribute modifications to the Software is
  26. requested to send the modifications to the original developer so that
  27. they can be incorporated into the canonical version. It is also
  28. requested that these non-binding requests be included whenever the
  29. above license is reproduced.
  30. */
  31. #ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
  32. #define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H
  33. #include <cassert>
  34. #include <cstddef>
  35. #include <cstring> // size_t
  36. #include "OscTypes.h"
  37. #include "OscException.h"
  38. namespace osc{
  39. class MalformedPacketException : public Exception{
  40. public:
  41. MalformedPacketException( const char *w="malformed packet" )
  42. : Exception( w ) {}
  43. };
  44. class MalformedMessageException : public Exception{
  45. public:
  46. MalformedMessageException( const char *w="malformed message" )
  47. : Exception( w ) {}
  48. };
  49. class MalformedBundleException : public Exception{
  50. public:
  51. MalformedBundleException( const char *w="malformed bundle" )
  52. : Exception( w ) {}
  53. };
  54. class WrongArgumentTypeException : public Exception{
  55. public:
  56. WrongArgumentTypeException( const char *w="wrong argument type" )
  57. : Exception( w ) {}
  58. };
  59. class MissingArgumentException : public Exception{
  60. public:
  61. MissingArgumentException( const char *w="missing argument" )
  62. : Exception( w ) {}
  63. };
  64. class ExcessArgumentException : public Exception{
  65. public:
  66. ExcessArgumentException( const char *w="too many arguments" )
  67. : Exception( w ) {}
  68. };
  69. class ReceivedPacket{
  70. public:
  71. // Although the OSC spec is not entirely clear on this, we only support
  72. // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value
  73. // representable by an int32). An exception will be raised if you pass a
  74. // larger value to the ReceivedPacket() constructor.
  75. ReceivedPacket( const char *contents, osc_bundle_element_size_t size )
  76. : contents_( contents )
  77. , size_( ValidateSize(size) ) {}
  78. ReceivedPacket( const char *contents, std::size_t size )
  79. : contents_( contents )
  80. , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
  81. #if !(defined(__x86_64__) || defined(_M_X64))
  82. ReceivedPacket( const char *contents, int size )
  83. : contents_( contents )
  84. , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {}
  85. #endif
  86. bool IsMessage() const { return !IsBundle(); }
  87. bool IsBundle() const;
  88. osc_bundle_element_size_t Size() const { return size_; }
  89. const char *Contents() const { return contents_; }
  90. private:
  91. const char *contents_;
  92. osc_bundle_element_size_t size_;
  93. static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size )
  94. {
  95. // sanity check integer types declared in OscTypes.h
  96. // you'll need to fix OscTypes.h if any of these asserts fail
  97. assert( sizeof(osc::int32) == 4 );
  98. assert( sizeof(osc::uint32) == 4 );
  99. assert( sizeof(osc::int64) == 8 );
  100. assert( sizeof(osc::uint64) == 8 );
  101. if( !IsValidElementSizeValue(size) )
  102. throw MalformedPacketException( "invalid packet size" );
  103. if( size == 0 )
  104. throw MalformedPacketException( "zero length elements not permitted" );
  105. if( !IsMultipleOf4(size) )
  106. throw MalformedPacketException( "element size must be multiple of four" );
  107. return size;
  108. }
  109. };
  110. class ReceivedBundleElement{
  111. public:
  112. ReceivedBundleElement( const char *sizePtr )
  113. : sizePtr_( sizePtr ) {}
  114. friend class ReceivedBundleElementIterator;
  115. bool IsMessage() const { return !IsBundle(); }
  116. bool IsBundle() const;
  117. osc_bundle_element_size_t Size() const;
  118. const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; }
  119. private:
  120. const char *sizePtr_;
  121. };
  122. class ReceivedBundleElementIterator{
  123. public:
  124. ReceivedBundleElementIterator( const char *sizePtr )
  125. : value_( sizePtr ) {}
  126. ReceivedBundleElementIterator operator++()
  127. {
  128. Advance();
  129. return *this;
  130. }
  131. ReceivedBundleElementIterator operator++(int)
  132. {
  133. ReceivedBundleElementIterator old( *this );
  134. Advance();
  135. return old;
  136. }
  137. const ReceivedBundleElement& operator*() const { return value_; }
  138. const ReceivedBundleElement* operator->() const { return &value_; }
  139. friend bool operator==(const ReceivedBundleElementIterator& lhs,
  140. const ReceivedBundleElementIterator& rhs );
  141. private:
  142. ReceivedBundleElement value_;
  143. void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); }
  144. bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
  145. {
  146. return value_.sizePtr_ == rhs.value_.sizePtr_;
  147. }
  148. };
  149. inline bool operator==(const ReceivedBundleElementIterator& lhs,
  150. const ReceivedBundleElementIterator& rhs )
  151. {
  152. return lhs.IsEqualTo( rhs );
  153. }
  154. inline bool operator!=(const ReceivedBundleElementIterator& lhs,
  155. const ReceivedBundleElementIterator& rhs )
  156. {
  157. return !( lhs == rhs );
  158. }
  159. class ReceivedMessageArgument{
  160. public:
  161. ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr )
  162. : typeTagPtr_( typeTagPtr )
  163. , argumentPtr_( argumentPtr ) {}
  164. friend class ReceivedMessageArgumentIterator;
  165. char TypeTag() const { return *typeTagPtr_; }
  166. // the unchecked methods below don't check whether the argument actually
  167. // is of the specified type. they should only be used if you've already
  168. // checked the type tag or the associated IsType() method.
  169. bool IsBool() const
  170. { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; }
  171. bool AsBool() const;
  172. bool AsBoolUnchecked() const;
  173. bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; }
  174. bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; }
  175. bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; }
  176. int32 AsInt32() const;
  177. int32 AsInt32Unchecked() const;
  178. bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; }
  179. float AsFloat() const;
  180. float AsFloatUnchecked() const;
  181. bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; }
  182. char AsChar() const;
  183. char AsCharUnchecked() const;
  184. bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; }
  185. uint32 AsRgbaColor() const;
  186. uint32 AsRgbaColorUnchecked() const;
  187. bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; }
  188. uint32 AsMidiMessage() const;
  189. uint32 AsMidiMessageUnchecked() const;
  190. bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; }
  191. int64 AsInt64() const;
  192. int64 AsInt64Unchecked() const;
  193. bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; }
  194. uint64 AsTimeTag() const;
  195. uint64 AsTimeTagUnchecked() const;
  196. bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; }
  197. double AsDouble() const;
  198. double AsDoubleUnchecked() const;
  199. bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; }
  200. const char* AsString() const;
  201. const char* AsStringUnchecked() const { return argumentPtr_; }
  202. bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; }
  203. const char* AsSymbol() const;
  204. const char* AsSymbolUnchecked() const { return argumentPtr_; }
  205. bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; }
  206. void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const;
  207. void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const;
  208. bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; }
  209. bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; }
  210. // Calculate the number of top-level items in the array. Nested arrays count as one item.
  211. // Only valid at array start. Will throw an exception if IsArrayStart() == false.
  212. std::size_t ComputeArrayItemCount() const;
  213. private:
  214. const char *typeTagPtr_;
  215. const char *argumentPtr_;
  216. };
  217. class ReceivedMessageArgumentIterator{
  218. public:
  219. ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments )
  220. : value_( typeTags, arguments ) {}
  221. ReceivedMessageArgumentIterator operator++()
  222. {
  223. Advance();
  224. return *this;
  225. }
  226. ReceivedMessageArgumentIterator operator++(int)
  227. {
  228. ReceivedMessageArgumentIterator old( *this );
  229. Advance();
  230. return old;
  231. }
  232. const ReceivedMessageArgument& operator*() const { return value_; }
  233. const ReceivedMessageArgument* operator->() const { return &value_; }
  234. friend bool operator==(const ReceivedMessageArgumentIterator& lhs,
  235. const ReceivedMessageArgumentIterator& rhs );
  236. private:
  237. ReceivedMessageArgument value_;
  238. void Advance();
  239. bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
  240. {
  241. return value_.typeTagPtr_ == rhs.value_.typeTagPtr_;
  242. }
  243. };
  244. inline bool operator==(const ReceivedMessageArgumentIterator& lhs,
  245. const ReceivedMessageArgumentIterator& rhs )
  246. {
  247. return lhs.IsEqualTo( rhs );
  248. }
  249. inline bool operator!=(const ReceivedMessageArgumentIterator& lhs,
  250. const ReceivedMessageArgumentIterator& rhs )
  251. {
  252. return !( lhs == rhs );
  253. }
  254. class ReceivedMessageArgumentStream{
  255. friend class ReceivedMessage;
  256. ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin,
  257. const ReceivedMessageArgumentIterator& end )
  258. : p_( begin )
  259. , end_( end ) {}
  260. ReceivedMessageArgumentIterator p_, end_;
  261. public:
  262. // end of stream
  263. bool Eos() const { return p_ == end_; }
  264. ReceivedMessageArgumentStream& operator>>( bool& rhs )
  265. {
  266. if( Eos() )
  267. throw MissingArgumentException();
  268. rhs = (*p_++).AsBool();
  269. return *this;
  270. }
  271. // not sure if it would be useful to stream Nil and Infinitum
  272. // for now it's not possible
  273. // same goes for array boundaries
  274. ReceivedMessageArgumentStream& operator>>( int32& rhs )
  275. {
  276. if( Eos() )
  277. throw MissingArgumentException();
  278. rhs = (*p_++).AsInt32();
  279. return *this;
  280. }
  281. ReceivedMessageArgumentStream& operator>>( float& rhs )
  282. {
  283. if( Eos() )
  284. throw MissingArgumentException();
  285. rhs = (*p_++).AsFloat();
  286. return *this;
  287. }
  288. ReceivedMessageArgumentStream& operator>>( char& rhs )
  289. {
  290. if( Eos() )
  291. throw MissingArgumentException();
  292. rhs = (*p_++).AsChar();
  293. return *this;
  294. }
  295. ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )
  296. {
  297. if( Eos() )
  298. throw MissingArgumentException();
  299. rhs.value = (*p_++).AsRgbaColor();
  300. return *this;
  301. }
  302. ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )
  303. {
  304. if( Eos() )
  305. throw MissingArgumentException();
  306. rhs.value = (*p_++).AsMidiMessage();
  307. return *this;
  308. }
  309. ReceivedMessageArgumentStream& operator>>( int64& rhs )
  310. {
  311. if( Eos() )
  312. throw MissingArgumentException();
  313. rhs = (*p_++).AsInt64();
  314. return *this;
  315. }
  316. ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )
  317. {
  318. if( Eos() )
  319. throw MissingArgumentException();
  320. rhs.value = (*p_++).AsTimeTag();
  321. return *this;
  322. }
  323. ReceivedMessageArgumentStream& operator>>( double& rhs )
  324. {
  325. if( Eos() )
  326. throw MissingArgumentException();
  327. rhs = (*p_++).AsDouble();
  328. return *this;
  329. }
  330. ReceivedMessageArgumentStream& operator>>( Blob& rhs )
  331. {
  332. if( Eos() )
  333. throw MissingArgumentException();
  334. (*p_++).AsBlob( rhs.data, rhs.size );
  335. return *this;
  336. }
  337. ReceivedMessageArgumentStream& operator>>( const char*& rhs )
  338. {
  339. if( Eos() )
  340. throw MissingArgumentException();
  341. rhs = (*p_++).AsString();
  342. return *this;
  343. }
  344. ReceivedMessageArgumentStream& operator>>( Symbol& rhs )
  345. {
  346. if( Eos() )
  347. throw MissingArgumentException();
  348. rhs.value = (*p_++).AsSymbol();
  349. return *this;
  350. }
  351. ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
  352. {
  353. (void) rhs; // suppress unused parameter warning
  354. if( !Eos() )
  355. throw ExcessArgumentException();
  356. return *this;
  357. }
  358. };
  359. class ReceivedMessage{
  360. void Init( const char *bundle, osc_bundle_element_size_t size );
  361. public:
  362. explicit ReceivedMessage( const ReceivedPacket& packet );
  363. explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
  364. const char *AddressPattern() const { return addressPattern_; }
  365. // Support for non-standard SuperCollider integer address patterns:
  366. bool AddressPatternIsUInt32() const;
  367. uint32 AddressPatternAsUInt32() const;
  368. uint32 ArgumentCount() const { return static_cast<uint32>(typeTagsEnd_ - typeTagsBegin_); }
  369. const char *TypeTags() const { return typeTagsBegin_; }
  370. typedef ReceivedMessageArgumentIterator const_iterator;
  371. ReceivedMessageArgumentIterator ArgumentsBegin() const
  372. {
  373. return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ );
  374. }
  375. ReceivedMessageArgumentIterator ArgumentsEnd() const
  376. {
  377. return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 );
  378. }
  379. ReceivedMessageArgumentStream ArgumentStream() const
  380. {
  381. return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() );
  382. }
  383. private:
  384. const char *addressPattern_;
  385. const char *typeTagsBegin_;
  386. const char *typeTagsEnd_;
  387. const char *arguments_;
  388. };
  389. class ReceivedBundle{
  390. void Init( const char *message, osc_bundle_element_size_t size );
  391. public:
  392. explicit ReceivedBundle( const ReceivedPacket& packet );
  393. explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
  394. uint64 TimeTag() const;
  395. uint32 ElementCount() const { return elementCount_; }
  396. typedef ReceivedBundleElementIterator const_iterator;
  397. ReceivedBundleElementIterator ElementsBegin() const
  398. {
  399. return ReceivedBundleElementIterator( timeTag_ + 8 );
  400. }
  401. ReceivedBundleElementIterator ElementsEnd() const
  402. {
  403. return ReceivedBundleElementIterator( end_ );
  404. }
  405. private:
  406. const char *timeTag_;
  407. const char *end_;
  408. uint32 elementCount_;
  409. };
  410. } // namespace osc
  411. #endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */