]> git.sesse.net Git - casparcg/blob - protocol/osc/oscpack/OscReceivedElements.h
- Implemented real-time state notification using OSC-UDP.
[casparcg] / protocol / osc / oscpack / OscReceivedElements.h
1 /*
2         oscpack -- Open Sound Control packet manipulation library
3         http://www.audiomulch.com/~rossb/oscpack
4
5         Copyright (c) 2004-2005 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         Any person wishing to distribute modifications to the Software is
19         requested to send the modifications to the original developer so that
20         they can be incorporated into the canonical version.
21
22         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23         EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24         MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25         IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
26         ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27         CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28         WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 */
30 #ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
31 #define INCLUDED_OSCRECEIVEDELEMENTS_H
32
33 #include <cstddef>
34
35 #include "OscTypes.h"
36 #include "OscException.h"
37
38
39 namespace osc{
40
41
42 class MalformedMessageException : public Exception{
43 public:
44     MalformedMessageException( const char *w="malformed message" )
45         : Exception( w ) {}
46 };
47
48 class MalformedBundleException : public Exception{
49 public:
50     MalformedBundleException( const char *w="malformed bundle" )
51         : Exception( w ) {}
52 };
53
54 class WrongArgumentTypeException : public Exception{
55 public:
56     WrongArgumentTypeException( const char *w="wrong argument type" )
57         : Exception( w ) {}
58 };
59
60 class MissingArgumentException : public Exception{
61 public:
62     MissingArgumentException( const char *w="missing argument" )
63         : Exception( w ) {}
64 };
65
66 class ExcessArgumentException : public Exception{
67 public:
68     ExcessArgumentException( const char *w="too many arguments" )
69         : Exception( w ) {}
70 };
71
72
73 class ReceivedPacket{
74 public:
75     ReceivedPacket( const char *contents, int32 size )
76         : contents_( contents )
77         , size_( size ) {}
78
79     bool IsMessage() const { return !IsBundle(); }
80     bool IsBundle() const;
81
82     int32 Size() const { return size_; }
83     const char *Contents() const { return contents_; }
84
85 private:
86     const char *contents_;
87     int32 size_;
88 };
89
90
91 class ReceivedBundleElement{
92 public:
93     ReceivedBundleElement( const char *size )
94         : size_( size ) {}
95
96     friend class ReceivedBundleElementIterator;
97
98     bool IsMessage() const { return !IsBundle(); }
99     bool IsBundle() const;
100
101     int32 Size() const;
102     const char *Contents() const { return size_ + 4; }
103
104 private:
105     const char *size_;
106 };
107
108
109 class ReceivedBundleElementIterator{
110 public:
111         ReceivedBundleElementIterator( const char *sizePtr )
112         : value_( sizePtr ) {}
113
114         ReceivedBundleElementIterator operator++()
115         {
116         Advance();
117         return *this;
118         }
119
120     ReceivedBundleElementIterator operator++(int)
121     {
122         ReceivedBundleElementIterator old( *this );
123         Advance();
124         return old;
125     }
126
127         const ReceivedBundleElement& operator*() const { return value_; }
128
129     const ReceivedBundleElement* operator->() const { return &value_; }
130
131         friend bool operator==(const ReceivedBundleElementIterator& lhs,
132             const ReceivedBundleElementIterator& rhs );
133
134 private:
135         ReceivedBundleElement value_;
136
137         void Advance() { value_.size_ = value_.Contents() + value_.Size(); }
138
139     bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
140     {
141         return value_.size_ == rhs.value_.size_;
142     }
143 };
144
145 inline bool operator==(const ReceivedBundleElementIterator& lhs,
146         const ReceivedBundleElementIterator& rhs )
147 {       
148         return lhs.IsEqualTo( rhs );
149 }
150
151 inline bool operator!=(const ReceivedBundleElementIterator& lhs,
152         const ReceivedBundleElementIterator& rhs )
153 {
154         return !( lhs == rhs );
155 }
156
157
158 class ReceivedMessageArgument{
159 public:
160         ReceivedMessageArgument( const char *typeTag, const char *argument )
161                 : typeTag_( typeTag )
162                 , argument_( argument ) {}
163
164     friend class ReceivedMessageArgumentIterator;
165     
166         const char TypeTag() const { return *typeTag_; }
167
168     // the unchecked methods below don't check whether the argument actually
169     // is of the specified type. they should only be used if you've already
170     // checked the type tag or the associated IsType() method.
171
172     bool IsBool() const
173         { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }
174     bool AsBool() const;
175     bool AsBoolUnchecked() const;
176
177     bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }
178     bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }
179
180     bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }
181     int32 AsInt32() const;
182     int32 AsInt32Unchecked() const;
183
184     bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }
185     float AsFloat() const;
186     float AsFloatUnchecked() const;
187
188     bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }
189     char AsChar() const;
190     char AsCharUnchecked() const;
191
192     bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }
193     uint32 AsRgbaColor() const;
194     uint32 AsRgbaColorUnchecked() const;
195
196     bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }
197     uint32 AsMidiMessage() const;
198     uint32 AsMidiMessageUnchecked() const;
199
200     bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }
201     int64 AsInt64() const;
202     int64 AsInt64Unchecked() const;
203
204     bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }
205     uint64 AsTimeTag() const;
206     uint64 AsTimeTagUnchecked() const;
207
208     bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }
209     double AsDouble() const;
210     double AsDoubleUnchecked() const;
211
212     bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }
213     const char* AsString() const;
214     const char* AsStringUnchecked() const { return argument_; }
215
216     bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }
217     const char* AsSymbol() const;
218     const char* AsSymbolUnchecked() const { return argument_; }
219
220     bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }
221     void AsBlob( const void*& data, unsigned long& size ) const;
222     void AsBlobUnchecked( const void*& data, unsigned long& size ) const;
223     
224 private:
225         const char *typeTag_;
226         const char *argument_;
227 };
228
229
230 class ReceivedMessageArgumentIterator{
231 public:
232         ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments )
233         : value_( typeTags, arguments ) {}
234
235         ReceivedMessageArgumentIterator operator++()
236         {
237         Advance();
238         return *this;
239         }
240
241     ReceivedMessageArgumentIterator operator++(int)
242     {
243         ReceivedMessageArgumentIterator old( *this );
244         Advance();
245         return old;
246     }
247
248         const ReceivedMessageArgument& operator*() const { return value_; }
249
250     const ReceivedMessageArgument* operator->() const { return &value_; }
251
252         friend bool operator==(const ReceivedMessageArgumentIterator& lhs,
253             const ReceivedMessageArgumentIterator& rhs );
254
255 private:
256         ReceivedMessageArgument value_;
257
258         void Advance();
259
260     bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
261     {
262         return value_.typeTag_ == rhs.value_.typeTag_;
263     }
264 };
265
266 inline bool operator==(const ReceivedMessageArgumentIterator& lhs,
267         const ReceivedMessageArgumentIterator& rhs )
268 {       
269         return lhs.IsEqualTo( rhs );
270 }
271
272 inline bool operator!=(const ReceivedMessageArgumentIterator& lhs,
273         const ReceivedMessageArgumentIterator& rhs )
274 {       
275         return !( lhs == rhs );
276 }
277
278
279 class ReceivedMessageArgumentStream{
280     friend class ReceivedMessage;
281     ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin,
282             const ReceivedMessageArgumentIterator& end )
283         : p_( begin )
284         , end_( end ) {}
285
286     ReceivedMessageArgumentIterator p_, end_;
287     
288 public:
289
290     // end of stream
291     bool Eos() const { return p_ == end_; }
292
293     ReceivedMessageArgumentStream& operator>>( bool& rhs )
294     {
295         if( Eos() )
296             throw MissingArgumentException();
297
298         rhs = (*p_++).AsBool();
299         return *this;
300     }
301
302     // not sure if it would be useful to stream Nil and Infinitum
303     // for now it's not possible
304
305     ReceivedMessageArgumentStream& operator>>( int32& rhs )
306     {
307         if( Eos() )
308             throw MissingArgumentException();
309
310         rhs = (*p_++).AsInt32();
311         return *this;
312     }     
313
314     ReceivedMessageArgumentStream& operator>>( float& rhs )
315     {
316         if( Eos() )
317             throw MissingArgumentException();
318
319         rhs = (*p_++).AsFloat();
320         return *this;
321     }
322
323     ReceivedMessageArgumentStream& operator>>( char& rhs )
324     {
325         if( Eos() )
326             throw MissingArgumentException();
327
328         rhs = (*p_++).AsChar();
329         return *this;
330     }
331
332     ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )
333     {
334         if( Eos() )
335             throw MissingArgumentException();
336
337         rhs.value = (*p_++).AsRgbaColor();
338         return *this;
339     }
340
341     ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )
342     {
343         if( Eos() )
344             throw MissingArgumentException();
345
346         rhs.value = (*p_++).AsMidiMessage();
347         return *this;
348     }
349
350     ReceivedMessageArgumentStream& operator>>( int64& rhs )
351     {
352         if( Eos() )
353             throw MissingArgumentException();
354
355         rhs = (*p_++).AsInt64();
356         return *this;
357     }
358     
359     ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )
360     {
361         if( Eos() )
362             throw MissingArgumentException();
363
364         rhs.value = (*p_++).AsTimeTag();
365         return *this;
366     }
367
368     ReceivedMessageArgumentStream& operator>>( double& rhs )
369     {
370         if( Eos() )
371             throw MissingArgumentException();
372
373         rhs = (*p_++).AsDouble();
374         return *this;
375     }
376
377     ReceivedMessageArgumentStream& operator>>( Blob& rhs )
378     {
379         if( Eos() )
380             throw MissingArgumentException();
381
382         (*p_++).AsBlob( rhs.data, rhs.size );
383         return *this;
384     }
385     
386     ReceivedMessageArgumentStream& operator>>( const char*& rhs )
387     {
388         if( Eos() )
389             throw MissingArgumentException();
390
391         rhs = (*p_++).AsString();
392         return *this;
393     }
394     
395     ReceivedMessageArgumentStream& operator>>( Symbol& rhs )
396     {
397         if( Eos() )
398             throw MissingArgumentException();
399
400         rhs.value = (*p_++).AsSymbol();
401         return *this;
402     }
403
404     ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
405     {
406         if( !Eos() )
407             throw ExcessArgumentException();
408
409         return *this;
410     }
411 };
412
413
414 class ReceivedMessage{
415     void Init( const char *bundle, unsigned long size );
416 public:
417     explicit ReceivedMessage( const ReceivedPacket& packet );
418     explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
419
420         const char *AddressPattern() const { return addressPattern_; }
421
422         // Support for non-standad SuperCollider integer address patterns:
423         bool AddressPatternIsUInt32() const;
424         uint32 AddressPatternAsUInt32() const;
425
426         unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }
427
428     const char *TypeTags() const { return typeTagsBegin_; }
429
430
431     typedef ReceivedMessageArgumentIterator const_iterator;
432     
433         ReceivedMessageArgumentIterator ArgumentsBegin() const
434     {
435         return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ );
436     }
437      
438         ReceivedMessageArgumentIterator ArgumentsEnd() const
439     {
440         return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 );
441     }
442
443     ReceivedMessageArgumentStream ArgumentStream() const
444     {
445         return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() );
446     }
447
448 private:
449         const char *addressPattern_;
450         const char *typeTagsBegin_;
451         const char *typeTagsEnd_;
452     const char *arguments_;
453 };
454
455
456 class ReceivedBundle{
457     void Init( const char *message, unsigned long size );
458 public:
459     explicit ReceivedBundle( const ReceivedPacket& packet );
460     explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
461
462     uint64 TimeTag() const;
463
464     unsigned long ElementCount() const { return elementCount_; }
465
466     typedef ReceivedBundleElementIterator const_iterator;
467     
468         ReceivedBundleElementIterator ElementsBegin() const
469     {
470         return ReceivedBundleElementIterator( timeTag_ + 8 );
471     }
472      
473         ReceivedBundleElementIterator ElementsEnd() const
474     {
475         return ReceivedBundleElementIterator( end_ );
476     }
477
478 private:
479     const char *timeTag_;
480     const char *end_;
481     unsigned long elementCount_;
482 };
483
484
485 } // namespace osc
486
487
488 #endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */