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