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 */