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