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