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 "OscOutboundPacketStream.h"
|
rob@76
|
38
|
rob@76
|
39 #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
|
rob@76
|
40 #include <malloc.h> // for alloca
|
rob@76
|
41 #else
|
rob@76
|
42 //#include <alloca.h> // alloca on Linux (also OSX)
|
rob@76
|
43 #include <stdlib.h> // alloca on OSX and FreeBSD (and Linux?)
|
rob@76
|
44 #endif
|
rob@76
|
45
|
rob@76
|
46 #include <cassert>
|
rob@76
|
47 #include <cstring> // memcpy, memmove, strcpy, strlen
|
rob@76
|
48 #include <cstddef> // ptrdiff_t
|
rob@76
|
49
|
rob@76
|
50 #include "OscHostEndianness.h"
|
rob@76
|
51
|
rob@76
|
52 #if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
|
rob@76
|
53 namespace std {
|
rob@76
|
54 using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'.
|
rob@76
|
55 }
|
rob@76
|
56 #endif
|
rob@76
|
57
|
rob@76
|
58 namespace osc{
|
rob@76
|
59
|
rob@76
|
60 static void FromInt32( char *p, int32 x )
|
rob@76
|
61 {
|
rob@76
|
62 #ifdef OSC_HOST_LITTLE_ENDIAN
|
rob@76
|
63 union{
|
rob@76
|
64 osc::int32 i;
|
rob@76
|
65 char c[4];
|
rob@76
|
66 } u;
|
rob@76
|
67
|
rob@76
|
68 u.i = x;
|
rob@76
|
69
|
rob@76
|
70 p[3] = u.c[0];
|
rob@76
|
71 p[2] = u.c[1];
|
rob@76
|
72 p[1] = u.c[2];
|
rob@76
|
73 p[0] = u.c[3];
|
rob@76
|
74 #else
|
rob@76
|
75 *reinterpret_cast<int32*>(p) = x;
|
rob@76
|
76 #endif
|
rob@76
|
77 }
|
rob@76
|
78
|
rob@76
|
79
|
rob@76
|
80 static void FromUInt32( char *p, uint32 x )
|
rob@76
|
81 {
|
rob@76
|
82 #ifdef OSC_HOST_LITTLE_ENDIAN
|
rob@76
|
83 union{
|
rob@76
|
84 osc::uint32 i;
|
rob@76
|
85 char c[4];
|
rob@76
|
86 } u;
|
rob@76
|
87
|
rob@76
|
88 u.i = x;
|
rob@76
|
89
|
rob@76
|
90 p[3] = u.c[0];
|
rob@76
|
91 p[2] = u.c[1];
|
rob@76
|
92 p[1] = u.c[2];
|
rob@76
|
93 p[0] = u.c[3];
|
rob@76
|
94 #else
|
rob@76
|
95 *reinterpret_cast<uint32*>(p) = x;
|
rob@76
|
96 #endif
|
rob@76
|
97 }
|
rob@76
|
98
|
rob@76
|
99
|
rob@76
|
100 static void FromInt64( char *p, int64 x )
|
rob@76
|
101 {
|
rob@76
|
102 #ifdef OSC_HOST_LITTLE_ENDIAN
|
rob@76
|
103 union{
|
rob@76
|
104 osc::int64 i;
|
rob@76
|
105 char c[8];
|
rob@76
|
106 } u;
|
rob@76
|
107
|
rob@76
|
108 u.i = x;
|
rob@76
|
109
|
rob@76
|
110 p[7] = u.c[0];
|
rob@76
|
111 p[6] = u.c[1];
|
rob@76
|
112 p[5] = u.c[2];
|
rob@76
|
113 p[4] = u.c[3];
|
rob@76
|
114 p[3] = u.c[4];
|
rob@76
|
115 p[2] = u.c[5];
|
rob@76
|
116 p[1] = u.c[6];
|
rob@76
|
117 p[0] = u.c[7];
|
rob@76
|
118 #else
|
rob@76
|
119 *reinterpret_cast<int64*>(p) = x;
|
rob@76
|
120 #endif
|
rob@76
|
121 }
|
rob@76
|
122
|
rob@76
|
123
|
rob@76
|
124 static void FromUInt64( char *p, uint64 x )
|
rob@76
|
125 {
|
rob@76
|
126 #ifdef OSC_HOST_LITTLE_ENDIAN
|
rob@76
|
127 union{
|
rob@76
|
128 osc::uint64 i;
|
rob@76
|
129 char c[8];
|
rob@76
|
130 } u;
|
rob@76
|
131
|
rob@76
|
132 u.i = x;
|
rob@76
|
133
|
rob@76
|
134 p[7] = u.c[0];
|
rob@76
|
135 p[6] = u.c[1];
|
rob@76
|
136 p[5] = u.c[2];
|
rob@76
|
137 p[4] = u.c[3];
|
rob@76
|
138 p[3] = u.c[4];
|
rob@76
|
139 p[2] = u.c[5];
|
rob@76
|
140 p[1] = u.c[6];
|
rob@76
|
141 p[0] = u.c[7];
|
rob@76
|
142 #else
|
rob@76
|
143 *reinterpret_cast<uint64*>(p) = x;
|
rob@76
|
144 #endif
|
rob@76
|
145 }
|
rob@76
|
146
|
rob@76
|
147
|
rob@76
|
148 // round up to the next highest multiple of 4. unless x is already a multiple of 4
|
rob@76
|
149 static inline std::size_t RoundUp4( std::size_t x )
|
rob@76
|
150 {
|
rob@76
|
151 return (x + 3) & ~((std::size_t)0x03);
|
rob@76
|
152 }
|
rob@76
|
153
|
rob@76
|
154
|
rob@76
|
155 OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity )
|
rob@76
|
156 : data_( buffer )
|
rob@76
|
157 , end_( data_ + capacity )
|
rob@76
|
158 , typeTagsCurrent_( end_ )
|
rob@76
|
159 , messageCursor_( data_ )
|
rob@76
|
160 , argumentCurrent_( data_ )
|
rob@76
|
161 , elementSizePtr_( 0 )
|
rob@76
|
162 , messageIsInProgress_( false )
|
rob@76
|
163 {
|
rob@76
|
164 // sanity check integer types declared in OscTypes.h
|
rob@76
|
165 // you'll need to fix OscTypes.h if any of these asserts fail
|
rob@76
|
166 assert( sizeof(osc::int32) == 4 );
|
rob@76
|
167 assert( sizeof(osc::uint32) == 4 );
|
rob@76
|
168 assert( sizeof(osc::int64) == 8 );
|
rob@76
|
169 assert( sizeof(osc::uint64) == 8 );
|
rob@76
|
170 }
|
rob@76
|
171
|
rob@76
|
172
|
rob@76
|
173 OutboundPacketStream::~OutboundPacketStream()
|
rob@76
|
174 {
|
rob@76
|
175
|
rob@76
|
176 }
|
rob@76
|
177
|
rob@76
|
178
|
rob@76
|
179 char *OutboundPacketStream::BeginElement( char *beginPtr )
|
rob@76
|
180 {
|
rob@76
|
181 if( elementSizePtr_ == 0 ){
|
rob@76
|
182
|
rob@76
|
183 elementSizePtr_ = reinterpret_cast<uint32*>(data_);
|
rob@76
|
184
|
rob@76
|
185 return beginPtr;
|
rob@76
|
186
|
rob@76
|
187 }else{
|
rob@76
|
188 // store an offset to the old element size ptr in the element size slot
|
rob@76
|
189 // we store an offset rather than the actual pointer to be 64 bit clean.
|
rob@76
|
190 *reinterpret_cast<uint32*>(beginPtr) =
|
rob@76
|
191 (uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
|
rob@76
|
192
|
rob@76
|
193 elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
|
rob@76
|
194
|
rob@76
|
195 return beginPtr + 4;
|
rob@76
|
196 }
|
rob@76
|
197 }
|
rob@76
|
198
|
rob@76
|
199
|
rob@76
|
200 void OutboundPacketStream::EndElement( char *endPtr )
|
rob@76
|
201 {
|
rob@76
|
202 assert( elementSizePtr_ != 0 );
|
rob@76
|
203
|
rob@76
|
204 if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
|
rob@76
|
205
|
rob@76
|
206 elementSizePtr_ = 0;
|
rob@76
|
207
|
rob@76
|
208 }else{
|
rob@76
|
209 // while building an element, an offset to the containing element's
|
rob@76
|
210 // size slot is stored in the elements size slot (or a ptr to data_
|
rob@76
|
211 // if there is no containing element). We retrieve that here
|
rob@76
|
212 uint32 *previousElementSizePtr =
|
rob@76
|
213 reinterpret_cast<uint32*>(data_ + *elementSizePtr_);
|
rob@76
|
214
|
rob@76
|
215 // then we store the element size in the slot. note that the element
|
rob@76
|
216 // size does not include the size slot, hence the - 4 below.
|
rob@76
|
217
|
rob@76
|
218 std::ptrdiff_t d = endPtr - reinterpret_cast<char*>(elementSizePtr_);
|
rob@76
|
219 // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb
|
rob@76
|
220
|
rob@76
|
221 uint32 elementSize = static_cast<uint32>(d - 4);
|
rob@76
|
222 FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
|
rob@76
|
223
|
rob@76
|
224 // finally, we reset the element size ptr to the containing element
|
rob@76
|
225 elementSizePtr_ = previousElementSizePtr;
|
rob@76
|
226 }
|
rob@76
|
227 }
|
rob@76
|
228
|
rob@76
|
229
|
rob@76
|
230 bool OutboundPacketStream::ElementSizeSlotRequired() const
|
rob@76
|
231 {
|
rob@76
|
232 return (elementSizePtr_ != 0);
|
rob@76
|
233 }
|
rob@76
|
234
|
rob@76
|
235
|
rob@76
|
236 void OutboundPacketStream::CheckForAvailableBundleSpace()
|
rob@76
|
237 {
|
rob@76
|
238 std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
|
rob@76
|
239
|
rob@76
|
240 if( required > Capacity() )
|
rob@76
|
241 throw OutOfBufferMemoryException();
|
rob@76
|
242 }
|
rob@76
|
243
|
rob@76
|
244
|
rob@76
|
245 void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
|
rob@76
|
246 {
|
rob@76
|
247 // plus 4 for at least four bytes of type tag
|
rob@76
|
248 std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0)
|
rob@76
|
249 + RoundUp4(std::strlen(addressPattern) + 1) + 4;
|
rob@76
|
250
|
rob@76
|
251 if( required > Capacity() )
|
rob@76
|
252 throw OutOfBufferMemoryException();
|
rob@76
|
253 }
|
rob@76
|
254
|
rob@76
|
255
|
rob@76
|
256 void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength )
|
rob@76
|
257 {
|
rob@76
|
258 // plus three for extra type tag, comma and null terminator
|
rob@76
|
259 std::size_t required = (argumentCurrent_ - data_) + argumentLength
|
rob@76
|
260 + RoundUp4( (end_ - typeTagsCurrent_) + 3 );
|
rob@76
|
261
|
rob@76
|
262 if( required > Capacity() )
|
rob@76
|
263 throw OutOfBufferMemoryException();
|
rob@76
|
264 }
|
rob@76
|
265
|
rob@76
|
266
|
rob@76
|
267 void OutboundPacketStream::Clear()
|
rob@76
|
268 {
|
rob@76
|
269 typeTagsCurrent_ = end_;
|
rob@76
|
270 messageCursor_ = data_;
|
rob@76
|
271 argumentCurrent_ = data_;
|
rob@76
|
272 elementSizePtr_ = 0;
|
rob@76
|
273 messageIsInProgress_ = false;
|
rob@76
|
274 }
|
rob@76
|
275
|
rob@76
|
276
|
rob@76
|
277 std::size_t OutboundPacketStream::Capacity() const
|
rob@76
|
278 {
|
rob@76
|
279 return end_ - data_;
|
rob@76
|
280 }
|
rob@76
|
281
|
rob@76
|
282
|
rob@76
|
283 std::size_t OutboundPacketStream::Size() const
|
rob@76
|
284 {
|
rob@76
|
285 std::size_t result = argumentCurrent_ - data_;
|
rob@76
|
286 if( IsMessageInProgress() ){
|
rob@76
|
287 // account for the length of the type tag string. the total type tag
|
rob@76
|
288 // includes an initial comma, plus at least one terminating \0
|
rob@76
|
289 result += RoundUp4( (end_ - typeTagsCurrent_) + 2 );
|
rob@76
|
290 }
|
rob@76
|
291
|
rob@76
|
292 return result;
|
rob@76
|
293 }
|
rob@76
|
294
|
rob@76
|
295
|
rob@76
|
296 const char *OutboundPacketStream::Data() const
|
rob@76
|
297 {
|
rob@76
|
298 return data_;
|
rob@76
|
299 }
|
rob@76
|
300
|
rob@76
|
301
|
rob@76
|
302 bool OutboundPacketStream::IsReady() const
|
rob@76
|
303 {
|
rob@76
|
304 return (!IsMessageInProgress() && !IsBundleInProgress());
|
rob@76
|
305 }
|
rob@76
|
306
|
rob@76
|
307
|
rob@76
|
308 bool OutboundPacketStream::IsMessageInProgress() const
|
rob@76
|
309 {
|
rob@76
|
310 return messageIsInProgress_;
|
rob@76
|
311 }
|
rob@76
|
312
|
rob@76
|
313
|
rob@76
|
314 bool OutboundPacketStream::IsBundleInProgress() const
|
rob@76
|
315 {
|
rob@76
|
316 return (elementSizePtr_ != 0);
|
rob@76
|
317 }
|
rob@76
|
318
|
rob@76
|
319
|
rob@76
|
320 OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
|
rob@76
|
321 {
|
rob@76
|
322 if( IsMessageInProgress() )
|
rob@76
|
323 throw MessageInProgressException();
|
rob@76
|
324
|
rob@76
|
325 CheckForAvailableBundleSpace();
|
rob@76
|
326
|
rob@76
|
327 messageCursor_ = BeginElement( messageCursor_ );
|
rob@76
|
328
|
rob@76
|
329 std::memcpy( messageCursor_, "#bundle\0", 8 );
|
rob@76
|
330 FromUInt64( messageCursor_ + 8, rhs.timeTag );
|
rob@76
|
331
|
rob@76
|
332 messageCursor_ += 16;
|
rob@76
|
333 argumentCurrent_ = messageCursor_;
|
rob@76
|
334
|
rob@76
|
335 return *this;
|
rob@76
|
336 }
|
rob@76
|
337
|
rob@76
|
338
|
rob@76
|
339 OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )
|
rob@76
|
340 {
|
rob@76
|
341 (void) rhs;
|
rob@76
|
342
|
rob@76
|
343 if( !IsBundleInProgress() )
|
rob@76
|
344 throw BundleNotInProgressException();
|
rob@76
|
345 if( IsMessageInProgress() )
|
rob@76
|
346 throw MessageInProgressException();
|
rob@76
|
347
|
rob@76
|
348 EndElement( messageCursor_ );
|
rob@76
|
349
|
rob@76
|
350 return *this;
|
rob@76
|
351 }
|
rob@76
|
352
|
rob@76
|
353
|
rob@76
|
354 OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
|
rob@76
|
355 {
|
rob@76
|
356 if( IsMessageInProgress() )
|
rob@76
|
357 throw MessageInProgressException();
|
rob@76
|
358
|
rob@76
|
359 CheckForAvailableMessageSpace( rhs.addressPattern );
|
rob@76
|
360
|
rob@76
|
361 messageCursor_ = BeginElement( messageCursor_ );
|
rob@76
|
362
|
rob@76
|
363 std::strcpy( messageCursor_, rhs.addressPattern );
|
rob@76
|
364 std::size_t rhsLength = std::strlen(rhs.addressPattern);
|
rob@76
|
365 messageCursor_ += rhsLength + 1;
|
rob@76
|
366
|
rob@76
|
367 // zero pad to 4-byte boundary
|
rob@76
|
368 std::size_t i = rhsLength + 1;
|
rob@76
|
369 while( i & 0x3 ){
|
rob@76
|
370 *messageCursor_++ = '\0';
|
rob@76
|
371 ++i;
|
rob@76
|
372 }
|
rob@76
|
373
|
rob@76
|
374 argumentCurrent_ = messageCursor_;
|
rob@76
|
375 typeTagsCurrent_ = end_;
|
rob@76
|
376
|
rob@76
|
377 messageIsInProgress_ = true;
|
rob@76
|
378
|
rob@76
|
379 return *this;
|
rob@76
|
380 }
|
rob@76
|
381
|
rob@76
|
382
|
rob@76
|
383 OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )
|
rob@76
|
384 {
|
rob@76
|
385 (void) rhs;
|
rob@76
|
386
|
rob@76
|
387 if( !IsMessageInProgress() )
|
rob@76
|
388 throw MessageNotInProgressException();
|
rob@76
|
389
|
rob@76
|
390 std::size_t typeTagsCount = end_ - typeTagsCurrent_;
|
rob@76
|
391
|
rob@76
|
392 if( typeTagsCount ){
|
rob@76
|
393
|
rob@76
|
394 char *tempTypeTags = (char*)alloca(typeTagsCount);
|
rob@76
|
395 std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
|
rob@76
|
396
|
rob@76
|
397 // slot size includes comma and null terminator
|
rob@76
|
398 std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
|
rob@76
|
399
|
rob@76
|
400 std::size_t argumentsSize = argumentCurrent_ - messageCursor_;
|
rob@76
|
401
|
rob@76
|
402 std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
|
rob@76
|
403
|
rob@76
|
404 messageCursor_[0] = ',';
|
rob@76
|
405 // copy type tags in reverse (really forward) order
|
rob@76
|
406 for( std::size_t i=0; i < typeTagsCount; ++i )
|
rob@76
|
407 messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
|
rob@76
|
408
|
rob@76
|
409 char *p = messageCursor_ + 1 + typeTagsCount;
|
rob@76
|
410 for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
|
rob@76
|
411 *p++ = '\0';
|
rob@76
|
412
|
rob@76
|
413 typeTagsCurrent_ = end_;
|
rob@76
|
414
|
rob@76
|
415 // advance messageCursor_ for next message
|
rob@76
|
416 messageCursor_ += typeTagSlotSize + argumentsSize;
|
rob@76
|
417
|
rob@76
|
418 }else{
|
rob@76
|
419 // send an empty type tags string
|
rob@76
|
420 std::memcpy( messageCursor_, ",\0\0\0", 4 );
|
rob@76
|
421
|
rob@76
|
422 // advance messageCursor_ for next message
|
rob@76
|
423 messageCursor_ += 4;
|
rob@76
|
424 }
|
rob@76
|
425
|
rob@76
|
426 argumentCurrent_ = messageCursor_;
|
rob@76
|
427
|
rob@76
|
428 EndElement( messageCursor_ );
|
rob@76
|
429
|
rob@76
|
430 messageIsInProgress_ = false;
|
rob@76
|
431
|
rob@76
|
432 return *this;
|
rob@76
|
433 }
|
rob@76
|
434
|
rob@76
|
435
|
rob@76
|
436 OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
|
rob@76
|
437 {
|
rob@76
|
438 CheckForAvailableArgumentSpace(0);
|
rob@76
|
439
|
rob@76
|
440 *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
|
rob@76
|
441
|
rob@76
|
442 return *this;
|
rob@76
|
443 }
|
rob@76
|
444
|
rob@76
|
445
|
rob@76
|
446 OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
|
rob@76
|
447 {
|
rob@76
|
448 (void) rhs;
|
rob@76
|
449 CheckForAvailableArgumentSpace(0);
|
rob@76
|
450
|
rob@76
|
451 *(--typeTagsCurrent_) = NIL_TYPE_TAG;
|
rob@76
|
452
|
rob@76
|
453 return *this;
|
rob@76
|
454 }
|
rob@76
|
455
|
rob@76
|
456
|
rob@76
|
457 OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
|
rob@76
|
458 {
|
rob@76
|
459 (void) rhs;
|
rob@76
|
460 CheckForAvailableArgumentSpace(0);
|
rob@76
|
461
|
rob@76
|
462 *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
|
rob@76
|
463
|
rob@76
|
464 return *this;
|
rob@76
|
465 }
|
rob@76
|
466
|
rob@76
|
467
|
rob@76
|
468 OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
|
rob@76
|
469 {
|
rob@76
|
470 CheckForAvailableArgumentSpace(4);
|
rob@76
|
471
|
rob@76
|
472 *(--typeTagsCurrent_) = INT32_TYPE_TAG;
|
rob@76
|
473 FromInt32( argumentCurrent_, rhs );
|
rob@76
|
474 argumentCurrent_ += 4;
|
rob@76
|
475
|
rob@76
|
476 return *this;
|
rob@76
|
477 }
|
rob@76
|
478
|
rob@76
|
479
|
rob@76
|
480 OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
|
rob@76
|
481 {
|
rob@76
|
482 CheckForAvailableArgumentSpace(4);
|
rob@76
|
483
|
rob@76
|
484 *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
|
rob@76
|
485
|
rob@76
|
486 #ifdef OSC_HOST_LITTLE_ENDIAN
|
rob@76
|
487 union{
|
rob@76
|
488 float f;
|
rob@76
|
489 char c[4];
|
rob@76
|
490 } u;
|
rob@76
|
491
|
rob@76
|
492 u.f = rhs;
|
rob@76
|
493
|
rob@76
|
494 argumentCurrent_[3] = u.c[0];
|
rob@76
|
495 argumentCurrent_[2] = u.c[1];
|
rob@76
|
496 argumentCurrent_[1] = u.c[2];
|
rob@76
|
497 argumentCurrent_[0] = u.c[3];
|
rob@76
|
498 #else
|
rob@76
|
499 *reinterpret_cast<float*>(argumentCurrent_) = rhs;
|
rob@76
|
500 #endif
|
rob@76
|
501
|
rob@76
|
502 argumentCurrent_ += 4;
|
rob@76
|
503
|
rob@76
|
504 return *this;
|
rob@76
|
505 }
|
rob@76
|
506
|
rob@76
|
507
|
rob@76
|
508 OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
|
rob@76
|
509 {
|
rob@76
|
510 CheckForAvailableArgumentSpace(4);
|
rob@76
|
511
|
rob@76
|
512 *(--typeTagsCurrent_) = CHAR_TYPE_TAG;
|
rob@76
|
513 FromInt32( argumentCurrent_, rhs );
|
rob@76
|
514 argumentCurrent_ += 4;
|
rob@76
|
515
|
rob@76
|
516 return *this;
|
rob@76
|
517 }
|
rob@76
|
518
|
rob@76
|
519
|
rob@76
|
520 OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
|
rob@76
|
521 {
|
rob@76
|
522 CheckForAvailableArgumentSpace(4);
|
rob@76
|
523
|
rob@76
|
524 *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
|
rob@76
|
525 FromUInt32( argumentCurrent_, rhs );
|
rob@76
|
526 argumentCurrent_ += 4;
|
rob@76
|
527
|
rob@76
|
528 return *this;
|
rob@76
|
529 }
|
rob@76
|
530
|
rob@76
|
531
|
rob@76
|
532 OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
|
rob@76
|
533 {
|
rob@76
|
534 CheckForAvailableArgumentSpace(4);
|
rob@76
|
535
|
rob@76
|
536 *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
|
rob@76
|
537 FromUInt32( argumentCurrent_, rhs );
|
rob@76
|
538 argumentCurrent_ += 4;
|
rob@76
|
539
|
rob@76
|
540 return *this;
|
rob@76
|
541 }
|
rob@76
|
542
|
rob@76
|
543
|
rob@76
|
544 OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
|
rob@76
|
545 {
|
rob@76
|
546 CheckForAvailableArgumentSpace(8);
|
rob@76
|
547
|
rob@76
|
548 *(--typeTagsCurrent_) = INT64_TYPE_TAG;
|
rob@76
|
549 FromInt64( argumentCurrent_, rhs );
|
rob@76
|
550 argumentCurrent_ += 8;
|
rob@76
|
551
|
rob@76
|
552 return *this;
|
rob@76
|
553 }
|
rob@76
|
554
|
rob@76
|
555
|
rob@76
|
556 OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
|
rob@76
|
557 {
|
rob@76
|
558 CheckForAvailableArgumentSpace(8);
|
rob@76
|
559
|
rob@76
|
560 *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
|
rob@76
|
561 FromUInt64( argumentCurrent_, rhs );
|
rob@76
|
562 argumentCurrent_ += 8;
|
rob@76
|
563
|
rob@76
|
564 return *this;
|
rob@76
|
565 }
|
rob@76
|
566
|
rob@76
|
567
|
rob@76
|
568 OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
|
rob@76
|
569 {
|
rob@76
|
570 CheckForAvailableArgumentSpace(8);
|
rob@76
|
571
|
rob@76
|
572 *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
|
rob@76
|
573
|
rob@76
|
574 #ifdef OSC_HOST_LITTLE_ENDIAN
|
rob@76
|
575 union{
|
rob@76
|
576 double f;
|
rob@76
|
577 char c[8];
|
rob@76
|
578 } u;
|
rob@76
|
579
|
rob@76
|
580 u.f = rhs;
|
rob@76
|
581
|
rob@76
|
582 argumentCurrent_[7] = u.c[0];
|
rob@76
|
583 argumentCurrent_[6] = u.c[1];
|
rob@76
|
584 argumentCurrent_[5] = u.c[2];
|
rob@76
|
585 argumentCurrent_[4] = u.c[3];
|
rob@76
|
586 argumentCurrent_[3] = u.c[4];
|
rob@76
|
587 argumentCurrent_[2] = u.c[5];
|
rob@76
|
588 argumentCurrent_[1] = u.c[6];
|
rob@76
|
589 argumentCurrent_[0] = u.c[7];
|
rob@76
|
590 #else
|
rob@76
|
591 *reinterpret_cast<double*>(argumentCurrent_) = rhs;
|
rob@76
|
592 #endif
|
rob@76
|
593
|
rob@76
|
594 argumentCurrent_ += 8;
|
rob@76
|
595
|
rob@76
|
596 return *this;
|
rob@76
|
597 }
|
rob@76
|
598
|
rob@76
|
599
|
rob@76
|
600 OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
|
rob@76
|
601 {
|
rob@76
|
602 CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
|
rob@76
|
603
|
rob@76
|
604 *(--typeTagsCurrent_) = STRING_TYPE_TAG;
|
rob@76
|
605 std::strcpy( argumentCurrent_, rhs );
|
rob@76
|
606 std::size_t rhsLength = std::strlen(rhs);
|
rob@76
|
607 argumentCurrent_ += rhsLength + 1;
|
rob@76
|
608
|
rob@76
|
609 // zero pad to 4-byte boundary
|
rob@76
|
610 std::size_t i = rhsLength + 1;
|
rob@76
|
611 while( i & 0x3 ){
|
rob@76
|
612 *argumentCurrent_++ = '\0';
|
rob@76
|
613 ++i;
|
rob@76
|
614 }
|
rob@76
|
615
|
rob@76
|
616 return *this;
|
rob@76
|
617 }
|
rob@76
|
618
|
rob@76
|
619
|
rob@76
|
620 OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
|
rob@76
|
621 {
|
rob@76
|
622 CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) );
|
rob@76
|
623
|
rob@76
|
624 *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
|
rob@76
|
625 std::strcpy( argumentCurrent_, rhs );
|
rob@76
|
626 std::size_t rhsLength = std::strlen(rhs);
|
rob@76
|
627 argumentCurrent_ += rhsLength + 1;
|
rob@76
|
628
|
rob@76
|
629 // zero pad to 4-byte boundary
|
rob@76
|
630 std::size_t i = rhsLength + 1;
|
rob@76
|
631 while( i & 0x3 ){
|
rob@76
|
632 *argumentCurrent_++ = '\0';
|
rob@76
|
633 ++i;
|
rob@76
|
634 }
|
rob@76
|
635
|
rob@76
|
636 return *this;
|
rob@76
|
637 }
|
rob@76
|
638
|
rob@76
|
639
|
rob@76
|
640 OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
|
rob@76
|
641 {
|
rob@76
|
642 CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
|
rob@76
|
643
|
rob@76
|
644 *(--typeTagsCurrent_) = BLOB_TYPE_TAG;
|
rob@76
|
645 FromUInt32( argumentCurrent_, rhs.size );
|
rob@76
|
646 argumentCurrent_ += 4;
|
rob@76
|
647
|
rob@76
|
648 std::memcpy( argumentCurrent_, rhs.data, rhs.size );
|
rob@76
|
649 argumentCurrent_ += rhs.size;
|
rob@76
|
650
|
rob@76
|
651 // zero pad to 4-byte boundary
|
rob@76
|
652 unsigned long i = rhs.size;
|
rob@76
|
653 while( i & 0x3 ){
|
rob@76
|
654 *argumentCurrent_++ = '\0';
|
rob@76
|
655 ++i;
|
rob@76
|
656 }
|
rob@76
|
657
|
rob@76
|
658 return *this;
|
rob@76
|
659 }
|
rob@76
|
660
|
rob@76
|
661 OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs )
|
rob@76
|
662 {
|
rob@76
|
663 (void) rhs;
|
rob@76
|
664 CheckForAvailableArgumentSpace(0);
|
rob@76
|
665
|
rob@76
|
666 *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG;
|
rob@76
|
667
|
rob@76
|
668 return *this;
|
rob@76
|
669 }
|
rob@76
|
670
|
rob@76
|
671 OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs )
|
rob@76
|
672 {
|
rob@76
|
673 (void) rhs;
|
rob@76
|
674 CheckForAvailableArgumentSpace(0);
|
rob@76
|
675
|
rob@76
|
676 *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG;
|
rob@76
|
677
|
rob@76
|
678 return *this;
|
rob@76
|
679 }
|
rob@76
|
680
|
rob@76
|
681 } // namespace osc
|
rob@76
|
682
|
rob@76
|
683
|