]> git.sesse.net Git - casparcg/blob - protocol/osc/oscpack/OscReceivedElements.cpp
Merge branch '2.1.0' of https://github.com/CasparCG/Server into 2.1.0
[casparcg] / protocol / osc / oscpack / OscReceivedElements.cpp
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 #undef _CRT_SECURE_NO_WARNINGS
31 #define _CRT_SECURE_NO_WARNINGS
32
33 #include "OscReceivedElements.h"
34
35 #include <cassert>
36
37 #include "OscHostEndianness.h"
38
39
40 namespace osc{
41
42
43 // return the first 4 byte boundary after the end of a str4
44 // be careful about calling this version if you don't know whether
45 // the string is terminated correctly.
46 static inline const char* FindStr4End( const char *p )
47 {
48         if( p[0] == '\0' )    // special case for SuperCollider integer address pattern
49                 return p + 4;
50
51     p += 3;
52
53     while( *p )
54         p += 4;
55
56     return p + 1;
57 }
58
59
60 // return the first 4 byte boundary after the end of a str4
61 // returns 0 if p == end or if the string is unterminated
62 static inline const char* FindStr4End( const char *p, const char *end )
63 {
64     if( p >= end )
65         return 0;
66
67         if( p[0] == '\0' )    // special case for SuperCollider integer address pattern
68                 return p + 4;
69
70     p += 3;
71     end -= 1;
72
73     while( p < end && *p )
74         p += 4;
75
76     if( *p )
77         return 0;
78     else
79         return p + 1;
80 }
81
82
83 static inline unsigned long RoundUp4( unsigned long x )
84 {
85     unsigned long remainder = x & 0x3UL;
86     if( remainder )
87         return x + (4 - remainder);
88     else
89         return x;
90 }
91
92
93 static inline int32 ToInt32( const char *p )
94 {
95 #ifdef OSC_HOST_LITTLE_ENDIAN
96     union{
97         osc::int32 i;
98         char c[4];
99     } u;
100
101     u.c[0] = p[3];
102     u.c[1] = p[2];
103     u.c[2] = p[1];
104     u.c[3] = p[0];
105
106     return u.i;
107 #else
108         return *(int32*)p;
109 #endif
110 }
111
112
113 static inline uint32 ToUInt32( const char *p )
114 {
115 #ifdef OSC_HOST_LITTLE_ENDIAN
116     union{
117         osc::uint32 i;
118         char c[4];
119     } u;
120
121     u.c[0] = p[3];
122     u.c[1] = p[2];
123     u.c[2] = p[1];
124     u.c[3] = p[0];
125
126     return u.i;
127 #else
128         return *(uint32*)p;
129 #endif
130 }
131
132
133 int64 ToInt64( const char *p )
134 {
135 #ifdef OSC_HOST_LITTLE_ENDIAN
136     union{
137         osc::int64 i;
138         char c[8];
139     } u;
140
141     u.c[0] = p[7];
142     u.c[1] = p[6];
143     u.c[2] = p[5];
144     u.c[3] = p[4];
145     u.c[4] = p[3];
146     u.c[5] = p[2];
147     u.c[6] = p[1];
148     u.c[7] = p[0];
149
150     return u.i;
151 #else
152         return *(int64*)p;
153 #endif
154 }
155
156
157 uint64 ToUInt64( const char *p )
158 {
159 #ifdef OSC_HOST_LITTLE_ENDIAN
160     union{
161         osc::uint64 i;
162         char c[8];
163     } u;
164
165     u.c[0] = p[7];
166     u.c[1] = p[6];
167     u.c[2] = p[5];
168     u.c[3] = p[4];
169     u.c[4] = p[3];
170     u.c[5] = p[2];
171     u.c[6] = p[1];
172     u.c[7] = p[0];
173
174     return u.i;
175 #else
176         return *(uint64*)p;
177 #endif
178 }
179
180 //------------------------------------------------------------------------------
181
182 bool ReceivedPacket::IsBundle() const
183 {
184     return (Size() > 0 && Contents()[0] == '#');
185 }
186
187 //------------------------------------------------------------------------------
188
189 bool ReceivedBundleElement::IsBundle() const
190 {
191     return (Size() > 0 && Contents()[0] == '#');
192 }
193
194
195 int32 ReceivedBundleElement::Size() const
196 {
197     return ToUInt32( size_ );
198 }
199
200 //------------------------------------------------------------------------------
201
202 bool ReceivedMessageArgument::AsBool() const
203 {
204     if( !typeTag_ )
205         throw MissingArgumentException();
206         else if( *typeTag_ == TRUE_TYPE_TAG )
207                 return true;
208         else if( *typeTag_ == FALSE_TYPE_TAG )
209                 return false;
210         else
211                 throw WrongArgumentTypeException();
212 }
213
214
215 bool ReceivedMessageArgument::AsBoolUnchecked() const
216 {
217     if( !typeTag_ )
218         throw MissingArgumentException();
219         else if( *typeTag_ == TRUE_TYPE_TAG )
220                 return true;
221     else
222             return false;
223 }
224
225
226 int32 ReceivedMessageArgument::AsInt32() const
227 {
228     if( !typeTag_ )
229         throw MissingArgumentException();
230         else if( *typeTag_ == INT32_TYPE_TAG )
231                 return AsInt32Unchecked();
232         else
233                 throw WrongArgumentTypeException();
234 }
235
236
237 int32 ReceivedMessageArgument::AsInt32Unchecked() const
238 {
239 #ifdef OSC_HOST_LITTLE_ENDIAN
240     union{
241         osc::int32 i;
242         char c[4];
243     } u;
244
245     u.c[0] = argument_[3];
246     u.c[1] = argument_[2];
247     u.c[2] = argument_[1];
248     u.c[3] = argument_[0];
249
250     return u.i;
251 #else
252         return *(int32*)argument_;
253 #endif
254 }
255
256
257 float ReceivedMessageArgument::AsFloat() const
258 {
259     if( !typeTag_ )
260         throw MissingArgumentException();
261         else if( *typeTag_ == FLOAT_TYPE_TAG )
262                 return AsFloatUnchecked();
263         else
264                 throw WrongArgumentTypeException();
265 }
266
267
268 float ReceivedMessageArgument::AsFloatUnchecked() const
269 {
270 #ifdef OSC_HOST_LITTLE_ENDIAN
271     union{
272         float f;
273         char c[4];
274     } u;
275
276     u.c[0] = argument_[3];
277     u.c[1] = argument_[2];
278     u.c[2] = argument_[1];
279     u.c[3] = argument_[0];
280
281     return u.f;
282 #else
283         return *(float*)argument_;
284 #endif
285 }
286
287
288 char ReceivedMessageArgument::AsChar() const
289 {
290     if( !typeTag_ )
291         throw MissingArgumentException();
292         else if( *typeTag_ == CHAR_TYPE_TAG )
293                 return AsCharUnchecked();
294         else
295                 throw WrongArgumentTypeException();
296 }
297
298
299 char ReceivedMessageArgument::AsCharUnchecked() const
300 {
301     return (char)ToInt32( argument_ );
302 }
303
304
305 uint32 ReceivedMessageArgument::AsRgbaColor() const
306 {
307     if( !typeTag_ )
308         throw MissingArgumentException();
309         else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
310                 return AsRgbaColorUnchecked();
311         else
312                 throw WrongArgumentTypeException();
313 }
314
315
316 uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
317 {
318         return ToUInt32( argument_ );
319 }
320
321
322 uint32 ReceivedMessageArgument::AsMidiMessage() const
323 {
324     if( !typeTag_ )
325         throw MissingArgumentException();
326         else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
327                 return AsMidiMessageUnchecked();
328         else
329                 throw WrongArgumentTypeException();
330 }
331
332
333 uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
334 {
335         return ToUInt32( argument_ );
336 }
337
338
339 int64 ReceivedMessageArgument::AsInt64() const
340 {
341     if( !typeTag_ )
342         throw MissingArgumentException();
343         else if( *typeTag_ == INT64_TYPE_TAG )
344                 return AsInt64Unchecked();
345         else
346                 throw WrongArgumentTypeException();
347 }
348
349
350 int64 ReceivedMessageArgument::AsInt64Unchecked() const
351 {
352     return ToInt64( argument_ );
353 }
354
355
356 uint64 ReceivedMessageArgument::AsTimeTag() const
357 {
358     if( !typeTag_ )
359         throw MissingArgumentException();
360         else if( *typeTag_ == TIME_TAG_TYPE_TAG )
361                 return AsTimeTagUnchecked();
362         else
363                 throw WrongArgumentTypeException();
364 }
365
366
367 uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
368 {
369     return ToUInt64( argument_ );
370 }
371
372
373 double ReceivedMessageArgument::AsDouble() const
374 {
375     if( !typeTag_ )
376         throw MissingArgumentException();
377         else if( *typeTag_ == DOUBLE_TYPE_TAG )
378                 return AsDoubleUnchecked();
379         else
380                 throw WrongArgumentTypeException();
381 }
382
383
384 double ReceivedMessageArgument::AsDoubleUnchecked() const
385 {
386 #ifdef OSC_HOST_LITTLE_ENDIAN
387     union{
388         double d;
389         char c[8];
390     } u;
391
392     u.c[0] = argument_[7];
393     u.c[1] = argument_[6];
394     u.c[2] = argument_[5];
395     u.c[3] = argument_[4];
396     u.c[4] = argument_[3];
397     u.c[5] = argument_[2];
398     u.c[6] = argument_[1];
399     u.c[7] = argument_[0];
400
401     return u.d;
402 #else
403         return *(double*)argument_;
404 #endif
405 }
406
407
408 const char* ReceivedMessageArgument::AsString() const
409 {
410     if( !typeTag_ )
411         throw MissingArgumentException();
412         else if( *typeTag_ == STRING_TYPE_TAG )
413                 return argument_;
414         else
415                 throw WrongArgumentTypeException();
416 }
417
418
419 const char* ReceivedMessageArgument::AsSymbol() const
420 {
421     if( !typeTag_ )
422         throw MissingArgumentException();
423         else if( *typeTag_ == SYMBOL_TYPE_TAG )
424                 return argument_;
425         else
426                 throw WrongArgumentTypeException();
427 }
428
429
430 void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
431 {
432     if( !typeTag_ )
433         throw MissingArgumentException();
434         else if( *typeTag_ == BLOB_TYPE_TAG )
435                 AsBlobUnchecked( data, size );
436         else
437                 throw WrongArgumentTypeException();
438 }
439
440
441 void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
442 {
443     size = ToUInt32( argument_ );
444         data = (void*)(argument_+4);
445 }
446
447 //------------------------------------------------------------------------------
448
449 void ReceivedMessageArgumentIterator::Advance()
450 {
451     if( !value_.typeTag_ )
452         return;
453         
454     switch( *value_.typeTag_++ ){
455         case '\0':
456             // don't advance past end
457             --value_.typeTag_;
458             break;
459             
460         case TRUE_TYPE_TAG:
461         case FALSE_TYPE_TAG:
462         case NIL_TYPE_TAG:
463         case INFINITUM_TYPE_TAG:
464
465             // zero length
466             break;
467
468         case INT32_TYPE_TAG:
469         case FLOAT_TYPE_TAG:                                    
470         case CHAR_TYPE_TAG:
471         case RGBA_COLOR_TYPE_TAG:
472         case MIDI_MESSAGE_TYPE_TAG:
473
474             value_.argument_ += 4;
475             break;
476
477         case INT64_TYPE_TAG:
478         case TIME_TAG_TYPE_TAG:
479         case DOUBLE_TYPE_TAG:
480                                 
481             value_.argument_ += 8;
482             break;
483
484         case STRING_TYPE_TAG: 
485         case SYMBOL_TYPE_TAG:
486
487             // we use the unsafe function FindStr4End(char*) here because all of
488             // the arguments have already been validated in
489             // ReceivedMessage::Init() below.
490             
491             value_.argument_ = FindStr4End( value_.argument_ );
492             break;
493
494         case BLOB_TYPE_TAG:
495             {
496                 uint32 blobSize = ToUInt32( value_.argument_ );
497                 value_.argument_ = value_.argument_ + 4 + RoundUp4( (unsigned long)blobSize );
498             }
499             break;
500
501         default:    // unknown type tag
502             // don't advance
503             --value_.typeTag_;
504             break;
505             
506
507         //    not handled:
508         //    [ Indicates the beginning of an array. The tags following are for
509         //        data in the Array until a close brace tag is reached.
510         //    ] Indicates the end of an array.
511     }
512 }
513
514 //------------------------------------------------------------------------------
515
516 ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
517     : addressPattern_( packet.Contents() )
518 {
519     Init( packet.Contents(), packet.Size() );
520 }
521
522
523 ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
524     : addressPattern_( bundleElement.Contents() )
525 {
526     Init( bundleElement.Contents(), bundleElement.Size() );
527 }
528
529
530 bool ReceivedMessage::AddressPatternIsUInt32() const
531 {
532         return (addressPattern_[0] == '\0');
533 }
534
535
536 uint32 ReceivedMessage::AddressPatternAsUInt32() const
537 {
538     return ToUInt32( addressPattern_ );
539 }
540
541
542 void ReceivedMessage::Init( const char *message, unsigned long size )
543 {
544     if( size == 0 )
545         throw MalformedMessageException( "zero length messages not permitted" );
546
547     if( (size & 0x03L) != 0 )
548         throw MalformedMessageException( "message size must be multiple of four" );
549
550     const char *end = message + size;
551
552     typeTagsBegin_ = FindStr4End( addressPattern_, end );
553     if( typeTagsBegin_ == 0 ){
554         // address pattern was not terminated before end
555         throw MalformedMessageException( "unterminated address pattern" );
556     }
557
558     if( typeTagsBegin_ == end ){
559         // message consists of only the address pattern - no arguments or type tags.
560         typeTagsBegin_ = 0;
561         typeTagsEnd_ = 0;
562         arguments_ = 0;
563             
564     }else{
565         if( *typeTagsBegin_ != ',' )
566             throw MalformedMessageException( "type tags not present" );
567
568         if( *(typeTagsBegin_ + 1) == '\0' ){
569             // zero length type tags
570             typeTagsBegin_ = 0;
571             typeTagsEnd_ = 0;
572             arguments_ = 0;
573
574         }else{
575             // check that all arguments are present and well formed
576                 
577             arguments_ = FindStr4End( typeTagsBegin_, end );
578             if( arguments_ == 0 ){
579                 throw MalformedMessageException( "type tags were not terminated before end of message" );
580             }
581
582             ++typeTagsBegin_; // advance past initial ','
583             
584             const char *typeTag = typeTagsBegin_;
585             const char *argument = arguments_;
586                         
587             do{
588                 switch( *typeTag ){
589                     case TRUE_TYPE_TAG:
590                     case FALSE_TYPE_TAG:
591                     case NIL_TYPE_TAG:
592                     case INFINITUM_TYPE_TAG:
593
594                         // zero length
595                         break;
596
597                     case INT32_TYPE_TAG:
598                     case FLOAT_TYPE_TAG:
599                     case CHAR_TYPE_TAG:
600                     case RGBA_COLOR_TYPE_TAG:
601                     case MIDI_MESSAGE_TYPE_TAG:
602
603                         if( argument == end )
604                             throw MalformedMessageException( "arguments exceed message size" );
605                         argument += 4;
606                         if( argument > end )
607                             throw MalformedMessageException( "arguments exceed message size" );
608                         break;
609
610                     case INT64_TYPE_TAG:
611                     case TIME_TAG_TYPE_TAG:
612                     case DOUBLE_TYPE_TAG:
613
614                         if( argument == end )
615                             throw MalformedMessageException( "arguments exceed message size" );
616                         argument += 8;
617                         if( argument > end )
618                             throw MalformedMessageException( "arguments exceed message size" );
619                         break;
620
621                     case STRING_TYPE_TAG: 
622                     case SYMBOL_TYPE_TAG:
623                     
624                         if( argument == end )
625                             throw MalformedMessageException( "arguments exceed message size" );
626                         argument = FindStr4End( argument, end );
627                         if( argument == 0 )
628                             throw MalformedMessageException( "unterminated string argument" );
629                         break;
630
631                     case BLOB_TYPE_TAG:
632                         {
633                             if( argument + 4 > end )
634                                 throw MalformedMessageException( "arguments exceed message size" );
635                                 
636                             uint32 blobSize = ToUInt32( argument );
637                             argument = argument + 4 + RoundUp4( (unsigned long)blobSize );
638                             if( argument > end )
639                                 throw MalformedMessageException( "arguments exceed message size" );
640                         }
641                         break;
642                         
643                     default:
644                         throw MalformedMessageException( "unknown type tag" );
645
646                     //    not handled:
647                     //    [ Indicates the beginning of an array. The tags following are for
648                     //        data in the Array until a close brace tag is reached.
649                     //    ] Indicates the end of an array.
650                 }
651
652             }while( *++typeTag != '\0' );
653             typeTagsEnd_ = typeTag;
654         }
655     }
656 }
657
658 //------------------------------------------------------------------------------
659
660 ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
661     : elementCount_( 0 )
662 {
663     Init( packet.Contents(), packet.Size() );
664 }
665
666
667 ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
668     : elementCount_( 0 )
669 {
670     Init( bundleElement.Contents(), bundleElement.Size() );
671 }
672
673
674 void ReceivedBundle::Init( const char *bundle, unsigned long size )
675 {
676     if( size < 16 )
677         throw MalformedBundleException( "packet too short for bundle" );
678
679     if( (size & 0x03L) != 0 )
680         throw MalformedBundleException( "bundle size must be multiple of four" );
681
682     if( bundle[0] != '#'
683         || bundle[1] != 'b'
684         || bundle[2] != 'u'
685         || bundle[3] != 'n'
686         || bundle[4] != 'd'
687         || bundle[5] != 'l'
688         || bundle[6] != 'e'
689         || bundle[7] != '\0' )
690             throw MalformedBundleException( "bad bundle address pattern" );    
691
692     end_ = bundle + size;
693
694     timeTag_ = bundle + 8;
695
696     const char *p = timeTag_ + 8;
697         
698     while( p < end_ ){
699         if( p + 4 > end_ )
700             throw MalformedBundleException( "packet too short for elementSize" );
701
702         uint32 elementSize = ToUInt32( p );
703         if( (elementSize & 0x03L) != 0 )
704             throw MalformedBundleException( "bundle element size must be multiple of four" );
705
706         p += 4 + elementSize;
707         if( p > end_ )
708             throw MalformedBundleException( "packet too short for bundle element" );
709
710         ++elementCount_;
711     }
712
713     if( p != end_ )
714         throw MalformedBundleException( "bundle contents " );
715 }
716
717
718 uint64 ReceivedBundle::TimeTag() const
719 {
720     return ToUInt64( timeTag_ );
721 }
722
723
724 } // namespace osc
725