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