Mercurial > hg > nodescore
comparison oscpack/osc/OscReceivedElements.h @ 76:0ae87af84e2f
added oscgroups
author | Rob Canning <rob@foo.net> |
---|---|
date | Sun, 13 Jul 2014 10:07:41 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
75:3a2845e3156e | 76:0ae87af84e2f |
---|---|
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 #ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H | |
38 #define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H | |
39 | |
40 #include <cassert> | |
41 #include <cstddef> | |
42 #include <cstring> // size_t | |
43 | |
44 #include "OscTypes.h" | |
45 #include "OscException.h" | |
46 | |
47 | |
48 namespace osc{ | |
49 | |
50 | |
51 class MalformedPacketException : public Exception{ | |
52 public: | |
53 MalformedPacketException( const char *w="malformed packet" ) | |
54 : Exception( w ) {} | |
55 }; | |
56 | |
57 class MalformedMessageException : public Exception{ | |
58 public: | |
59 MalformedMessageException( const char *w="malformed message" ) | |
60 : Exception( w ) {} | |
61 }; | |
62 | |
63 class MalformedBundleException : public Exception{ | |
64 public: | |
65 MalformedBundleException( const char *w="malformed bundle" ) | |
66 : Exception( w ) {} | |
67 }; | |
68 | |
69 class WrongArgumentTypeException : public Exception{ | |
70 public: | |
71 WrongArgumentTypeException( const char *w="wrong argument type" ) | |
72 : Exception( w ) {} | |
73 }; | |
74 | |
75 class MissingArgumentException : public Exception{ | |
76 public: | |
77 MissingArgumentException( const char *w="missing argument" ) | |
78 : Exception( w ) {} | |
79 }; | |
80 | |
81 class ExcessArgumentException : public Exception{ | |
82 public: | |
83 ExcessArgumentException( const char *w="too many arguments" ) | |
84 : Exception( w ) {} | |
85 }; | |
86 | |
87 | |
88 class ReceivedPacket{ | |
89 public: | |
90 // Although the OSC spec is not entirely clear on this, we only support | |
91 // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value | |
92 // representable by an int32). An exception will be raised if you pass a | |
93 // larger value to the ReceivedPacket() constructor. | |
94 | |
95 ReceivedPacket( const char *contents, osc_bundle_element_size_t size ) | |
96 : contents_( contents ) | |
97 , size_( ValidateSize(size) ) {} | |
98 | |
99 ReceivedPacket( const char *contents, std::size_t size ) | |
100 : contents_( contents ) | |
101 , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} | |
102 | |
103 #if !(defined(__x86_64__) || defined(_M_X64)) | |
104 ReceivedPacket( const char *contents, int size ) | |
105 : contents_( contents ) | |
106 , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} | |
107 #endif | |
108 | |
109 bool IsMessage() const { return !IsBundle(); } | |
110 bool IsBundle() const; | |
111 | |
112 osc_bundle_element_size_t Size() const { return size_; } | |
113 const char *Contents() const { return contents_; } | |
114 | |
115 private: | |
116 const char *contents_; | |
117 osc_bundle_element_size_t size_; | |
118 | |
119 static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size ) | |
120 { | |
121 // sanity check integer types declared in OscTypes.h | |
122 // you'll need to fix OscTypes.h if any of these asserts fail | |
123 assert( sizeof(osc::int32) == 4 ); | |
124 assert( sizeof(osc::uint32) == 4 ); | |
125 assert( sizeof(osc::int64) == 8 ); | |
126 assert( sizeof(osc::uint64) == 8 ); | |
127 | |
128 if( !IsValidElementSizeValue(size) ) | |
129 throw MalformedPacketException( "invalid packet size" ); | |
130 | |
131 if( size == 0 ) | |
132 throw MalformedPacketException( "zero length elements not permitted" ); | |
133 | |
134 if( !IsMultipleOf4(size) ) | |
135 throw MalformedPacketException( "element size must be multiple of four" ); | |
136 | |
137 return size; | |
138 } | |
139 }; | |
140 | |
141 | |
142 class ReceivedBundleElement{ | |
143 public: | |
144 ReceivedBundleElement( const char *sizePtr ) | |
145 : sizePtr_( sizePtr ) {} | |
146 | |
147 friend class ReceivedBundleElementIterator; | |
148 | |
149 bool IsMessage() const { return !IsBundle(); } | |
150 bool IsBundle() const; | |
151 | |
152 osc_bundle_element_size_t Size() const; | |
153 const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } | |
154 | |
155 private: | |
156 const char *sizePtr_; | |
157 }; | |
158 | |
159 | |
160 class ReceivedBundleElementIterator{ | |
161 public: | |
162 ReceivedBundleElementIterator( const char *sizePtr ) | |
163 : value_( sizePtr ) {} | |
164 | |
165 ReceivedBundleElementIterator operator++() | |
166 { | |
167 Advance(); | |
168 return *this; | |
169 } | |
170 | |
171 ReceivedBundleElementIterator operator++(int) | |
172 { | |
173 ReceivedBundleElementIterator old( *this ); | |
174 Advance(); | |
175 return old; | |
176 } | |
177 | |
178 const ReceivedBundleElement& operator*() const { return value_; } | |
179 | |
180 const ReceivedBundleElement* operator->() const { return &value_; } | |
181 | |
182 friend bool operator==(const ReceivedBundleElementIterator& lhs, | |
183 const ReceivedBundleElementIterator& rhs ); | |
184 | |
185 private: | |
186 ReceivedBundleElement value_; | |
187 | |
188 void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } | |
189 | |
190 bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const | |
191 { | |
192 return value_.sizePtr_ == rhs.value_.sizePtr_; | |
193 } | |
194 }; | |
195 | |
196 inline bool operator==(const ReceivedBundleElementIterator& lhs, | |
197 const ReceivedBundleElementIterator& rhs ) | |
198 { | |
199 return lhs.IsEqualTo( rhs ); | |
200 } | |
201 | |
202 inline bool operator!=(const ReceivedBundleElementIterator& lhs, | |
203 const ReceivedBundleElementIterator& rhs ) | |
204 { | |
205 return !( lhs == rhs ); | |
206 } | |
207 | |
208 | |
209 class ReceivedMessageArgument{ | |
210 public: | |
211 ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) | |
212 : typeTagPtr_( typeTagPtr ) | |
213 , argumentPtr_( argumentPtr ) {} | |
214 | |
215 friend class ReceivedMessageArgumentIterator; | |
216 | |
217 char TypeTag() const { return *typeTagPtr_; } | |
218 | |
219 // the unchecked methods below don't check whether the argument actually | |
220 // is of the specified type. they should only be used if you've already | |
221 // checked the type tag or the associated IsType() method. | |
222 | |
223 bool IsBool() const | |
224 { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } | |
225 bool AsBool() const; | |
226 bool AsBoolUnchecked() const; | |
227 | |
228 bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } | |
229 bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } | |
230 | |
231 bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } | |
232 int32 AsInt32() const; | |
233 int32 AsInt32Unchecked() const; | |
234 | |
235 bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } | |
236 float AsFloat() const; | |
237 float AsFloatUnchecked() const; | |
238 | |
239 bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } | |
240 char AsChar() const; | |
241 char AsCharUnchecked() const; | |
242 | |
243 bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } | |
244 uint32 AsRgbaColor() const; | |
245 uint32 AsRgbaColorUnchecked() const; | |
246 | |
247 bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } | |
248 uint32 AsMidiMessage() const; | |
249 uint32 AsMidiMessageUnchecked() const; | |
250 | |
251 bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } | |
252 int64 AsInt64() const; | |
253 int64 AsInt64Unchecked() const; | |
254 | |
255 bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } | |
256 uint64 AsTimeTag() const; | |
257 uint64 AsTimeTagUnchecked() const; | |
258 | |
259 bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } | |
260 double AsDouble() const; | |
261 double AsDoubleUnchecked() const; | |
262 | |
263 bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } | |
264 const char* AsString() const; | |
265 const char* AsStringUnchecked() const { return argumentPtr_; } | |
266 | |
267 bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } | |
268 const char* AsSymbol() const; | |
269 const char* AsSymbolUnchecked() const { return argumentPtr_; } | |
270 | |
271 bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } | |
272 void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; | |
273 void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; | |
274 | |
275 bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; } | |
276 bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; } | |
277 // Calculate the number of top-level items in the array. Nested arrays count as one item. | |
278 // Only valid at array start. Will throw an exception if IsArrayStart() == false. | |
279 std::size_t ComputeArrayItemCount() const; | |
280 | |
281 private: | |
282 const char *typeTagPtr_; | |
283 const char *argumentPtr_; | |
284 }; | |
285 | |
286 | |
287 class ReceivedMessageArgumentIterator{ | |
288 public: | |
289 ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) | |
290 : value_( typeTags, arguments ) {} | |
291 | |
292 ReceivedMessageArgumentIterator operator++() | |
293 { | |
294 Advance(); | |
295 return *this; | |
296 } | |
297 | |
298 ReceivedMessageArgumentIterator operator++(int) | |
299 { | |
300 ReceivedMessageArgumentIterator old( *this ); | |
301 Advance(); | |
302 return old; | |
303 } | |
304 | |
305 const ReceivedMessageArgument& operator*() const { return value_; } | |
306 | |
307 const ReceivedMessageArgument* operator->() const { return &value_; } | |
308 | |
309 friend bool operator==(const ReceivedMessageArgumentIterator& lhs, | |
310 const ReceivedMessageArgumentIterator& rhs ); | |
311 | |
312 private: | |
313 ReceivedMessageArgument value_; | |
314 | |
315 void Advance(); | |
316 | |
317 bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const | |
318 { | |
319 return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; | |
320 } | |
321 }; | |
322 | |
323 inline bool operator==(const ReceivedMessageArgumentIterator& lhs, | |
324 const ReceivedMessageArgumentIterator& rhs ) | |
325 { | |
326 return lhs.IsEqualTo( rhs ); | |
327 } | |
328 | |
329 inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, | |
330 const ReceivedMessageArgumentIterator& rhs ) | |
331 { | |
332 return !( lhs == rhs ); | |
333 } | |
334 | |
335 | |
336 class ReceivedMessageArgumentStream{ | |
337 friend class ReceivedMessage; | |
338 ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, | |
339 const ReceivedMessageArgumentIterator& end ) | |
340 : p_( begin ) | |
341 , end_( end ) {} | |
342 | |
343 ReceivedMessageArgumentIterator p_, end_; | |
344 | |
345 public: | |
346 | |
347 // end of stream | |
348 bool Eos() const { return p_ == end_; } | |
349 | |
350 ReceivedMessageArgumentStream& operator>>( bool& rhs ) | |
351 { | |
352 if( Eos() ) | |
353 throw MissingArgumentException(); | |
354 | |
355 rhs = (*p_++).AsBool(); | |
356 return *this; | |
357 } | |
358 | |
359 // not sure if it would be useful to stream Nil and Infinitum | |
360 // for now it's not possible | |
361 // same goes for array boundaries | |
362 | |
363 ReceivedMessageArgumentStream& operator>>( int32& rhs ) | |
364 { | |
365 if( Eos() ) | |
366 throw MissingArgumentException(); | |
367 | |
368 rhs = (*p_++).AsInt32(); | |
369 return *this; | |
370 } | |
371 | |
372 ReceivedMessageArgumentStream& operator>>( float& rhs ) | |
373 { | |
374 if( Eos() ) | |
375 throw MissingArgumentException(); | |
376 | |
377 rhs = (*p_++).AsFloat(); | |
378 return *this; | |
379 } | |
380 | |
381 ReceivedMessageArgumentStream& operator>>( char& rhs ) | |
382 { | |
383 if( Eos() ) | |
384 throw MissingArgumentException(); | |
385 | |
386 rhs = (*p_++).AsChar(); | |
387 return *this; | |
388 } | |
389 | |
390 ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) | |
391 { | |
392 if( Eos() ) | |
393 throw MissingArgumentException(); | |
394 | |
395 rhs.value = (*p_++).AsRgbaColor(); | |
396 return *this; | |
397 } | |
398 | |
399 ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) | |
400 { | |
401 if( Eos() ) | |
402 throw MissingArgumentException(); | |
403 | |
404 rhs.value = (*p_++).AsMidiMessage(); | |
405 return *this; | |
406 } | |
407 | |
408 ReceivedMessageArgumentStream& operator>>( int64& rhs ) | |
409 { | |
410 if( Eos() ) | |
411 throw MissingArgumentException(); | |
412 | |
413 rhs = (*p_++).AsInt64(); | |
414 return *this; | |
415 } | |
416 | |
417 ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) | |
418 { | |
419 if( Eos() ) | |
420 throw MissingArgumentException(); | |
421 | |
422 rhs.value = (*p_++).AsTimeTag(); | |
423 return *this; | |
424 } | |
425 | |
426 ReceivedMessageArgumentStream& operator>>( double& rhs ) | |
427 { | |
428 if( Eos() ) | |
429 throw MissingArgumentException(); | |
430 | |
431 rhs = (*p_++).AsDouble(); | |
432 return *this; | |
433 } | |
434 | |
435 ReceivedMessageArgumentStream& operator>>( Blob& rhs ) | |
436 { | |
437 if( Eos() ) | |
438 throw MissingArgumentException(); | |
439 | |
440 (*p_++).AsBlob( rhs.data, rhs.size ); | |
441 return *this; | |
442 } | |
443 | |
444 ReceivedMessageArgumentStream& operator>>( const char*& rhs ) | |
445 { | |
446 if( Eos() ) | |
447 throw MissingArgumentException(); | |
448 | |
449 rhs = (*p_++).AsString(); | |
450 return *this; | |
451 } | |
452 | |
453 ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) | |
454 { | |
455 if( Eos() ) | |
456 throw MissingArgumentException(); | |
457 | |
458 rhs.value = (*p_++).AsSymbol(); | |
459 return *this; | |
460 } | |
461 | |
462 ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) | |
463 { | |
464 (void) rhs; // suppress unused parameter warning | |
465 | |
466 if( !Eos() ) | |
467 throw ExcessArgumentException(); | |
468 | |
469 return *this; | |
470 } | |
471 }; | |
472 | |
473 | |
474 class ReceivedMessage{ | |
475 void Init( const char *bundle, osc_bundle_element_size_t size ); | |
476 public: | |
477 explicit ReceivedMessage( const ReceivedPacket& packet ); | |
478 explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); | |
479 | |
480 const char *AddressPattern() const { return addressPattern_; } | |
481 | |
482 // Support for non-standard SuperCollider integer address patterns: | |
483 bool AddressPatternIsUInt32() const; | |
484 uint32 AddressPatternAsUInt32() const; | |
485 | |
486 uint32 ArgumentCount() const { return static_cast<uint32>(typeTagsEnd_ - typeTagsBegin_); } | |
487 | |
488 const char *TypeTags() const { return typeTagsBegin_; } | |
489 | |
490 | |
491 typedef ReceivedMessageArgumentIterator const_iterator; | |
492 | |
493 ReceivedMessageArgumentIterator ArgumentsBegin() const | |
494 { | |
495 return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); | |
496 } | |
497 | |
498 ReceivedMessageArgumentIterator ArgumentsEnd() const | |
499 { | |
500 return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); | |
501 } | |
502 | |
503 ReceivedMessageArgumentStream ArgumentStream() const | |
504 { | |
505 return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); | |
506 } | |
507 | |
508 private: | |
509 const char *addressPattern_; | |
510 const char *typeTagsBegin_; | |
511 const char *typeTagsEnd_; | |
512 const char *arguments_; | |
513 }; | |
514 | |
515 | |
516 class ReceivedBundle{ | |
517 void Init( const char *message, osc_bundle_element_size_t size ); | |
518 public: | |
519 explicit ReceivedBundle( const ReceivedPacket& packet ); | |
520 explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); | |
521 | |
522 uint64 TimeTag() const; | |
523 | |
524 uint32 ElementCount() const { return elementCount_; } | |
525 | |
526 typedef ReceivedBundleElementIterator const_iterator; | |
527 | |
528 ReceivedBundleElementIterator ElementsBegin() const | |
529 { | |
530 return ReceivedBundleElementIterator( timeTag_ + 8 ); | |
531 } | |
532 | |
533 ReceivedBundleElementIterator ElementsEnd() const | |
534 { | |
535 return ReceivedBundleElementIterator( end_ ); | |
536 } | |
537 | |
538 private: | |
539 const char *timeTag_; | |
540 const char *end_; | |
541 uint32 elementCount_; | |
542 }; | |
543 | |
544 | |
545 } // namespace osc | |
546 | |
547 | |
548 #endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ |