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