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