root/oscpack/tags/release_1_0_2/osc/OscOutboundPacketStream.cpp

Revision 53, 14.4 kB (checked in by ross, 3 years ago)

x86_64 fix from John Ffitch plus other 64 bit portability fixes

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